def test_formula_flattening(): lang = generate_bw_loc_and_clear(3) b1, b2, b3, clear = lang.get('b1', 'b2', 'b3', 'clear') f1 = land(clear(b1), clear(b2), clear(b3), clear(b1), flat=True) f2 = lor(clear(b1), clear(b2), clear(b3), clear(b1), flat=True) assert f1 == flatten(f1) # both are already flat - this tests for syntactic identity assert f2 == flatten(f2) # Now test formulas which are not flat, so flattening them will change their syntactic form f1 = land(clear(b1), clear(b2), clear(b3), clear(b1), flat=False) f2 = lor(clear(b1), f1, clear(b3), (clear(b3) | clear(b1)), flat=False) z = flatten(f1) assert f1 != z and len(z.subformulas) == 4 z = flatten(f2) assert f2 != z and len(z.subformulas) == 5 assert clear(b1) == flatten(clear(b1)) # Flattening non-compound formulas leaves them untouched
def assert_action(self, op): """ For given operator op and timestep t, assert the SMT expression: op@t --> op.precondition@t op@t --> op.effects@(t+1) """ ml = self.metalang vart = _get_timestep_var(ml) apred = ml.get_predicate(op.name) vars_ = generate_action_arguments(ml, op) # Don't use the timestep arg substitution = { symref(param): arg for param, arg in zip(op.parameters, vars_) } args = vars_ + [vart] happens = apred(*args) prec = term_substitution(flatten(op.precondition), substitution) a_implies_prec = forall(*args, implies(happens, self.to_metalang(prec, vart))) self.theory.append(a_implies_prec) for eff in op.effects: eff = term_substitution(eff, substitution) antec = happens # Prepend the effect condition, if necessary: if not isinstance(eff.condition, Tautology): antec = land(antec, self.to_metalang(eff.condition, vart)) if isinstance(eff, fs.AddEffect): a_implies_eff = implies( antec, self.to_metalang(eff.atom, vart + 1, subt=vart)) elif isinstance(eff, fs.DelEffect): a_implies_eff = implies( antec, self.to_metalang(~eff.atom, vart + 1, subt=vart)) elif isinstance(eff, fs.FunctionalEffect): lhs = self.to_metalang(eff.lhs, vart + 1, subt=vart) rhs = self.to_metalang(eff.rhs, vart, subt=vart) a_implies_eff = implies(antec, lhs == rhs) else: raise TransformationError(f"Can't compile effect {eff}") self.theory.append(forall(*args, a_implies_eff))
def test_neg_precondition_compilation_on_problem(): problem = generate_strips_blocksworld_problem() lang = problem.language b1, clear, on, ontable, handempty, holding = lang.get('b1', 'clear', 'on', 'ontable', 'handempty', 'holding') x = lang.variable('x', 'object') compiled = compile_negated_preconditions_away(problem) # Check that nothing was changed for aname, a1 in problem.actions.items(): a2 = compiled.get_action(aname) assert flatten(a1.precondition) == a2.precondition act1 = problem.action('act1', [x], precondition=clear(x) & ~ontable(x) & handempty(), effects=[DelEffect(ontable(x), ~clear(x)), AddEffect(ontable(x))]) compiled = compile_negated_preconditions_away(problem) assert str(compiled.get_action('act1').precondition) == '(clear(x) and _not_ontable(x) and handempty())'
def test_neg_precondition_compilation_on_action(): problem = generate_strips_blocksworld_problem() lang = problem.language clear, on, ontable, handempty, holding = lang.get('clear', 'on', 'ontable', 'handempty', 'holding') x = lang.variable('x', 'object') negpreds = dict() pickup = problem.get_action('pick-up') pickupc = compile_action_negated_preconditions_away(pickup, negpreds) assert flatten(pickup.precondition) == pickupc.precondition and len(negpreds) == 0 act1 = problem.action('act1', [x], precondition=clear(x) & ~ontable(x) & handempty(), effects=[DelEffect(ontable(x), ~clear(x)), AddEffect(ontable(x))]) act1c = compile_action_negated_preconditions_away(act1, negpreds) assert len(negpreds) == 2 # For ontable and for clear assert str(act1c.precondition) == '(clear(x) and _not_ontable(x) and handempty())' assert str(act1c.effects[0].condition) == '_not_clear(x)'