Source code for up_SMT_engine.ProblemBuilder.R2EProblemBuilder
from up_SMT_engine.ProblemBuilder.BaseProblemBuilder import BaseProblemBuilder
[docs]class R2EProblemBuilder(BaseProblemBuilder):
"""Subclass of BaseProblemBuilder, overriding build and adding new methods to implement relaxed relaxed ThereExists parallelism"""
[docs] def add_fluent_constraints(self, problem_instance, plan_len):
"""For each fluent object generate all relevant constraints
Args:
problem_instance (z3.Solver): The solver to which clauses are added
plan_len (int): The plan length
"""
if plan_len > 0:
# Generate explanatory axioms, these are responsible for linking each fluent to the next similar to frame axioms
for fluent in self.fluents:
if self.incremental:
problem_instance.add(
fluent.generate_explanatory_axioms_at_t(
plan_len, self.fluents, self.actions
)
)
problem_instance.add(
fluent.link_chained_vars_to_majors_at_t(plan_len)
)
else:
axioms = fluent.generate_explanatory_axioms_up_to_t(
plan_len, self.fluents, self.actions
)
for axiom in axioms:
problem_instance.add(axiom)
links = fluent.link_chained_vars_to_majors_up_to_t(plan_len)
for linking_constraint in links:
problem_instance.add(linking_constraint)
# Generate bound constraints over chained variables
for fluent in self.fluents:
if self.incremental:
problem_instance.add(
fluent.get_chained_vars_bound_constraints_at_t(plan_len)
)
else:
bound_constraints = (
fluent.get_chained_vars_bound_constraints_up_to_t(plan_len)
)
if bound_constraints is not None:
for constraint in bound_constraints:
problem_instance.add(constraint)
# Generate bound constraints over non-chained fluents
for fluent in self.fluents:
if self.incremental:
problem_instance.add(fluent.get_bound_constraints_at_t(plan_len))
else:
bound_constraints = fluent.get_bound_constraints_up_to_t(plan_len)
if bound_constraints is not None:
for constraint in bound_constraints:
problem_instance.add(constraint)
[docs] def add_action_constraints(self, problem_instance, plan_len):
"""For each action object generate all relevant constraints
Args:
problem_instance (z3.Solver): The solver to which clauses are added
plan_len (int): The plan length
"""
# Generate all causal constraints over all actions. These require that an action occurring causes the correct effects
for action in self.actions:
if self.incremental:
problem_instance.add(
action.get_causal_axioms_at_t(plan_len, self.fluents, self.actions)
)
else:
axioms = action.get_causal_axioms_up_to_t(
plan_len, self.fluents, self.actions
)
for axiom in axioms:
problem_instance.add(axiom)
# Generate all precondition constraints over all actions. These require that an action occurring only happens when preconditions are satisfied
for action in self.actions:
if self.incremental:
problem_instance.add(
action.get_precondition_constraints_at_t(
plan_len, self.fluents, self.actions
)
)
else:
constraints = action.get_precondition_constraints_up_to_t(
plan_len, self.fluents, self.actions
)
for constraint in constraints:
problem_instance.add(constraint)
[docs] def build(self, problem_instance, plan_len, goal_clause):
"""Using clauses generated by actions and fluents build the problem in the z3 Solver
Args:
problem_instance (z3.Solver): The current solver to which clauses are added
plan_len (int): The plan length
goal_clause (Clause): The clause representing all goal conditions
"""
self.add_init(problem_instance, plan_len)
self.add_fluent_constraints(problem_instance, plan_len)
# Don't consider actions, frame axiom constraints and chained variables until after timestep 0
if plan_len > 0:
self.add_action_constraints(problem_instance, plan_len)
# No mutexes required
self.add_goal(problem_instance, goal_clause)
return