Skip to content

Commit 5321d78

Browse files
authored
Merge pull request #67 from APLA-Toolbox/add-data-analyst-docs
Resolve issues 63 61 65
2 parents 61997ca + 98c77e4 commit 5321d78

4 files changed

Lines changed: 90 additions & 28 deletions

File tree

.github/workflows/format.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: format
22
on:
3-
pull_request:
3+
push:
44
branches: [main]
55
jobs:
66
format:
@@ -25,4 +25,4 @@ jobs:
2525
uses: stefanzweifel/git-auto-commit-action@v4.8.0
2626
with:
2727
commit_message: Apply formatting changes
28-
branch: ${{ github.head_ref }}
28+
branch: main

README.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ $ python3 -m pip install jupyddl
5151
# REFL Mode
5252

5353
- Run `python3` in the terminal.
54-
- Use the AutomatedPlanner class to do what you want:
54+
55+
## [AutomatedPlanner]
56+
5557
```python
5658
from jupyddl import AutomatedPlanner # takes some time because it has to instantiate the Julia interface
5759
apl = AutomatedPlanner("data/domain.pddl", "data/problem.pddl)
@@ -77,6 +79,32 @@ print(apl.get_actions_from_path(path))
7779
[<PyCall.jlwrap flip_row(r1)>, <PyCall.jlwrap flip_row(r3)>, <PyCall.jlwrap flip_column(c2)>]
7880
```
7981

82+
## [Data Analyst]
83+
84+
Make sure you have a data folder where you run your environment that contains independent folders with "domain.pddl" and "problem.pddl" files, with those standard names.
85+
86+
```python
87+
from jupyddl import DataAnalyst
88+
89+
da = DataAnalyst()
90+
da.plot_astar_data() # plots complexity statistics for all the problem.pddl/domain.pddl couples in the data/ folder
91+
92+
da.plot_astar_data(problem="data/flip/problem.pddl", domain="data/flip/domain.pddl") # scatter complexity statistics for the provided pddl
93+
94+
da.plot_astar_data(heuristic_key="zero") # use h=0 instead of goal_count for your computation
95+
96+
da.plot_dfs() # same as astar
97+
98+
da.comparative_data_plot() # Run all planners on the data folder and plots them on the same figure, data is stored in a data.json file
99+
100+
da.comparative_data_plot(astar=False) # Exclude astar from the comparative plot
101+
102+
da.comparative_data_plot(heuristic_key="zero") # use zero heuristic for h based planners
103+
104+
da.comparative_data_plot(collect_new_data=False) # uses data.json to plot the data
105+
```
106+
107+
80108
# Contribute
81109

