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 +112 -100
- data/VERSION +1 -1
- data/lib/sfplanner/planner.rb +45 -11
- data/lib/sfplanner/sas.rb +1 -1
- data/sfplanner.gemspec +1 -1
- metadata +4 -4
data/README.md
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
-
|
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
|
-
|
7
|
+
[](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
|
-
|
47
|
-
|
46
|
+
```ruby
|
47
|
+
# include sfplanner library
|
48
|
+
require 'sfplanner'
|
48
49
|
|
49
|
-
|
50
|
-
|
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
|
-
|
55
|
-
|
56
|
+
```ruby
|
57
|
+
# include sfplanner library
|
58
|
+
require 'sfplanner'
|
56
59
|
|
57
|
-
|
58
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
76
|
-
|
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
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
+
```javascript
|
113
|
+
include "types.sfp"
|
114
|
+
|
115
|
+
initial state {
|
116
|
+
a isa Service {
|
117
|
+
running is true
|
118
|
+
}
|
112
119
|
|
113
|
-
|
120
|
+
b isa Service // with "running" is false
|
114
121
|
|
115
|
-
|
116
|
-
|
117
|
-
}
|
122
|
+
pc isa Client {
|
123
|
+
refer is a
|
118
124
|
}
|
125
|
+
}
|
119
126
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
127
|
+
goal constraint {
|
128
|
+
pc.refer is b
|
129
|
+
a.running is false
|
130
|
+
}
|
124
131
|
|
125
|
-
|
126
|
-
|
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
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
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
|
-
-
|
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
|
-
-
|
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
|
-
-
|
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.
|
1
|
+
0.1.3
|
data/lib/sfplanner/planner.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
203
|
-
|
204
|
-
|
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 =
|
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
|
-
|
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
|
-
|
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
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.
|
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: &
|
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.
|
21
|
+
version: 0.3.12
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
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.
|