longjing 0.1.0

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.
@@ -0,0 +1,138 @@
1
+ require 'set'
2
+ require 'longjing/search/base'
3
+ require 'longjing/ff/preprocess'
4
+ require 'longjing/ff/connectivity_graph'
5
+ require 'longjing/ff/ordering'
6
+ require 'longjing/ff/relaxed_graph_plan'
7
+
8
+ module Longjing
9
+ module PDDL
10
+ class Literal
11
+ attr_accessor :ff_neg_goal
12
+ end
13
+ end
14
+
15
+ module Search
16
+ def self.ff
17
+ FF
18
+ end
19
+
20
+ class FF < Base
21
+ include Longjing::FF
22
+
23
+ def init(problem)
24
+ log { 'Preprocess' }
25
+ @problem = Preprocess.new.execute(problem)
26
+ log { 'Propositionalized problem:' }
27
+ log { "# actions: #{@problem.all_actions.size}" }
28
+ log { 'Initialize graphs' }
29
+ cg = ConnectivityGraph.new(@problem)
30
+ @h = RelaxedGraphPlan.new(cg)
31
+ @ordering = Ordering.new(cg)
32
+ end
33
+
34
+ def search(problem)
35
+ log { 'FF search starts' }
36
+ init(problem)
37
+ log { "Build goal agenda" }
38
+ agenda = @ordering.goal_agenda(@problem)
39
+ log { "Goal agenda:" }
40
+ log(:facts, agenda)
41
+ goal = []
42
+ state = @problem.initial
43
+ agenda.each do |g|
44
+ goal << g
45
+ unless state = hill_climbing(state, goal)
46
+ return greedy_search
47
+ end
48
+ end
49
+ solution(state)
50
+ end
51
+
52
+ def hill_climbing(state, goal_list)
53
+ log { "Hill climbing, goal:" }
54
+ log(:facts, goal_list)
55
+ reset_best_heuristic
56
+
57
+ best = if relaxed_solution = @h.extract(goal_list, state)
58
+ distance(relaxed_solution)
59
+ end
60
+ logger.debug { "Initial cost: #{best}" }
61
+ return unless best
62
+ state.cost = best
63
+ helpful_actions = relaxed_solution[1]
64
+ goal_set = goal_list.to_set
65
+ until best == 0 do
66
+ state, best, helpful_actions = breadth_first([state],
67
+ best,
68
+ helpful_actions,
69
+ goal_set,
70
+ goal_list)
71
+ return unless state
72
+ logger.debug { "----\nState: #{state}\nCost: #{best}\nPath: #{state.path.map(&:signature).join("\n")}" }
73
+ end
74
+ state
75
+ end
76
+
77
+ def breadth_first(frontier, best, helpful_actions,
78
+ goal_set, goal_list)
79
+ known = Hash[frontier.map{|f| [f, true]}]
80
+ until frontier.empty? do
81
+ state = frontier.shift
82
+ statistics.expanded += 1
83
+
84
+ log(:exploring, state)
85
+ log_progress(state)
86
+
87
+ actions = helpful_actions || @problem.actions(state)
88
+ helpful_actions = nil
89
+ actions.each do |action|
90
+ new_state = @problem.result(action, state)
91
+ statistics.generated += 1
92
+ log(:action, action, new_state)
93
+ if known.include?(new_state)
94
+ logger.debug { "Known state" }
95
+ next
96
+ end
97
+
98
+ added_goals = Hash[action.effect.to_a.select{|lit| goal_set.include?(lit)}.map{|k| [k, true]}]
99
+ if solution = @h.extract(goal_list, new_state, added_goals)
100
+ dist = distance(solution)
101
+ new_state.cost = dist
102
+ log(:heuristic, new_state, solution, dist, best)
103
+ if dist < best
104
+ return [new_state, dist, solution[1]]
105
+ else
106
+ known[new_state] = true
107
+ frontier << new_state
108
+ end
109
+ else
110
+ # ignore infinite heuristic state
111
+ logger.debug { "No relaxed solution" }
112
+ end
113
+ statistics.evaluated += 1
114
+ end
115
+ end
116
+ return nil
117
+ end
118
+
119
+ def greedy_search
120
+ reset_best_heuristic
121
+ goal_list = @problem.goal.to_a
122
+ greedy = Greedy.new
123
+ heuristic = lambda {|state| distance(@h.extract(goal_list, state))}
124
+ greedy.search(@problem, heuristic)
125
+ end
126
+
127
+
128
+ def distance(relaxed)
129
+ return Float::INFINITY if relaxed.nil?
130
+ if relaxed[0].empty?
131
+ 0
132
+ else
133
+ relaxed[0].map(&:size).reduce(:+)
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,28 @@
1
+ require 'set'
2
+ require 'longjing/search/base'
3
+ require 'longjing/ff/preprocess'
4
+ require 'longjing/ff/connectivity_graph'
5
+ require 'longjing/ff/ordering'
6
+ require 'longjing/ff/relaxed_graph_plan'
7
+
8
+ module Longjing
9
+ module PDDL
10
+ class Literal
11
+ attr_accessor :ff_neg_goal
12
+ end
13
+ end
14
+
15
+ module Search
16
+ def self.ff_greedy
17
+ FFGreedy
18
+ end
19
+
20
+ class FFGreedy < FF
21
+ def search(problem)
22
+ log { 'FF greedy search starts' }
23
+ init(problem)
24
+ greedy_search
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,43 @@
1
+ require 'set'
2
+ require 'longjing/search/base'
3
+
4
+ module Longjing
5
+ module Search
6
+ class Greedy < Base
7
+ def search(problem, heuristic)
8
+ log { "Greedy search" }
9
+ initial = problem.initial
10
+ if problem.goal?(initial)
11
+ return solution(initial)
12
+ end
13
+ initial.cost = heuristic.call(initial)
14
+ frontier = SortedSet.new([initial])
15
+ known = {initial => true}
16
+ until frontier.empty? do
17
+ state = frontier.first
18
+ statistics.expanded += 1
19
+ frontier.delete(state)
20
+ log(:exploring, state)
21
+ log_progress(state)
22
+ problem.actions(state).each do |action|
23
+ new_state = problem.result(action, state)
24
+ statistics.generated += 1
25
+ log(:action, action, new_state)
26
+ if known.include?(new_state)
27
+ logger.debug { "Known state" }
28
+ next
29
+ end
30
+ if problem.goal?(new_state)
31
+ return solution(new_state)
32
+ end
33
+ new_state.cost = heuristic.call(new_state)
34
+ statistics.evaluated += 1
35
+ known[new_state] = true
36
+ frontier << new_state
37
+ end
38
+ end
39
+ no_solution
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,10 @@
1
+ module Longjing
2
+ module Search
3
+ class Statistics
4
+ attr_accessor :generated, :expanded, :evaluated
5
+ def initialize
6
+ @generated, @expanded, @evaluated = 0, 0, 0
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,27 @@
1
+ module Longjing
2
+ class State
3
+ attr_reader :raw, :path, :hash
4
+ attr_accessor :cost
5
+
6
+ def initialize(raw, path=[])
7
+ @raw = raw
8
+ @path = path
9
+ @hash = @raw.hash
10
+ @cost = 0
11
+ end
12
+
13
+ def ==(state)
14
+ return true if state.object_id == self.object_id
15
+ @raw == state.raw
16
+ end
17
+ alias :eql? :==
18
+
19
+ def to_s
20
+ "{#{@raw.to_a.join(" ")}}"
21
+ end
22
+
23
+ def <=>(s)
24
+ @cost <=> s.cost
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module Longjing
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'longjing/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "longjing"
8
+ spec.version = Longjing::VERSION
9
+ spec.authors = ["Xiao Li"]
10
+ spec.email = ["swing1979@gmail.com"]
11
+
12
+ spec.summary = %q{Longjing is classical planner.}
13
+ spec.description = %q{Longjing is classical planner for learning classical planning algorithms.}
14
+ spec.homepage = "https://github.com/xli/longjing"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.10"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "ruby-prof"
24
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: longjing
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Xiao Li
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-08-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ruby-prof
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Longjing is classical planner for learning classical planning algorithms.
56
+ email:
57
+ - swing1979@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".ruby-version"
64
+ - ".travis.yml"
65
+ - Gemfile
66
+ - README.md
67
+ - Rakefile
68
+ - TODO
69
+ - benchmark.log
70
+ - bin/console
71
+ - bin/longjing
72
+ - bin/setup
73
+ - lib/longjing.rb
74
+ - lib/longjing/ff/action.rb
75
+ - lib/longjing/ff/connectivity_graph.rb
76
+ - lib/longjing/ff/ordering.rb
77
+ - lib/longjing/ff/preprocess.rb
78
+ - lib/longjing/ff/relaxed_graph_plan.rb
79
+ - lib/longjing/logging.rb
80
+ - lib/longjing/parameters.rb
81
+ - lib/longjing/pddl.rb
82
+ - lib/longjing/pddl/action.rb
83
+ - lib/longjing/pddl/literal.rb
84
+ - lib/longjing/pddl/obj.rb
85
+ - lib/longjing/pddl/parser.tab.rb
86
+ - lib/longjing/pddl/parser.y
87
+ - lib/longjing/pddl/predicate.rb
88
+ - lib/longjing/pddl/type.rb
89
+ - lib/longjing/pddl/var.rb
90
+ - lib/longjing/problem.rb
91
+ - lib/longjing/search.rb
92
+ - lib/longjing/search/base.rb
93
+ - lib/longjing/search/ff.rb
94
+ - lib/longjing/search/ff_greedy.rb
95
+ - lib/longjing/search/greedy.rb
96
+ - lib/longjing/search/statistics.rb
97
+ - lib/longjing/state.rb
98
+ - lib/longjing/version.rb
99
+ - longjing.gemspec
100
+ homepage: https://github.com/xli/longjing
101
+ licenses: []
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubyforge_project:
119
+ rubygems_version: 2.4.5
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: Longjing is classical planner.
123
+ test_files: []