-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHypertension_U.rb
154 lines (140 loc) · 4.78 KB
/
Hypertension_U.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
#-----------------------------------------------
# HyperTensioN U
#-----------------------------------------------
# Mau Magnaguagno
#-----------------------------------------------
# HTN planner
#-----------------------------------------------
require_relative '../HyperTensioN/Hypertension'
module Hypertension_U
include Hypertension
extend self
attr_accessor :min_prob, :max_plans, :plans
# Probabilistic plan = [PROBABILITY = 1, VALUATION = 0, op0, ..., opN]
PROBABILITY = 0
VALUATION = 1
#-----------------------------------------------
# Planning
#-----------------------------------------------
def planning(tasks, level = 0, plan = [1,0])
# Limit test
if @plans.size != @max_plans
if tasks.empty?
if plan[PROBABILITY] >= @min_prob
puts "#{' ' * level}plan found" if @debug
@plans << plan
end
else
case decomposition = @domain[(current_task = tasks.shift)[0]]
# Operator with single outcome
when Numeric
execute(current_task, decomposition, tasks, level, plan)
# Operator with multiple outcomes
when Hash
task_name = current_task[0]
begin
decomposition.each {|task_prob,probability|
current_task[0] = task_prob
execute(current_task, probability, tasks, level, plan)
return if @plans.size == @max_plans
}
rescue SystemStackError then @nostack = true
end
current_task[0] = task_name
# Method
when Array
# Keep decomposing the hierarchy
task_name = current_task.shift
plans_found = @plans.size
level += 1
begin
decomposition.each {|method|
puts "#{' ' * level.pred}#{method}(#{current_task.join(' ')})" if @debug
# Every unification is tested
__send__(method, *current_task) {|subtasks|
planning(subtasks.concat(tasks), level, plan)
return if @plans.size == @max_plans
}
# Consider success when at least one new plan was found
break if @plans.size != plans_found
}
rescue SystemStackError then @nostack = true
end
current_task.unshift(task_name)
# Error
else raise "Domain defines no decomposition for #{current_task[0]}"
end
end
end
end
#-----------------------------------------------
# State valuation
#-----------------------------------------------
def state_valuation(old_state)
0
end
#-----------------------------------------------
# Execute
#-----------------------------------------------
def execute(current_task, probability, tasks, level, plan)
old_state = @state
puts "#{' ' * level}#{current_task[0]}(#{current_task.drop(1).join(' ')})" if @debug
begin
# Minimum probability and applied
if (new_prob = plan[PROBABILITY] * probability) >= @min_prob and __send__(*current_task)
new_plan = plan.dup << current_task.map(&:dup)
new_plan[PROBABILITY] = new_prob
new_plan[VALUATION] += state_valuation(old_state) * probability
# Keep decomposing the hierarchy
planning(tasks, level, new_plan)
end
rescue SystemStackError then @nostack = true
end
@state = old_state
end
#-----------------------------------------------
# Problem
#-----------------------------------------------
def problem(state, tasks, debug = false, max_plans = -1, min_prob = 0, ordered = true)
@nostack = false
@debug = debug
@state = state
@min_prob = min_prob
@max_plans = max_plans
@plans = []
puts 'Tasks'.center(50,'-')
print_data(tasks)
puts 'Planning'.center(50,'-')
t = Time.now.to_f
ordered ? planning(tasks) : task_permutations(state, tasks)
puts "Time: #{Time.now.to_f - t}s", "Plans found: #{@plans.size}"
if @plans.each_with_index {|(probability,valuation,*plan),i|
puts "Plan #{i.succ}".center(50,'-'),
"Probability: #{probability}",
"Valuation: #{valuation}"
if plan.delete_if {|op,| op.start_with?('invisible_')}.empty? then puts 'Empty plan'
else print_data(plan)
end
}.empty?
abort(@nostack ? 'Planning failed, try with more stack' : 'Planning failed')
end
@plans
rescue Interrupt
puts 'Interrupted'
exit(130)
rescue
puts $!, $@
exit(2)
end
#-----------------------------------------------
# Task permutations
#-----------------------------------------------
def task_permutations(state, tasks)
# All permutations are considered
tasks.permutation {|task_list|
planning(Marshal.load(Marshal.dump(task_list)))
return if @plans.size == @max_plans
@state = state
}
end
end