sfplanner 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,10 +1,12 @@
1
- SFP Planner for Ruby
2
- ====================
1
+ SFPlanner
2
+ =========
3
3
  - Author: Herry (herry13@gmail.com)
4
4
  - [Version](https://github.com/herry13/sfplanner/blob/master/VERSION)
5
5
  - License: [BSD](https://github.com/herry13/sfp-ruby/blob/master/LICENSE)
6
6
 
7
- A Ruby gem that provides a Ruby API to SFP planner that solves a planning task written in [SFP language](https://github.com/herry13/nuri/wiki/SFP-language).
7
+ [![Gem Version](https://badge.fury.io/rb/sfplanner.png)](http://badge.fury.io/rb/sfplanner)
8
+
9
+ A Ruby script and library of SFP planner, which solves a planning task written in [SFP language](https://github.com/herry13/nuri/wiki/SFP-language).
8
10
 
9
11
  Click [here](https://github.com/herry13/nuri/wiki/SFP-language), for more details about SFP language.
10
12
 
@@ -22,13 +24,11 @@ Requirements
22
24
  - Ruby (>= 1.8.7)
23
25
  - Rubygems
24
26
  - sfp (>= 0.3.0)
25
- - antlr3
26
- - json
27
27
 
28
28
  Tested on:
29
29
  - Ubuntu 12.04
30
30
  - Debian Squeeze
31
- - Scientific Linux 6.
31
+ - Scientific Linux 6
32
32
  - MacOS X 10.8
33
33
 
34
34
 
@@ -43,53 +43,59 @@ To use as Ruby library
43
43
  ----------------------
44
44
  - parse an SFP file, and then generate the plan (if found) in Hash:
45
45
 
46
- # include sfplanner library
47
- require 'sfplanner'
46
+ ```ruby
47
+ # include sfplanner library
48
+ require 'sfplanner'
48
49
 
49
- # solve and return the plan in Hash
50
- planner.solve({:file => file_path})
50
+ # solve and return the plan in Hash
51
+ planner.solve({:file => file_path})
52
+ ```
51
53
 
52
54
  - parse an SFP file, and then generate the plan in JSON:
53
55
 
54
- # include sfplanner library
55
- require 'sfplanner'
56
+ ```ruby
57
+ # include sfplanner library
58
+ require 'sfplanner'
56
59
 
57
- # solve and return the plan in JSON
58
- planner.solve({:file => file_path, :json => true})
60
+ # solve and return the plan in Hash
61
+ planner.solve({:file => file_path, :json => true})
62
+ ```
59
63
 
60
64
 
61
65
  Example of Planning Task
62
66
  ------------------------
63
67
  - Create file **types.sfp** to hold required schemas:
64
68
 
65
- schema Service {
66
- running is false
67
- procedure start {
68
- conditions {
69
- this.running is false
70
- }
71
- effects {
72
- this.running is true
73
- }
69
+ ```javascript
70
+ schema Service {
71
+ running is false
72
+ procedure start {
73
+ conditions {
74
+ this.running is false
74
75
  }
75
- procedure stop {
76
- conditions {
77
- this.running is true
78
- }
79
- effects {
80
- this.running is false
81
- }
76
+ effects {
77
+ this.running is true
82
78
  }
83
79
  }
84
- schema Client {
85
- refer isref Service
86
- procedure redirect(s isref Service) {
87
- conditions { }
88
- effects {
89
- this.refer is s
90
- }
80
+ procedure stop {
81
+ conditions {
82
+ this.running is true
83
+ }
84
+ effects {
85
+ this.running is false
91
86
  }
92
87
  }
88
+ }
89
+ schema Client {
90
+ refer isref Service
91
+ procedure redirect(s isref Service) {
92
+ conditions { }
93
+ effects {
94
+ this.refer is s
95
+ }
96
+ }
97
+ }
98
+ ```
93
99
 
94
100
  In this file, we have two schemas that model our domain. First, schema
95
101
  **Service** with an attribute **running**, procedure **start** that
@@ -103,28 +109,30 @@ Example of Planning Task
103
109
 
104
110
  - Create file **task.sfp** to hold the task:
105
111
 
106
- include "types.sfp"
107
-
108
- initial state {
109
- a isa Service {
110
- running is true
111
- }
112
+ ```javascript
113
+ include "types.sfp"
114
+
115
+ initial state {
116
+ a isa Service {
117
+ running is true
118
+ }
112
119
 
113
- b isa Service // with "running" is false
120
+ b isa Service // with "running" is false
114
121
 
115
- pc isa Client {
116
- refer is a
117
- }
122
+ pc isa Client {
123
+ refer is a
118
124
  }
125
+ }
119
126
 
120
- goal constraint {
121
- pc.refer is b
122
- a.running is false
123
- }
127
+ goal constraint {
128
+ pc.refer is b
129
+ a.running is false
130
+ }
124
131
 
125
- global constraint {
126
- pc.refer.running is true
127
- }
132
+ global constraint {
133
+ pc.refer.running is true
134
+ }
135
+ ```
128
136
 
129
137
  In this file, we specify a task where in the initial state of our domain,
130
138
  we have two services **a** and **b**, and a client **pc**. **a** is
@@ -140,46 +148,48 @@ Example of Planning Task
140
148
 
141
149
  Which will generate a workflow in JSON
142
150
 
143
- {
144
- "type": "sequential",
145
- "workflow": [
146
- {
147
- "name": "$.b.start",
148
- "parameters": {
149
- },
150
- "condition": {
151
- "$.b.running": false
152
- },
153
- "effect": {
154
- "$.b.running": true
155
- }
156
- },
157
- {
158
- "name": "$.pc.redirect",
159
- "parameters": {
160
- "$.s": "$.b"
161
- },
162
- "condition": {
163
- },
164
- "effect": {
165
- "$.pc.refer": "$.b"
166
- }
167
- },
168
- {
169
- "name": "$.a.stop",
170
- "parameters": {
171
- },
172
- "condition": {
173
- "$.a.running": true
174
- },
175
- "effect": {
176
- "$.a.running": false
177
- }
178
- }
179
- ],
180
- "version": "1",
181
- "total": 3
182
- }
151
+ ```javascript
152
+ {
153
+ "type": "sequential",
154
+ "workflow": [
155
+ {
156
+ "name": "$.b.start",
157
+ "parameters": {
158
+ },
159
+ "condition": {
160
+ "$.b.running": false
161
+ },
162
+ "effect": {
163
+ "$.b.running": true
164
+ }
165
+ },
166
+ {
167
+ "name": "$.pc.redirect",
168
+ "parameters": {
169
+ "$.s": "$.b"
170
+ },
171
+ "condition": {
172
+ },
173
+ "effect": {
174
+ "$.pc.refer": "$.b"
175
+ }
176
+ },
177
+ {
178
+ "name": "$.a.stop",
179
+ "parameters": {
180
+ },
181
+ "condition": {
182
+ "$.a.running": true
183
+ },
184
+ "effect": {
185
+ "$.a.running": false
186
+ }
187
+ }
188
+ ],
189
+ "version": "1",
190
+ "total": 3
191
+ }
192
+ ```
183
193
 
184
194
  This workflow is sequential that has 3 procedures. If you executes
185
195
  the workflow in given order, it will achieves the goal state as well
@@ -189,16 +199,18 @@ Example of Planning Task
189
199
  Planner Options
190
200
  ---------------
191
201
  You could set particular environment variable to change the planner settings:
192
- - to activate debug-mode
202
+ - To activate debug-mode
193
203
 
194
- SFPLANNER_DEBUG=1
204
+ $ export SFPLANNER_DEBUG=1
205
+
206
+ This will disable automated deletion of temporary files in temporary directory (/tmp/nuri_****/).
195
207
 
196
- - to use multiple heuristic on finding the solution, and then pick the best result
208
+ - To use multiple heuristic on finding the solution, and then pick the best result
197
209
 
198
- SFPLANNER_MIXED_CONTINUE=1
210
+ $ export SFPLANNER_MIXED_CONTINUE=1
199
211
 
200
- - to set heuristics which are used in searching
212
+ - To set heuristics which are used in searching
201
213
 
202
- SFPLANNER_MIXED_HEURISTICS=ff2,cea2
214
+ $ export SFPLANNER_MIXED_HEURISTICS=ff2,cea2
203
215
 
204
216
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.3
@@ -39,6 +39,7 @@ module Sfp
39
39
  # if false or nil then return a sequential plan
40
40
  # @param :json : if true then return the plan in JSON
41
41
  # @param :pretty_json : if true then return in pretty JSON
42
+ # @param :bsig : if true then return the solution plan as a BSig model
42
43
  #
43
44
  def solve(params={})
44
45
  if params[:string].is_a?(String)
@@ -75,6 +76,7 @@ module Sfp
75
76
  raise Exception, "Conformant task is not supported yet" if @parser.conformant
76
77
 
77
78
  bsig = (params[:parallel] ? self.to_parallel_bsig : self.to_sequential_bsig)
79
+
78
80
  return (params[:json] ? JSON.generate(bsig) :
79
81
  (params[:pretty_json] ? JSON.pretty_generate(bsig) : bsig))
80
82
  end
@@ -107,7 +109,8 @@ module Sfp
107
109
  end
108
110
 
109
111
  def solve_conformant_task(params={})
110
- # TODO
112
+ raise Exception, "Conformant task is not supported yet" if params[:bsig]
113
+
111
114
  # 1) generate all possible initial states
112
115
  # remove states that do not satisfy the global constraint
113
116
  def get_possible_partial_initial_states(init)
@@ -171,49 +174,74 @@ module Sfp
171
174
 
172
175
  return @plan if params[:sas_plan]
173
176
 
177
+ return to_bsig(params) if params[:bsig]
178
+
174
179
  plan = (params[:parallel] ? self.get_parallel_plan : self.get_sequential_plan)
175
180
  return (params[:json] ? JSON.generate(plan) :
176
181
  (params[:pretty_json] ? JSON.pretty_generate(plan) : plan))
177
182
  end
178
183
 
179
184
  def bsig_template
180
- return {'version' => 1, 'operators' => [], 'id' => Time.now.getutc.to_i, 'goal' => []}
185
+ return {'version' => 1, 'operators' => [], 'id' => Time.now.getutc.to_i, 'goal' => {}, 'goal_operator' => {}}
181
186
  end
182
187
 
183
188
  def to_sequential_bsig
184
189
  bsig = self.bsig_template
185
190
  return bsig if @plan.length <= 0
191
+
186
192
  plan = self.get_sequential_plan
187
193
  bsig['operators'] = workflow = plan['workflow']
194
+
188
195
  (workflow.length-1).downto(1) do |i|
189
196
  op = workflow[i]
190
197
  prev_op = workflow[i-1]
191
198
  prev_op['effect'].each { |k,v| op['condition'][k] = v }
192
199
  end
193
200
  bsig['goal'], _ = self.bsig_goal_operator(workflow)
201
+
194
202
  return bsig
195
203
  end
196
204
 
197
205
  def to_parallel_bsig
206
+ def set_priority_index(operator, operators)
207
+ pi = 1
208
+ operator['successors'].each { |i|
209
+ set_priority_index(operators[i], operators)
210
+ pi = operators[i]['pi'] + 1 if pi <= operators[i]['pi']
211
+ }
212
+ operator['pi'] = pi
213
+ end
214
+
198
215
  return nil if @plan.nil?
216
+
199
217
  bsig = self.bsig_template
200
218
  return bsig if @plan.length <= 0
219
+
220
+ # generate parallel plan
201
221
  plan = self.get_parallel_plan
202
- # foreach operator's predecessors, add its effects to operator's conditions
203
- bsig['operators'] = workflow = plan['workflow']
204
- workflow.each do |op|
222
+
223
+ # set BSig operators
224
+ bsig['operators'] = operators = plan['workflow']
225
+
226
+ # set priority index
227
+ operators.each { |op| set_priority_index(op, operators) if op['predecessors'].length <= 0 }
228
+
229
+ # foreach operator
230
+ # - for each operator's predecessors, add its effects to operator's conditions
231
+ # - remove unnecessary data
232
+ operators.each do |op|
205
233
  op['predecessors'].each do |pred|
206
- pred_op = workflow[pred]
234
+ pred_op = operators[pred]
207
235
  pred_op['effect'].each { |k,v| op['condition'][k] = v }
208
236
  end
209
- end
210
- # remove unnecessary information
211
- workflow.each do |op|
212
237
  op.delete('id')
213
238
  op.delete('predecessors')
214
239
  op.delete('successors')
215
240
  end
216
- bsig['goal'], bsig['goal_operator'] = self.bsig_goal_operator(workflow)
241
+
242
+ # set goals
243
+ bsig['goal'], bsig['goal_operator'] = self.bsig_goal_operator(operators)
244
+
217
245
  return bsig
218
246
  end
219
247
 
@@ -255,7 +283,13 @@ module Sfp
255
283
 
256
284
  def get_parallel_plan
257
285
  json = {'type'=>'parallel', 'workflow'=>nil, 'init'=>nil, 'version'=>'1', 'total'=>0}
258
- return json if @plan == nil
286
+ if @plan.nil?
287
+ return json
288
+ elsif @plan.length <= 0
289
+ json['workflow'] = []
290
+ return json
291
+ end
292
+
259
293
  json['workflow'], json['init'], json['total'] = @sas_task.get_partial_order_workflow(@parser)
260
294
  return json
261
295
  end
data/lib/sfplanner/sas.rb CHANGED
@@ -99,7 +99,6 @@ module Nuri
99
99
  raise Exception, 'Cannot find operator: ' + op_name if operator.nil?
100
100
  op_sfw = operator.to_sfw
101
101
  op_sfw['id'] = i
102
- op_sfw['distance'] = distance
103
102
  op_sfw['successors'] = []
104
103
  op_sfw['predecessors'] = []
105
104
  sfw << op_sfw
@@ -116,6 +115,7 @@ module Nuri
116
115
  sfw[i]['predecessors'] << j
117
116
  end
118
117
  end
118
+
119
119
  return sfw, init, sfw.length
120
120
  end
121
121
 
data/sfplanner.gemspec CHANGED
@@ -16,5 +16,5 @@ Gem::Specification.new do |s|
16
16
  s.homepage = 'https://github.com/herry13/sfplanner'
17
17
  s.rubyforge_project = 'sfplanner'
18
18
 
19
- s.add_dependency 'sfp', '~> 0.3.11'
19
+ s.add_dependency 'sfp', '~> 0.3.12'
20
20
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sfplanner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,15 +13,15 @@ date: 2013-08-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sfp
16
- requirement: &8735620 !ruby/object:Gem::Requirement
16
+ requirement: &20029340 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 0.3.11
21
+ version: 0.3.12
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *8735620
24
+ version_requirements: *20029340
25
25
  description: A Ruby gem that provides a Ruby API and a script to the SFP planner.
26
26
  This planner can automatically generate a plan that solves a planning problem written
27
27
  in SFP language.