-
Notifications
You must be signed in to change notification settings - Fork 1
/
Hype.rb
246 lines (224 loc) · 7.62 KB
/
Hype.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#!/usr/bin/env ruby
#-----------------------------------------------
# Hype
#-----------------------------------------------
# Mau Magnaguagno
#-----------------------------------------------
# Planning description converter
#-----------------------------------------------
# Require parsers, compilers and extensions
Dir.glob("#{__dir__}/{parsers,compilers,extensions}/*.rb") {|file| require file}
module Hype
extend self
HELP = " Usage:
Hype domain problem {extensions} [output]\n
Output:
print - print parsed data(default)
rb - generate Ruby files to HyperTensioN
cpp - generate C++ file with HyperTensioN
pddl - generate PDDL files
hddl - generate HDDL files
jshop - generate JSHOP files
dot - generate DOT file
md - generate Markdown file
run - same as rb with execution
debug - same as run with execution log
nil - avoid print parsed data\n
Extensions:
patterns - add methods and tasks based on operator patterns
dummy - add brute-force methods to operators
dejavu - add invisible visit operators
wise - warn and fix description mistakes
macro - optimize operator sequences
warp - optimize unification
typredicate - optimize typed predicates
pullup - optimize structure based on preconditions
grammar - print hierarchical structure grammar
complexity - print estimated complexity of planning description"
#-----------------------------------------------
# Predicates to string
#-----------------------------------------------
def predicates_to_s(predicates, indent)
predicates.map {|i| "#{indent}(#{i.join(' ')})"}.join
end
#-----------------------------------------------
# Subtasks to string
#-----------------------------------------------
def subtasks_to_s(tasks, indent, ordered = true)
if tasks.empty?
"#{indent}empty"
else
operators = @parser.operators
output = "#{indent}#{'un' unless ordered}ordered"
tasks.each {|t| output << indent << (operators.assoc(t[0]) ? 'operator' : 'method ') << " (#{t.join(' ')})"}
output
end
end
#-----------------------------------------------
# Operators to string
#-----------------------------------------------
def operators_to_s
output = ''
indent = "\n "
@parser.operators.each {|op|
output << "\n #{op[0]}(#{op[1].join(' ')})"
output << "\n Precond positive:#{predicates_to_s(op[2], indent)}" unless op[2].empty?
output << "\n Precond negative:#{predicates_to_s(op[3], indent)}" unless op[3].empty?
output << "\n Effect positive:#{predicates_to_s(op[4], indent)}" unless op[4].empty?
output << "\n Effect negative:#{predicates_to_s(op[5], indent)}" unless op[5].empty?
output << "\n"
}
output
end
#-----------------------------------------------
# Methods to string
#-----------------------------------------------
def methods_to_s
output = ''
indent = "\n "
@parser.methods.each {|name,param,*decompositions|
output << "\n #{name}(#{param.join(' ')})"
decompositions.each {|dec|
output << "\n Label: #{dec[0]}"
output << "\n Free variables:\n #{dec[1].join(indent)}" unless dec[1].empty?
output << "\n Precond positive:#{predicates_to_s(dec[2], indent)}" unless dec[2].empty?
output << "\n Precond negative:#{predicates_to_s(dec[3], indent)}" unless dec[3].empty?
output << "\n Subtasks:#{subtasks_to_s(dec[4], indent)}"
}
output << "\n"
}
output
end
#-----------------------------------------------
# To string
#-----------------------------------------------
def to_s
"Domain #{@parser.domain_name}
Operators:#{operators_to_s}\n
Methods:#{methods_to_s}\n
Problem #{@parser.problem_name}
State:#{predicates_to_s(@parser.state.flat_map {|k,v| [k].product(v)}, "\n ")}\n
Goal:
Tasks:#{subtasks_to_s(@parser.tasks.drop(1), "\n ", @parser.tasks[0])}
Positive:#{@parser.goal_pos.empty? ? "\n empty" : predicates_to_s(@parser.goal_pos, "\n ")}
Negative:#{@parser.goal_not.empty? ? "\n empty" : predicates_to_s(@parser.goal_not, "\n ")}"
end
#-----------------------------------------------
# Parse
#-----------------------------------------------
def parse(domain, problem)
raise 'Incompatible extensions between domain and problem' if File.extname(domain) != File.extname(problem)
@parser = case File.extname(domain)
when '.jshop' then JSHOP_Parser
when '.hddl' then HDDL_Parser
when '.pddl' then PDDL_Parser
else raise "Unknown file extension #{File.extname(domain)}"
end
@parser.parse_domain(domain)
@parser.parse_problem(problem)
end
#-----------------------------------------------
# Extend
#-----------------------------------------------
def extend(extension)
case extension
when 'patterns' then Patterns
when 'dummy' then Dummy
when 'dejavu' then Dejavu
when 'wise' then Wise
when 'macro' then Macro
when 'warp' then Warp
when 'typredicate' then Typredicate
when 'pullup' then Pullup
when 'grammar' then Grammar
when 'complexity' then Complexity
else raise "Unknown extension #{extension}"
end.apply(
@parser.operators,
@parser.methods,
@parser.predicates,
@parser.state,
@parser.tasks,
@parser.goal_pos,
@parser.goal_not
)
end
#-----------------------------------------------
# Compile
#-----------------------------------------------
def compile(domain, problem, type)
compiler = case type
when 'rb' then Hyper_Compiler
when 'cpp' then Cyber_Compiler
when 'jshop' then JSHOP_Compiler
when 'hddl' then HDDL_Compiler
when 'pddl' then PDDL_Compiler
when 'dot' then Dot_Compiler
when 'md' then Markdown_Compiler
else raise "Unknown type #{type}"
end
args = [
@parser.domain_name,
@parser.problem_name,
@parser.operators,
@parser.methods,
@parser.predicates,
@parser.state,
@parser.tasks,
@parser.goal_pos,
@parser.goal_not
]
data = compiler.compile_domain(*args)
File.write("#{domain}.#{type}", data) if data
data = compiler.compile_problem(*args << File.basename(domain))
File.write("#{problem}.#{type}", data) if data
end
#-----------------------------------------------
# Execute
#-----------------------------------------------
def execute
args = [
@parser.domain_name,
@parser.problem_name,
@parser.operators,
@parser.methods,
@parser.predicates,
@parser.state,
@parser.tasks,
@parser.goal_pos,
@parser.goal_not
]
eval(Hyper_Compiler.compile_domain(*args))
eval(Hyper_Compiler.compile_problem(*args))
end
end
#-----------------------------------------------
# Main
#-----------------------------------------------
if $0 == __FILE__
begin
if ARGV.size < 2 or ARGV[0] == '-h'
puts Hype::HELP
elsif not File.exist?(domain = ARGV.shift)
abort("Domain not found: #{domain}")
elsif not File.exist?(problem = ARGV.shift)
abort("Problem not found: #{problem}")
else
type = ARGV.pop
t = Time.now.to_f
Hype.parse(domain, problem)
ARGV.each {|e| Hype.extend(e)}
if not type or type == 'print'
puts Hype.to_s
elsif type == 'run' or (ARGV[0] = type) == 'debug'
Hype.execute
elsif type != 'nil'
Hype.compile(domain, problem, type)
end
puts "Total time: #{Time.now.to_f - t}s"
end
rescue
puts $!, $@
exit(2)
end
end