sfplanner 0.1.5 → 0.2.1
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.
- checksums.yaml +7 -0
- data/README.md +8 -4
- data/VERSION +1 -1
- data/lib/sfplanner/planner.rb +138 -19
- data/lib/sfplanner.rb +4 -5
- data/sfplanner.gemspec +12 -13
- metadata +21 -18
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7aea85679985ccc529011c6d8145f45bae74702a
|
4
|
+
data.tar.gz: e24e321da99e4eadb5b5e37ea6fdf435df71ce3c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 400496a44f31dcde8d7bd4fc47b1df632e6b916f9e09470cc1d02b6bbd5e032e0992bc5d1a1cf09dc5f71db8110d9c23e504cdf8644c75cd0fa3265413344ec1
|
7
|
+
data.tar.gz: 4faedc38ca1f6cbe29aab72a0ad1eaf52cc13dc70f11d0dd7a567e383267306ebe288190de4951cba367943a03d0450a1663c14d8b1ce5884efb62e07bbd409d
|
data/README.md
CHANGED
@@ -10,8 +10,6 @@ A Ruby script and library of SFP planner, which solves a planning task written i
|
|
10
10
|
|
11
11
|
Click [here](https://github.com/herry13/nuri/wiki/SFP-language), for more details about SFP language.
|
12
12
|
|
13
|
-
This is a spin-out project from [Nuri](https://github.com/herry13/nuri).
|
14
|
-
|
15
13
|
|
16
14
|
Features
|
17
15
|
--------
|
@@ -28,10 +26,10 @@ To install
|
|
28
26
|
|
29
27
|
Requirements
|
30
28
|
------------
|
31
|
-
- Ruby (>= 1.
|
29
|
+
- Ruby (>= 1.9.2)
|
32
30
|
- Graphviz
|
33
31
|
- Rubygems
|
34
|
-
- sfp
|
32
|
+
- sfp
|
35
33
|
|
36
34
|
Tested on:
|
37
35
|
- Ubuntu 12.04
|
@@ -222,3 +220,9 @@ You could set particular environment variable to change the planner settings:
|
|
222
220
|
$ export SFPLANNER_MIXED_HEURISTICS=ff2,cea2
|
223
221
|
|
224
222
|
|
223
|
+
Related Projects
|
224
|
+
----------------
|
225
|
+
- [Nuri](https://github.com/herry13/nuri)
|
226
|
+
- [Sfp-ruby](https://github.com/herry13/sfp-ruby)
|
227
|
+
- [Sfpagent](https://github.com/herry13/sfpagent)
|
228
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1
|
1
|
+
0.2.1
|
data/lib/sfplanner/planner.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'fileutils'
|
2
|
+
require 'thread'
|
2
3
|
|
3
4
|
module Sfp
|
4
5
|
class Planner
|
@@ -346,7 +347,7 @@ module Sfp
|
|
346
347
|
def solve_sas(parser, p={})
|
347
348
|
return nil if parser.nil?
|
348
349
|
|
349
|
-
tmp_dir = '/tmp/nuri_' + (
|
350
|
+
tmp_dir = '/tmp/nuri_' + (Time.now.to_f * 1000000).to_i.to_s
|
350
351
|
begin
|
351
352
|
compile_time = Benchmark.measure do
|
352
353
|
parser.compile_step_1
|
@@ -361,23 +362,21 @@ module Sfp
|
|
361
362
|
|
362
363
|
benchmarks = parser.benchmarks
|
363
364
|
benchmarks['compile time'] = compile_time
|
364
|
-
File.open(tmp_dir + '/' + TranslatorBenchmarkFile, 'w') { |f| f.write(JSON.pretty_generate(benchmarks)) }
|
365
365
|
|
366
366
|
sas_file = tmp_dir + '/problem.sas'
|
367
367
|
plan_file = tmp_dir + '/out.plan'
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
368
|
+
benchmarks['generating sas'] = Benchmark.measure do
|
369
|
+
File.open(sas_file, 'w') do |f|
|
370
|
+
f.write(parser.sas)
|
371
|
+
f.flush
|
372
|
+
end
|
372
373
|
end
|
373
374
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
else
|
378
|
-
command = Sfp::Planner.getcommand(tmp_dir, sas_file, plan_file, Heuristic)
|
379
|
-
Kernel.system(command)
|
375
|
+
benchmarks['search_time'] = Benchmark.measure do
|
376
|
+
planner = ParallelHeuristic.new(tmp_dir, sas_file, plan_file)
|
377
|
+
planner.solve
|
380
378
|
end
|
379
|
+
|
381
380
|
plan = (File.exist?(plan_file) ? File.read(plan_file) : nil)
|
382
381
|
plan = plan_preprocessing(plan)
|
383
382
|
|
@@ -398,6 +397,8 @@ module Sfp
|
|
398
397
|
plan = tmp
|
399
398
|
end
|
400
399
|
|
400
|
+
File.open(tmp_dir + '/' + TranslatorBenchmarkFile, 'w') { |f| f.write(JSON.pretty_generate(benchmarks)) }
|
401
|
+
|
401
402
|
return plan, sas_task
|
402
403
|
rescue Exception => exp
|
403
404
|
raise exp
|
@@ -443,7 +444,7 @@ module Sfp
|
|
443
444
|
single(sum([g(),weight(hFF, 10)]),pref_only=true)],
|
444
445
|
boost=2000),
|
445
446
|
preferred=hFF,reopen_closed=false,cost_type=1)"'
|
446
|
-
when '
|
447
|
+
when 'fd-autotune-2' then ' \
|
447
448
|
--heuristic "hCea=cea(cost_type=2)" \
|
448
449
|
--heuristic "hCg=cg(cost_type=1)" \
|
449
450
|
--heuristic "hGoalCount=goalcount(cost_type=2)" \
|
@@ -458,7 +459,7 @@ module Sfp
|
|
458
459
|
single(sum([weight(g(), 2),weight(hGoalCount, 3)]),pref_only=true)],
|
459
460
|
boost=200),
|
460
461
|
preferred=[hCea,hGoalCount],reopen_closed=false,cost_type=1)"'
|
461
|
-
when '
|
462
|
+
when 'fd-autotune-1' then ' \
|
462
463
|
--heuristic "hFF=ff(cost_type=1)" \
|
463
464
|
--heuristic "hCea=cea(cost_type=0)" \
|
464
465
|
--heuristic "hCg=cg(cost_type=2)" \
|
@@ -514,6 +515,34 @@ module Sfp
|
|
514
515
|
command
|
515
516
|
end
|
516
517
|
|
518
|
+
def self.get_search_command(dir, plan_file, heuristic, timeout=nil)
|
519
|
+
planner = Sfp::Planner.path
|
520
|
+
params = Sfp::Planner.parameters(heuristic)
|
521
|
+
timeout = Sfp::Planner::Config.timeout if timeout.nil?
|
522
|
+
max_memory = Sfp::Planner::Config.max_memory
|
523
|
+
logfile = "search.log." + heuristic
|
524
|
+
|
525
|
+
case `uname -s`.downcase.strip
|
526
|
+
when 'linux'
|
527
|
+
"ulimit -Sv #{max_memory} && timeout #{timeout} nice #{planner}/downward #{params} \
|
528
|
+
--plan-file #{plan_file} < output 1>>#{logfile} 2>>#{logfile}"
|
529
|
+
when 'macos', 'darwin'
|
530
|
+
"ulimit -Sv #{max_memory} && nice #{planner}/downward #{params} \
|
531
|
+
--plan-file #{plan_file} < output 1>>#{logfile} 2>>#{logfile}"
|
532
|
+
else
|
533
|
+
'exit 1'
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
def self.get_preprocess_command(dir, sas_file)
|
538
|
+
case `uname -s`.downcase.strip
|
539
|
+
when 'linux', 'macos', 'darwin'
|
540
|
+
"cd #{dir} && #{Sfp::Planner.path}/preprocess < #{sas_file} 2>/dev/null 1>/dev/null"
|
541
|
+
else
|
542
|
+
"exit 1"
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
517
546
|
# Combination between two heuristic to obtain a suboptimal plan.
|
518
547
|
# 1) solve the problem with CG/CEA/FF, that will produce (usually) a non-optimal plan
|
519
548
|
# 2) remove actions which are not selected by previous step
|
@@ -525,7 +554,7 @@ module Sfp
|
|
525
554
|
@dir = dir
|
526
555
|
@sas_file = sas_file
|
527
556
|
@plan_file = plan_file
|
528
|
-
@heuristics_order = ['ff2', 'cea2', '
|
557
|
+
@heuristics_order = ['ff2', 'cea2', 'fd-autotune1', 'fd-autotune2']
|
529
558
|
@heuristics_order = ENV['SFPLANNER_MIXED_HEURISTICS'].split(',') if ENV['SFPLANNER_MIXED_HEURISTICS']
|
530
559
|
@continue = continue
|
531
560
|
@continue = true if ENV['SFPLANNER_MIXED_CONTINUE']
|
@@ -534,13 +563,13 @@ module Sfp
|
|
534
563
|
|
535
564
|
def solve2
|
536
565
|
if not File.exist?(@plan_file)
|
537
|
-
#
|
538
|
-
planner = Sfp::Planner.getcommand(@dir, @sas_file, @plan_file, '
|
566
|
+
#fd-autotune-1
|
567
|
+
planner = Sfp::Planner.getcommand(@dir, @sas_file, @plan_file, 'fd-autotune-1')
|
539
568
|
Kernel.system(planner)
|
540
569
|
end
|
541
570
|
if not File.exist?(@plan_file)
|
542
|
-
#
|
543
|
-
planner = Sfp::Planner.getcommand(@dir, @sas_file, @plan_file, '
|
571
|
+
#fd-autotune-2
|
572
|
+
planner = Sfp::Planner.getcommand(@dir, @sas_file, @plan_file, 'fd-autotune-2')
|
544
573
|
Kernel.system(planner)
|
545
574
|
end
|
546
575
|
if not File.exists?(@plan_file)
|
@@ -664,6 +693,96 @@ module Sfp
|
|
664
693
|
end
|
665
694
|
end
|
666
695
|
|
696
|
+
|
697
|
+
class ParallelHeuristic < MixedHeuristic
|
698
|
+
def initialize(dir, sas_file, plan_file, optimize=false)
|
699
|
+
@dir = dir
|
700
|
+
@sas_file = sas_file
|
701
|
+
@plan_file = plan_file
|
702
|
+
if ENV['SFPLANNER_HEURISTICS']
|
703
|
+
@heuristics = ENV['SFPLANNER_HEURISTICS'].split(',')
|
704
|
+
else
|
705
|
+
@heuristics = ['ff2', 'cea2', 'fd-autotune-1', 'fd-autotune-2']
|
706
|
+
end
|
707
|
+
if ENV['SFPLANNER_OPTIMIZE']
|
708
|
+
@optimize = case ENV['SFPLANNER_OPTIMIZE']
|
709
|
+
when '1', 'true'
|
710
|
+
true
|
711
|
+
else
|
712
|
+
false
|
713
|
+
end
|
714
|
+
else
|
715
|
+
@optimize = optimize
|
716
|
+
end
|
717
|
+
@timeout = (ENV['SFPLANNER_TIMEOUT'] ? ENV['SFPLANNER_TIMEOUT'].to_i : Sfp::Planner::Config.timeout)
|
718
|
+
end
|
719
|
+
|
720
|
+
def solve
|
721
|
+
### run preprocessing
|
722
|
+
return false if not do_preprocess
|
723
|
+
|
724
|
+
### save current working dir
|
725
|
+
home = Dir.pwd
|
726
|
+
|
727
|
+
### change to temporary working dir
|
728
|
+
Dir.chdir @dir
|
729
|
+
|
730
|
+
### run a thread for each heuristic
|
731
|
+
files = []
|
732
|
+
@heuristics.each do |heuristic|
|
733
|
+
plan_file = @plan_file + '.' + heuristic
|
734
|
+
cmd = Sfp::Planner.get_search_command(@dir, plan_file, heuristic, @timeout)
|
735
|
+
pid = Process.spawn cmd
|
736
|
+
Process.detach pid
|
737
|
+
files << plan_file
|
738
|
+
end
|
739
|
+
|
740
|
+
def processes(dir)
|
741
|
+
`ps ax | grep -v grep | grep downward | grep sfplanner | grep '#{dir}' | awk '{print $1" "}'`.to_s.strip.split("\n")
|
742
|
+
end
|
743
|
+
|
744
|
+
loop do
|
745
|
+
list = processes(@dir)
|
746
|
+
break if list.length <= 0
|
747
|
+
finished = files.select { |f| File.exist?(f) }
|
748
|
+
break if finished.length > 0
|
749
|
+
sleep 0.2
|
750
|
+
end
|
751
|
+
|
752
|
+
system "kill -9 " + processes(@dir).join(" ") + " 1>/dev/null 2>/dev/null"
|
753
|
+
|
754
|
+
### select best plan
|
755
|
+
selected = nil
|
756
|
+
length = -1
|
757
|
+
files.each do |file|
|
758
|
+
if File.exist?(file)
|
759
|
+
len = File.read(file).split("\n").length
|
760
|
+
if length < 0 or len < length
|
761
|
+
length = len
|
762
|
+
selected = file
|
763
|
+
end
|
764
|
+
end
|
765
|
+
end
|
766
|
+
|
767
|
+
if not selected.nil?
|
768
|
+
FileUtils.copy(selected, @plan_file)
|
769
|
+
optimize_plan if @optimize
|
770
|
+
|
771
|
+
Dir.chdir home
|
772
|
+
true
|
773
|
+
else
|
774
|
+
Dir.chdir home
|
775
|
+
false
|
776
|
+
end
|
777
|
+
end
|
778
|
+
|
779
|
+
def do_preprocess
|
780
|
+
(!!system(Sfp::Planner.get_preprocess_command(@dir, @sas_file)) &&
|
781
|
+
File.exist?(@dir + '/output'))
|
782
|
+
end
|
783
|
+
end
|
784
|
+
|
785
|
+
|
667
786
|
class Action
|
668
787
|
attr_accessor :operator, :predecessor
|
669
788
|
|
data/lib/sfplanner.rb
CHANGED
@@ -4,8 +4,7 @@ require 'json'
|
|
4
4
|
require 'sfp'
|
5
5
|
|
6
6
|
# internal dependencies
|
7
|
-
libdir = File.
|
8
|
-
|
9
|
-
require libdir
|
10
|
-
|
11
|
-
require libdir + '/sfplanner/planner'
|
7
|
+
libdir = File.dirname(__FILE__) + '/sfplanner'
|
8
|
+
Dir.entries(libdir).each do |item|
|
9
|
+
require "#{libdir}/#{item}" if File.extname(item) == '.rb'
|
10
|
+
end
|
data/sfplanner.gemspec
CHANGED
@@ -1,23 +1,22 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
|
-
s.name
|
3
|
-
s.version
|
4
|
-
s.date
|
5
|
-
s.summary
|
6
|
-
s.description
|
7
|
-
s.authors
|
8
|
-
s.email
|
2
|
+
s.name = 'sfplanner'
|
3
|
+
s.version = File.read(File.dirname(__FILE__) + '/VERSION').strip
|
4
|
+
s.date = File.atime(File.dirname(__FILE__) + '/VERSION').strftime("%Y-%m-%d").to_s
|
5
|
+
s.summary = 'SFPlanner'
|
6
|
+
s.description = 'A Ruby gem that provides a Ruby API and a script to the SFP planner. This planner can automatically generate a plan that solves a planning problem written in SFP language.'
|
7
|
+
s.authors = ['Herry']
|
8
|
+
s.email = 'herry13@gmail.com'
|
9
9
|
|
10
|
-
s.executables
|
11
|
-
s.
|
12
|
-
s.files = `git ls-files`.split("\n")
|
10
|
+
s.executables << 'sfplanner'
|
11
|
+
s.files = `git ls-files`.split("\n")
|
13
12
|
|
14
13
|
s.require_paths = ['lib']
|
15
14
|
s.license = 'BSD'
|
16
15
|
|
17
|
-
s.homepage
|
18
|
-
s.rubyforge_project
|
16
|
+
s.homepage = 'https://github.com/herry13/sfplanner'
|
17
|
+
s.rubyforge_project = 'sfplanner'
|
19
18
|
|
20
|
-
s.add_dependency
|
19
|
+
s.add_dependency 'sfp', '~> 0.3.19'
|
21
20
|
|
22
21
|
s.add_development_dependency 'rake'
|
23
22
|
end
|
metadata
CHANGED
@@ -1,45 +1,49 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sfplanner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Herry
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-11-20 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: sfp
|
16
|
-
requirement:
|
17
|
-
none: false
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.3.
|
19
|
+
version: 0.3.19
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
|
-
version_requirements:
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.3.19
|
25
27
|
- !ruby/object:Gem::Dependency
|
26
28
|
name: rake
|
27
|
-
requirement:
|
28
|
-
none: false
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
29
30
|
requirements:
|
30
|
-
- -
|
31
|
+
- - '>='
|
31
32
|
- !ruby/object:Gem::Version
|
32
33
|
version: '0'
|
33
34
|
type: :development
|
34
35
|
prerelease: false
|
35
|
-
version_requirements:
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
36
41
|
description: A Ruby gem that provides a Ruby API and a script to the SFP planner.
|
37
42
|
This planner can automatically generate a plan that solves a planning problem written
|
38
43
|
in SFP language.
|
39
44
|
email: herry13@gmail.com
|
40
45
|
executables:
|
41
46
|
- sfplanner
|
42
|
-
- sfw2graph
|
43
47
|
extensions: []
|
44
48
|
extra_rdoc_files: []
|
45
49
|
files:
|
@@ -74,26 +78,25 @@ files:
|
|
74
78
|
homepage: https://github.com/herry13/sfplanner
|
75
79
|
licenses:
|
76
80
|
- BSD
|
81
|
+
metadata: {}
|
77
82
|
post_install_message:
|
78
83
|
rdoc_options: []
|
79
84
|
require_paths:
|
80
85
|
- lib
|
81
86
|
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
-
none: false
|
83
87
|
requirements:
|
84
|
-
- -
|
88
|
+
- - '>='
|
85
89
|
- !ruby/object:Gem::Version
|
86
90
|
version: '0'
|
87
91
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
-
none: false
|
89
92
|
requirements:
|
90
|
-
- -
|
93
|
+
- - '>='
|
91
94
|
- !ruby/object:Gem::Version
|
92
95
|
version: '0'
|
93
96
|
requirements: []
|
94
97
|
rubyforge_project: sfplanner
|
95
|
-
rubygems_version: 1.
|
98
|
+
rubygems_version: 2.1.10
|
96
99
|
signing_key:
|
97
|
-
specification_version:
|
100
|
+
specification_version: 4
|
98
101
|
summary: SFPlanner
|
99
102
|
test_files: []
|