Skip to content

Commit 67fd2e7

Browse files
committed
Simplify and speed up relevance analysis and relaxation heuristics
Grounding relevance analysis: - Test whether an operator has a relevant effect with set.isdisjoint instead of building the throwaway union (add | del) and its intersection with the relevant facts on every operator and round. - Detect the fixpoint by comparing the size of the relevant-fact set before and after each pass (the set only grows) instead of copying the whole set each round to compare it. Relaxation heuristics (evaluated once per generated node): - Use the node's state set directly instead of copying it; it is only read, never mutated. - Pass generators to the sum/max evaluator instead of materializing intermediate lists of precondition/goal distances. All changes preserve behavior (identical grounded operators and plans; full test suite still passes).
1 parent ce3de70 commit 67fd2e7

2 files changed

Lines changed: 16 additions & 11 deletions

File tree

pyperplan/grounding.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,20 @@ def _relevance_analysis(operators, goals):
112112
are removed, and operators left without any effect are pruned entirely.
113113
"""
114114
relevant_facts = set(goals)
115-
changed = True
116-
while changed:
117-
old_relevant_facts = relevant_facts.copy()
115+
# Iterate to a fixpoint: an operator with a relevant effect makes its
116+
# preconditions relevant too. relevant_facts only grows, so a pass that adds
117+
# nothing means we have reached the fixpoint.
118+
while True:
119+
size_before = len(relevant_facts)
118120
for op in operators:
119-
if (op.add_effects | op.del_effects) & relevant_facts:
121+
has_relevant_effect = not (
122+
relevant_facts.isdisjoint(op.add_effects)
123+
and relevant_facts.isdisjoint(op.del_effects)
124+
)
125+
if has_relevant_effect:
120126
relevant_facts |= op.preconditions
121-
changed = old_relevant_facts != relevant_facts
127+
if len(relevant_facts) == size_before:
128+
break
122129

123130
relevant_operators = []
124131
for op in operators:

pyperplan/heuristics/relaxation.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def __init__(self, task):
111111

112112
def __call__(self, node):
113113
"""Compute the heuristic value for the state stored in ``node``."""
114-
state = set(node.state)
114+
state = node.state
115115

116116
# Reset distance and set to default values.
117117
self.init_distance(state)
@@ -169,9 +169,7 @@ def get_cost(self, operator, pre):
169169
"""
170170
if operator.preconditions:
171171
# Sum / maximize over the heuristic values of all preconditions.
172-
cost = self.eval(
173-
[self.facts[pre].distance for pre in operator.preconditions]
174-
)
172+
cost = self.eval(self.facts[pre].distance for pre in operator.preconditions)
175173
else:
176174
# An operator without preconditions has cost 0.
177175
cost = 0
@@ -187,7 +185,7 @@ def calc_goal_h(self):
187185
hSA and hFF. Returns 0 if the goal is empty.
188186
"""
189187
if self.goals:
190-
return self.eval([self.facts[fact].distance for fact in self.goals])
188+
return self.eval(self.facts[fact].distance for fact in self.goals)
191189
else:
192190
return 0
193191

@@ -328,7 +326,7 @@ def __init__(self, task):
328326

329327
def calc_h_with_plan(self, node):
330328
"""Calculate the hFF value together with a relaxed plan."""
331-
state = set(node.state)
329+
state = node.state
332330
# Reset distance and set to default values.
333331
self.init_distance(state)
334332

0 commit comments

Comments
 (0)