82110
Open an issue to state clearly the contribution you want to make. Upon aproval send in a PR with the Issue referenced. (Implement Issue #No / Fix Issue #No).

jupyddl/automated_planner.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ def __init__(self, domain_path, problem_path, log_level="DEBUG"):
3131
self.logger = logging.getLogger("automated_planning")
3232
coloredlogs.install(level=log_level)
3333

34+
# Running external Julia functions once to create the routes
35+
self.__run_julia_once()
36+
37+
def __run_julia_once(self):
38+
self.satisfies(self.problem.goal, self.initial_state)
39+
self.state_has_term(self.initial_state, self.goals[0])
40+
actions = self.available_actions(self.initial_state)
41+
self.transition(self.initial_state, actions[0])
42+
3443
def __init_logger(self, log_level):
3544
import os
3645

jupyddl/data_analyst.py

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,27 @@ def __get_all_pddl_from_data(self):
3737
return [("data/problem.pddl", "data/domain.pddl")]
3838

3939
def __plot_data(self, times, total_nodes, plot_title):
40-
plt.plot(total_nodes, times, "b:o")
40+
data = dict()
41+
for i, val in enumerate(total_nodes):
42+
data[val] = times[i]
43+
nodes_sorted = sorted(list(data.keys()))
44+
times_y = []
45+
for node_opened in nodes_sorted:
46+
times_y.append(data[node_opened])
47+
plt.plot(nodes_sorted, times_y, "r:o")
4148
plt.xlabel("Number of opened nodes")
4249
plt.ylabel("Planning computation time")
50+
plt.xscale('symlog')
4351
plt.title(plot_title)
44-
plt.xscale("symlog")
45-
plt.yscale("log")
4652
plt.grid(True)
4753
plt.show(block=False)
4854

4955
def __scatter_data(self, times, total_nodes, plot_title):
5056
plt.scatter(total_nodes, times)
5157
plt.xlabel("Number of opened nodes")
5258
plt.ylabel("Planning computation time")
59+
plt.xscale('symlog')
5360
plt.title(plot_title)
54-
plt.xscale("symlog")
55-
plt.yscale("log")
5661
plt.grid(True)
5762
plt.show(block=False)
5863

@@ -61,41 +66,46 @@ def __gather_data_astar(
6166
):
6267
has_multiple_files_tested = True
6368
if not domain_path or not problem_path:
64-
has_multiple_files_tested = False
6569
metrics = dict()
6670
for problem, domain in self.__get_all_pddl_from_data():
6771
logging.debug("Loading new PDDL instance planned with A*...")
6872
logging.debug("Domain: " + domain)
6973
logging.debug("Problem: " + problem)
7074
apla = AutomatedPlanner(domain, problem)
7175
if heuristic_key in apla.available_heuristics:
72-
_, total_time, opened_nodes = apla.astar_best_first_search(
76+
path, total_time, opened_nodes = apla.astar_best_first_search(
7377
heuristic=apla.available_heuristics[heuristic_key]
7478
)
7579
else:
7680
logging.critical(
7781
"Heuristic is not implemented! (Key not found in registered heuristics dict)"
7882
)
7983
return [0], [0], has_multiple_files_tested
80-
metrics[total_time] = opened_nodes
84+
if path:
85+
metrics[total_time] = opened_nodes
86+
else:
87+
metrics[0] = 0
8188

8289
total_nodes = list(metrics.values())
8390
times = list(metrics.keys())
8491
return times, total_nodes, has_multiple_files_tested
92+
has_multiple_files_tested = False
8593
logging.debug("Loading new PDDL instance...")
8694
logging.debug("Domain: " + domain_path)
8795
logging.debug("Problem: " + problem_path)
8896
apla = AutomatedPlanner(domain_path, problem_path)
8997
if heuristic_key in apla.available_heuristics:
90-
_, total_time, opened_nodes = apla.astar_best_first_search(
98+
path, total_time, opened_nodes = apla.astar_best_first_search(
9199
heuristic=apla.available_heuristics[heuristic_key]
92100
)
93101
else:
94102
logging.critical(
95103
"Heuristic is not implemented! (Key not found in registered heuristics dict)"
96104
)
97105
return [0], [0], has_multiple_files_tested
98-
return [total_time], [opened_nodes], has_multiple_files_tested
106+
if path:
107+
return [total_time], [opened_nodes], has_multiple_files_tested
108+
return [0], [0], has_multiple_files_tested
99109

100110
def plot_astar_data(self, heuristic_key="goal_count", domain="", problem=""):
101111
if bool(not problem) != bool(not domain):
@@ -115,25 +125,30 @@ def plot_astar_data(self, heuristic_key="goal_count", domain="", problem=""):
115125
def __gather_data_bfs(self, domain_path="", problem_path=""):
116126
has_multiple_files_tested = True
117127
if not domain_path or not problem_path:
118-
has_multiple_files_tested = False
119128
metrics = dict()
120129
for problem, domain in self.__get_all_pddl_from_data():
121130
logging.debug("Loading new PDDL instance planned with BFS...")
122131
logging.debug("Domain: " + domain)
123132
logging.debug("Problem: " + problem)
124133
apla = AutomatedPlanner(domain, problem)
125-
_, total_time, opened_nodes = apla.breadth_first_search()
126-
metrics[total_time] = opened_nodes
134+
path, total_time, opened_nodes = apla.breadth_first_search()
135+
if path:
136+
metrics[total_time] = opened_nodes
137+
else:
138+
metrics[0] = 0
127139

128140
total_nodes = list(metrics.values())
129141
times = list(metrics.keys())
130142
return times, total_nodes, has_multiple_files_tested
143+
has_multiple_files_tested = False
131144
logging.debug("Loading new PDDL instance...")
132145
logging.debug("Domain: " + domain_path)
133146
logging.debug("Problem: " + problem_path)
134147
apla = AutomatedPlanner(domain_path, problem_path)
135-
_, total_time, opened_nodes = apla.breadth_first_search()
136-
return [total_time], [opened_nodes], has_multiple_files_tested
148+
path, total_time, opened_nodes = apla.breadth_first_search()
149+
if path:
150+
return [total_time], [opened_nodes], has_multiple_files_tested
151+
return [0], [0], has_multiple_files_tested
137152

138153
def plot_bfs(self, domain="", problem=""):
139154
title = "BFS Statistics"
@@ -153,25 +168,30 @@ def plot_bfs(self, domain="", problem=""):
153168
def __gather_data_dfs(self, domain_path="", problem_path=""):
154169
has_multiple_files_tested = True
155170
if not domain_path or not problem_path:
156-
has_multiple_files_tested = False
157171
metrics = dict()
158172
for problem, domain in self.__get_all_pddl_from_data():
159173
logging.debug("Loading new PDDL instance planned with DFS...")
160174
logging.debug("Domain: " + domain)
161175
logging.debug("Problem: " + problem)
162176
apla = AutomatedPlanner(domain, problem)
163-
_, total_time, opened_nodes = apla.depth_first_search()
164-
metrics[total_time] = opened_nodes
177+
path, total_time, opened_nodes = apla.depth_first_search()
178+
if path:
179+
metrics[total_time] = opened_nodes
180+
else:
181+
metrics[0] = 0
165182

166183
total_nodes = list(metrics.values())
167184
times = list(metrics.keys())
168185
return times, total_nodes, has_multiple_files_tested
186+
has_multiple_files_tested = False
169187
logging.debug("Loading new PDDL instance...")
170188
logging.debug("Domain: " + domain_path)
171189
logging.debug("Problem: " + problem_path)
172190
apla = AutomatedPlanner(domain_path, problem_path)
173-
_, total_time, opened_nodes = apla.depth_first_search()
174-
return [total_time], [opened_nodes], has_multiple_files_tested
191+
path, total_time, opened_nodes = apla.depth_first_search()
192+
if path:
193+
return [total_time], [opened_nodes], has_multiple_files_tested
194+
return [0], [0], has_multiple_files_tested
175195

176196
def plot_dfs(self, problem="", domain=""):
177197
title = "DFS Statistics"
@@ -191,25 +211,30 @@ def plot_dfs(self, problem="", domain=""):
191211
def __gather_data_dijkstra(self, domain_path="", problem_path=""):
192212
has_multiple_files_tested = True
193213
if not domain_path or not problem_path:
194-
has_multiple_files_tested = False
195214
metrics = dict()
196215
for problem, domain in self.__get_all_pddl_from_data():
197216
logging.debug("Loading new PDDL instance planned with Dijkstra...")
198217
logging.debug("Domain: " + domain)
199218
logging.debug("Problem: " + problem)
200219
apla = AutomatedPlanner(domain, problem)
201-
_, total_time, opened_nodes = apla.dijktra_best_first_search()
202-
metrics[total_time] = opened_nodes
220+
path, total_time, opened_nodes = apla.dijktra_best_first_search()
221+
if path:
222+
metrics[total_time] = opened_nodes
223+
else:
224+
metrics[0] = 0
203225

204226
total_nodes = list(metrics.values())
205227
times = list(metrics.keys())
206228
return times, total_nodes, has_multiple_files_tested
229+
has_multiple_files_tested = False
207230
logging.debug("Loading new PDDL instance...")
208231
logging.debug("Domain: " + domain_path)
209232
logging.debug("Problem: " + problem_path)
210233
apla = AutomatedPlanner(domain_path, problem_path)
211-
_, total_time, opened_nodes = apla.dijktra_best_first_search()
212-
return [total_time], [opened_nodes], has_multiple_files_tested
234+
path, total_time, opened_nodes = apla.dijktra_best_first_search()
235+
if path:
236+
return [total_time], [opened_nodes], has_multiple_files_tested
237+
return [0], [0], has_multiple_files_tested
213238

214239
def plot_dijkstra(self, problem="", domain=""):
215240
title = "Dijkstra Statistics"

0 commit comments

Comments
 (0)