Skip to content

Commit 43a013b

Browse files
committed
Added critical path heuristic
1 parent d8ab4d4 commit 43a013b

3 files changed

Lines changed: 131 additions & 10 deletions

File tree

jupyddl/automated_planner.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from .a_star import AStarBestFirstSearch
55
from .greedy_best_first import GreedyBestFirstSearch
66
from .metrics import Metrics
7-
from .heuristics import BasicHeuristic, DeleteRelaxationHeuristic, CriticalPathHeuristic
7+
from .heuristics import BasicHeuristic, DeleteRelaxationHeuristic, RelaxedCriticalPathHeuristic, CriticalPathHeuristic
88
import coloredlogs
99
import logging
1010
import julia
@@ -31,9 +31,12 @@ def __init__(self, domain_path, problem_path, log_level="DEBUG"):
3131
"basic/goal_count",
3232
"delete_relaxation/h_add",
3333
"delete_relaxation/h_max",
34+
"relaxed_critical_path/1",
35+
"relaxed_critical_path/2",
36+
"relaxed_critical_path/3",
3437
"critical_path/1",
3538
"critical_path/2",
36-
"critical_path/3",
39+
"critical_path/3"
3740
]
3841

3942
# Logger
@@ -166,6 +169,8 @@ def astar_best_first_search(
166169
heuristic = BasicHeuristic(self, heuristic_key)
167170
elif "delete_relaxation" in heuristic_key:
168171
heuristic = DeleteRelaxationHeuristic(self, heuristic_key)
172+
elif "relaxed_critical_path" in heuristic_key:
173+
heuristic = RelaxedCriticalPathHeuristic(self, int(heuristic_key[-1]))
169174
elif "critical_path" in heuristic_key:
170175
heuristic = CriticalPathHeuristic(self, int(heuristic_key[-1]))
171176
else:
@@ -188,6 +193,8 @@ def greedy_best_first_search(
188193
heuristic = BasicHeuristic(self, "basic/goal_count")
189194
elif "delete_relaxation" in heuristic_key:
190195
heuristic = DeleteRelaxationHeuristic(self, heuristic_key)
196+
elif "relaxed_critical_path" in heuristic_key:
197+
heuristic = RelaxedCriticalPathHeuristic(self, int(heuristic_key[-1]))
191198
elif "critical_path" in heuristic_key:
192199
heuristic = CriticalPathHeuristic(self, int(heuristic_key[-1]))
193200
else:

jupyddl/heuristics.py

Lines changed: 120 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
from .node import Node
23

34

45
class BasicHeuristic:
@@ -129,17 +130,17 @@ def __facts_eq(self, facts_dict, facts_set):
129130
return True
130131

131132

132-
class CriticalPathHeuristic:
133+
class RelaxedCriticalPathHeuristic:
133134
def __init__(self, automated_planner, critical_path_level=1):
134-
class CPCache:
135+
class RCPCache:
135136
def __init__(self, domain=None, axioms=None, preconds=None, additions=None):
136137
self.domain = domain
137138
self.axioms = axioms
138139
self.preconds = preconds
139140
self.additions = additions
140141

141142
self.automated_planner = automated_planner
142-
self.cache = CPCache()
143+
self.cache = RCPCache()
143144
if critical_path_level > 3:
144145
logging.warning(
145146
"Critical Path level is only implemented until 3, forcing it to 3."
@@ -176,9 +177,7 @@ def compute(self, state):
176177
if str(g) in fact_costs_str:
177178
costs.append(fact_costs_str[str(g)])
178179
if self.critical_path_level == 2:
179-
pairs_of_goals = [
180-
(g1, g2) for g1 in goals for g2 in goals if g1 != g2
181-
]
180+
pairs_of_goals = [(g1, g2) for g1 in goals for g2 in goals if g1 != g2]
182181
for gs in pairs_of_goals:
183182
if (
184183
str(gs[0]) in fact_costs_str
@@ -259,3 +258,118 @@ def __facts_eq(self, facts_dict, facts_set):
259258
if not (str(f) in fact_costs_str.keys()):
260259
return False
261260
return True
261+
262+
class CriticalPathHeuristic:
263+
def __init__(self, automated_planner, critical_path_level=1):
264+
self.automated_planner = automated_planner
265+
266+
if critical_path_level > 3:
267+
logging.warning(
268+
"Critical Path level is only implemented until 3, forcing it to 3."
269+
)
270+
self.critical_path_level = 3
271+
if critical_path_level < 1:
272+
logging.warning(
273+
"Critical Path level has to be at least 1, forcing it to 1."
274+
)
275+
self.critical_path_level = 1
276+
else:
277+
self.critical_path_level = critical_path_level
278+
279+
self.goals = []
280+
281+
if self.critical_path_level == 1:
282+
self.goals = self.automated_planner.goals
283+
#do a dijkstra search for each goal in the goals
284+
285+
if self.critical_path_level == 2:
286+
self.goals = [[g1, g2] for g1 in self.automated_planner.goals for g2 in self.automated_planner.goals if g1 != g2]
287+
#create subgoal1, subgoal2
288+
289+
if self.critical_path_level == 3:
290+
self.goals = [
291+
[g1, g2, g3]
292+
for g1 in self.automated_planner.goals
293+
for g2 in self.automated_planner.goals
294+
for g3 in self.automated_planner.goals
295+
if g1 != g2 and g1 != g3 and g2 != g3
296+
]
297+
298+
print (self.goals)
299+
300+
301+
def __h_max(self, costs):
302+
return max(costs)
303+
304+
def compute(self, state):
305+
costs = []
306+
307+
for subgoal in self.goals:
308+
costs.append(self.__dijkstra_search(state, subgoal))
309+
310+
return self.__h_max(costs)
311+
312+
313+
def __hash(self, node):
314+
sep = ", Dict{Symbol,Any}"
315+
string = str(node.state)
316+
return string.split(sep, 1)[0] + ")"
317+
318+
319+
def __dijkstra_search(self, state, goal):
320+
def zero_heuristic():
321+
return 0
322+
323+
init = Node(state, self.automated_planner, is_closed=False, is_open=True, heuristic=zero_heuristic)
324+
325+
open_nodes_n = 1
326+
nodes = dict()
327+
nodes[self.__hash(init)] = init
328+
329+
while open_nodes_n > 0:
330+
current_key = min(
331+
[n for n in nodes if nodes[n].is_open],
332+
key=(lambda k: nodes[k].f_cost),
333+
)
334+
current_node = nodes[current_key]
335+
336+
if self.automated_planner.satisfies(goal, current_node.state):
337+
return current_node.g_cost
338+
339+
current_node.is_closed = True
340+
current_node.is_open = False
341+
open_nodes_n -= 1
342+
343+
actions = self.automated_planner.available_actions(current_node.state)
344+
345+
for act in actions:
346+
child = Node(
347+
state=self.automated_planner.transition(current_node.state, act),
348+
automated_planner=self.automated_planner,
349+
parent_action=act,
350+
parent=current_node,
351+
heuristic=zero_heuristic,
352+
is_closed=False,
353+
is_open=True)
354+
355+
child_hash = self.__hash(child)
356+
357+
if child_hash in nodes:
358+
if nodes[child_hash].is_closed:
359+
continue
360+
361+
if not nodes[child_hash].is_open:
362+
nodes[child_hash] = child
363+
open_nodes_n += 1
364+
365+
else:
366+
if child.g_cost < nodes[child_hash].g_cost:
367+
nodes[child_hash] = child
368+
open_nodes_n += 1
369+
370+
else:
371+
nodes[child_hash] = child
372+
open_nodes_n += 1
373+
374+
self.automated_planner.logger.warning("!!! No path found !!!")
375+
return float('inf')

scripts/ipc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323
output = sys.argv[2]
2424

2525
apla = AutomatedPlanner(domain, problem, log_level="WARNING")
26-
path, metrics = apla.astar_best_first_search(heuristic_key="delete_relaxation/h_max")
26+
path, metrics = apla.astar_best_first_search(heuristic_key="critical_path/2")
2727
actions = apla.get_actions_from_path(path)
2828
path = Path(path)
29-
path2, metrics2 = apla.astar_best_first_search(heuristic_key="delete_relaxation/h_add")
29+
path2, metrics2 = apla.astar_best_first_search(heuristic_key="critical_path/1")
3030
actions2 = apla.get_actions_from_path(path2)
3131
path2 = Path(path2)
3232

0 commit comments

Comments
 (0)