Skip to content

Commit 8c4feb2

Browse files
committed
update heuristics architecture
1 parent b536d40 commit 8c4feb2

12 files changed

Lines changed: 104 additions & 41 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,15 +104,15 @@ da.plot_astar() # plots complexity statistics for all the problem.pddl/domain.pd
104104

105105
da.plot_astar(problem="pddl-examples/flip/problem.pddl", domain="pddl-examples/flip/domain.pddl") # scatter complexity statistics for the provided pddl
106106

107-
da.plot_astar(heuristic_key="zero") # use h=0 instead of goal_count for your computation
107+
da.plot_astar(heuristic_key="basic/zero") # use h=0 instead of goal_count for your computation
108108

109109
da.plot_dfs() # same as astar
110110

111111
da.comparative_data_plot() # Run all planners on the pddl-examples folder and plots them on the same figure, data is stored in a data.json file
112112

113113
da.comparative_data_plot(astar=False) # Exclude astar from the comparative plot
114114

115-
da.comparative_data_plot(heuristic_key="zero") # use zero heuristic for h based planners
115+
da.comparative_data_plot(heuristic_key="basic/zero") # use zero heuristic for h based planners
116116

117117
da.comparative_data_plot(collect_new_data=False) # uses data.json to plot the data
118118
```

jupyddl/a_star.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from .heuristics import zero_heuristic
21
from .node import Node
32
import logging
43
import math

jupyddl/automated_planner.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from .dfs import DepthFirstSearch
33
from .dijkstra import DijkstraBestFirstSearch
44
from .a_star import AStarBestFirstSearch
5-
from .heuristics import goal_count_heuristic, zero_heuristic
5+
from .heuristics import BasicHeuristic
66
import coloredlogs
77
import logging
88
import julia
@@ -22,9 +22,10 @@ def __init__(self, domain_path, problem_path, log_level="DEBUG"):
2222
self.problem = self.pddl.load_problem(problem_path)
2323
self.initial_state = self.pddl.initialize(self.problem)
2424
self.goals = self.__flatten_goal()
25-
self.available_heuristics = dict()
26-
self.available_heuristics["goal_count"] = goal_count_heuristic
27-
self.available_heuristics["zero"] = zero_heuristic
25+
self.available_heuristics = [
26+
"basic/zero",
27+
"basic/goal_count"
28+
]
2829

2930
# Logger
3031
self.__init_logger(log_level)
@@ -40,6 +41,8 @@ def __run_julia_once(self):
4041
actions = self.available_actions(self.initial_state)
4142
self.transition(self.initial_state, actions[0])
4243

44+
def __rela
45+
4346
def __init_logger(self, log_level):
4447
import os
4548

@@ -53,7 +56,7 @@ def __init_logger(self, log_level):
5356
)
5457

5558
def display_available_heuristics(self):
56-
print(list(self.available_heuristics.keys()))
59+
print(self.available_heuristics)
5760

5861
def transition(self, state, action):
5962
return self.pddl.transition(self.domain, state, action, check=False)
@@ -125,8 +128,13 @@ def dijktra_best_first_search(self):
125128

126129
return path, total_time, opened_nodes
127130

128-
def astar_best_first_search(self, heuristic=goal_count_heuristic):
129-
astar = AStarBestFirstSearch(self, heuristic)
131+
def astar_best_first_search(self, heuristic_key="basic/goal_count"):
132+
if "basic" in heuristic_key:
133+
heuristic = BasicHeuristic(self, heuristic_key)
134+
else:
135+
logging.fatal("Not yet implemented")
136+
exit()
137+
astar = AStarBestFirstSearch(self, heuristic.compute)
130138
last_node, total_time, opened_nodes = astar.search()
131139
path = self.__retrace_path(last_node)
132140

jupyddl/data_analyst.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
class DataAnalyst:
2020
def __init__(self):
2121
logging.info("Instantiating data analyst...")
22-
self.available_heuristics = ["goal_count", "zero"]
22+
self.available_heuristics = ["basic/goal_count", "basic/zero"]
2323

2424
def __get_all_pddl_from_data(self, max_pddl_instances=-1):
2525
tested_files = []
@@ -75,7 +75,7 @@ def __gather_data_astar(
7575
self,
7676
domain_path="",
7777
problem_path="",
78-
heuristic_key="goal_count",
78+
heuristic_key="basic/goal_count",
7979
max_pddl_instances=-1,
8080
):
8181
has_multiple_files_tested = True
@@ -90,7 +90,7 @@ def __gather_data_astar(
9090
apla = AutomatedPlanner(domain, problem)
9191
if heuristic_key in apla.available_heuristics:
9292
path, total_time, opened_nodes = apla.astar_best_first_search(
93-
heuristic=apla.available_heuristics[heuristic_key]
93+
heuristic_key=heuristic_key
9494
)
9595
else:
9696
logging.critical(
@@ -112,7 +112,7 @@ def __gather_data_astar(
112112
apla = AutomatedPlanner(domain_path, problem_path)
113113
if heuristic_key in apla.available_heuristics:
114114
path, total_time, opened_nodes = apla.astar_best_first_search(
115-
heuristic=apla.available_heuristics[heuristic_key]
115+
heuristic_key=heuristic_key
116116
)
117117
else:
118118
logging.critical(
@@ -124,7 +124,7 @@ def __gather_data_astar(
124124
return [0], [0], has_multiple_files_tested
125125

126126
def plot_astar(
127-
self, heuristic_key="goal_count", domain="", problem="", max_pddl_instances=-1
127+
self, heuristic_key="basic/goal_count", domain="", problem="", max_pddl_instances=-1
128128
):
129129
if bool(not problem) != bool(not domain):
130130
logging.warning(
@@ -288,7 +288,7 @@ def plot_dijkstra(self, problem="", domain="", max_pddl_instances=-1):
288288

289289
def __gather_data(
290290
self,
291-
heuristic_key="goal_count",
291+
heuristic_key="basic/goal_count",
292292
astar=True,
293293
bfs=True,
294294
dfs=True,
@@ -374,7 +374,7 @@ def comparative_data_plot(
374374
dijkstra=True,
375375
domain="",
376376
problem="",
377-
heuristic_key="goal_count",
377+
heuristic_key="basic/goal_count",
378378
collect_new_data=True,
379379
max_pddl_instances=-1,
380380
):

jupyddl/dijkstra.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
from .heuristics import zero_heuristic
21
from .node import Node
32
import logging
43
import math
54
from datetime import datetime as timestamp
65
from time import time as now
76

8-
7+
def zero_heuristic():
8+
return 0
99
class DijkstraBestFirstSearch:
1010
def __init__(self, automated_planner):
1111
self.automated_planner = automated_planner

jupyddl/heuristics.py

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,60 @@
1-
def zero_heuristic(state, automated_planner):
2-
return 0
1+
import logging
32

3+
class BasicHeuristic:
4+
def __init__(self, automated_planner, heuristic_key):
5+
self.automated_planner = automated_planner
6+
self.heuristic_keys = {
7+
"basic/zero": self.__zero_heuristic,
8+
"basic/goal_count": self.__goal_count_heuristic
9+
}
10+
if heuristic_key not in list(self.heuristic_keys.keys()):
11+
logging.warning("Heuristic key isn't registered, forcing it to [basic/goal_count]")
12+
heuristic_key = "basic/goal_count"
413

5-
def goal_count_heuristic(state, automated_planner):
6-
count = 0
7-
for goal in automated_planner.goals:
8-
if not automated_planner.state_has_term(state, goal):
9-
count += 1
10-
return count
14+
self.current_h = heuristic_key
15+
16+
def compute(self, state):
17+
return self.heuristic_keys[self.current_h](state)
18+
19+
def __zero_heuristic(self, state):
20+
return 0
21+
22+
def __goal_count_heuristic(self, state):
23+
count = 0
24+
for goal in self.automated_planner.goals:
25+
if not self.automated_planner.state_has_term(state, goal):
26+
count += 1
27+
return count
28+
29+
30+
class DeleteRelaxationHeuristic:
31+
def __init__(self, automated_planner, heuristic_key):
32+
self.automated_planner = automated_planner
33+
self.heuristic_keys = {
34+
"delete_relaxation/h_add": self.__h_add,
35+
"delete_relaxation/h_max": self.__h_max
36+
}
37+
if heuristic_key not in list(self.heuristic_keys.keys()):
38+
logging.warning("Heuristic key isn't registered, forcing it to [delete_relaxation/h_add]")
39+
heuristic_key = "delete_relaxation/h_add"
40+
41+
self.current_h = heuristic_key
42+
43+
def compute(self, state):
44+
return self.heuristic_keys[self.current_h](state)
45+
46+
def __pre_compute(self):
47+
logging.fatal("Delete relaxation h_add is not yet implemented")
48+
exit()
49+
50+
def __cache(self):
51+
logging.fatal("Delete relaxation h_add is not yet implemented")
52+
exit()
53+
54+
def __h_add(self, state):
55+
logging.fatal("Delete relaxation h_add is not yet implemented")
56+
exit()
57+
58+
def __h_max(self, state):
59+
logging.fatal("Delete relaxation h_max is not yet implemented")
60+
exit()

jupyddl/node.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def __init__(
2222
self.g_cost = temp_cost
2323
if heuristic_based:
2424
if heuristic:
25-
self.h_cost = heuristic(state, automated_planner)
25+
self.h_cost = heuristic(state)
2626
else:
2727
automated_planner.logger.warning(
2828
"Heuristic function wasn't found, forcing it to return zero [Best practice: use the zero_heuristic function]"
@@ -38,7 +38,7 @@ def __init__(
3838
self.g_cost = g_cost
3939
if heuristic_based:
4040
if heuristic:
41-
self.h_cost = heuristic(state, automated_planner)
41+
self.h_cost = heuristic(state)
4242
else:
4343
automated_planner.logger.warning(
4444
"Heuristic function wasn't found, forcing it to return zero [Best practice: use the zero_heuristic function]"

main.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@ def main():
1515
apla_tbx = AutomatedPlanner(args.domain, args.problem)
1616
apla_tbx.logger.info("Starting the planning script")
1717
apla_tbx.logger.debug(
18-
"Available heuristics: " + str(apla_tbx.available_heuristics.keys())
18+
"Available heuristics: " + str(apla_tbx.available_heuristics)
1919
)
2020

21-
path, computation_time = apla_tbx.dijktra_best_first_search(time_it=True)
21+
path, computation_time, _ = apla_tbx.dijktra_best_first_search()
2222
apla_tbx.logger.debug(apla_tbx.get_actions_from_path(path))
2323

2424
apla_tbx.logger.debug("Computation time: %.2f seconds" % computation_time)
2525
apla_tbx.logger.info("Terminate with grace...")
26+
return 0
2627

2728

2829
if __name__ == "__main__":

tests/test_astar.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ def test_astar_init():
1212
apla = AutomatedPlanner(
1313
"pddl-examples/flip/domain.pddl", "pddl-examples/flip/problem.pddl"
1414
)
15-
astar = AStarBestFirstSearch(apla, apla.available_heuristics["goal_count"])
16-
assert astar.init.h_cost == apla.available_heuristics["goal_count"](
15+
astar = AStarBestFirstSearch(apla, apla.available_heuristics["basic/goal_count"])
16+
assert astar.init.h_cost == apla.available_heuristics["basic/goal_count"](
1717
apla.initial_state, apla
1818
)
1919

@@ -23,7 +23,7 @@ def test_astar_goal():
2323
"pddl-examples/flip/domain.pddl", "pddl-examples/flip/problem.pddl"
2424
)
2525
path, _, _ = apla.astar_best_first_search()
26-
assert apla.available_heuristics["goal_count"](path[-1].state, apla) == 0
26+
assert apla.available_heuristics["basic/goal_count"](path[-1].state, apla) == 0
2727

2828

2929
def test_astar_path_length():

tests/test_heuristics.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ def test_zero_heuristic():
1818
apla = AutomatedPlanner(
1919
"pddl-examples/flip/domain.pddl", "pddl-examples/flip/problem.pddl"
2020
)
21-
heuristic = hs.zero_heuristic(apla.initial_state, apla)
22-
assert heuristic == 0
21+
heuristic = hs.BasicHeuristic(apla, "zero")
22+
h = heuristic.compute(apla.initial_state)
23+
assert h == 0
2324

2425

2526
def test_goal_count_heuristic():
2627
apla = AutomatedPlanner(
2728
"pddl-examples/flip/domain.pddl", "pddl-examples/flip/problem.pddl"
2829
)
29-
heuristic = hs.goal_count_heuristic(apla.initial_state, apla)
30-
assert heuristic == 1
30+
heuristic = hs.BasicHeuristic(apla, "goal_count")
31+
h = heuristic.compute(apla.initial_state)
32+
assert h == 0

0 commit comments

Comments
 (0)