def test_strips_analysis(): problem = generate_strips_blocksworld_problem() assert is_strips_problem(problem) lang = problem.language clear, on, ontable, handempty, holding = lang.get('clear', 'on', 'ontable', 'handempty', 'holding') x = lang.variable('x', 'object') phi = clear(x) & ~ontable(x) assert not is_conjunction_of_positive_atoms(clear(x) & ~ontable(x)) assert is_strips_effect_set([DelEffect(ontable(x)), DelEffect(clear(x))]) assert is_strips_effect_set([DelEffect(ontable(x)), DelEffect(ontable(x))]) # Not strips, as it has an effect with conditions: assert not is_strips_effect_set( [DelEffect(ontable(x), clear(x)), AddEffect(ontable(x))]) # Not strips, as it has two contradictory effects: assert not is_strips_effect_set( [DelEffect(ontable(x)), AddEffect(ontable(x))]) problem = generate_fstrips_counters_problem(ncounters=3) assert not is_strips_problem(problem) inc = problem.get_action('increment') assert not is_strips_effect_set(inc.effects)
def test_effect_writing(): problem, loc, clear, b1, table = get_bw_elements() block_var = problem.language.variable("b", "block") e1 = loc(b1) << table e2 = AddEffect(clear(b1)) e3 = DelEffect(clear(b1)) s1, s2, s3 = [print_effect(e) for e in [e1, e2, e3]] assert s1 == "(assign (loc b1) table)" assert s2 == "(clear b1)" assert s3 == "(not (clear b1))" assert print_effects([e1, e2, e3]) == "(and\n {}\n {}\n {})".format(s1, s2, s3) e4 = UniversalEffect([block_var], [AddEffect(clear(block_var))]) s4 = print_effect(e4) assert s4 == "(forall (?b - block) (clear ?b))" e5 = UniversalEffect([block_var], [AddEffect(clear(block_var)), loc(block_var) << table]) s5 = print_effect(e5) assert s5 == "(forall (?b - block) (and\n (clear ?b)\n (assign (loc ?b) table)))" e6 = UniversalEffect([block_var], [FunctionalEffect(loc(block_var), table, condition=clear(block_var))]) s6 = print_effect(e6) assert s6 == "(forall (?b - block) (when (clear ?b) (assign (loc ?b) table)))"
def create_two_action_version(problem): lang = problem.language cell_t, at, reward, unblocked, picked, adjacent = lang.get("cell", "at", "reward", "unblocked", "picked", "adjacent") from_ = lang.variable("from", cell_t) to = lang.variable("to", cell_t) c = lang.variable("c", cell_t) problem.action(name='move', parameters=[from_, to], precondition=land(adjacent(from_, to), at(from_), unblocked(to), flat=True), effects=[DelEffect(at(from_)), AddEffect(at(to))]) x = lang.variable("x", cell_t) problem.action(name='pick-reward', parameters=[x], precondition=at(x) & reward(x), effects=[DelEffect(reward(x)), AddEffect(picked(x))])
def create_noop(problem): # A hackish no-op, to prevent the planner from detecting that the action is useless and pruning it lang = problem.language node_t, at = lang.get("node", "at") x = lang.variable("x", node_t) problem.action(name='noop', parameters=[x], precondition=at(x), effects=[AddEffect(at(x))])
def generate_fstrips_blocksworld_problem(nblocks=4, init="random", goal="random"): lang = generate_fstrips_bw_language(nblocks=nblocks) problem = create_fstrips_problem(lang, domain_name=BASE_DOMAIN_NAME, problem_name='test-instance') block, place, clear, loc, table = lang.get('block', 'place', 'clear', 'loc', 'table') # Generate init pattern if init == 'random': clearplaces, locations = generate_random_bw_pattern(lang) else: if len(init) != nblocks: raise ValueError( f"Blocksworld configuration ({init}) does not match given number of blocks ({nblocks})" ) locations = init clearplaces = compute_clear_from_pattern(lang, locations) for x, y in locations: problem.init.set(loc(lang.get(x)), lang.get(y)) for x in clearplaces: problem.init.add(clear, lang.get(x)) # Generate goal pattern if goal == 'random': clearplaces, locations = generate_random_bw_pattern(lang) else: if len(goal) != nblocks: raise ValueError( f"Blocksworld configuration ({goal}) does not match given number of blocks ({nblocks})" ) locations = goal problem.goal = land(*(loc(lang.get(x)) == lang.get(y) for x, y in locations), flat=True) # Generate move action: move x to y x = lang.variable('x', block) y = lang.variable('y', place) problem.action('move', [x, y], precondition=land(x != y, loc(x) != y, clear(x), clear(y)), effects=[ loc(x) << y, AddEffect(clear(loc(x))), DelEffect(clear(y), condition=(y != table)) ]) return problem
def create_single_action_version(problem): lang = problem.language cell_t, at, reward, unblocked, picked, adjacent = lang.get("cell", "at", "reward", "unblocked", "picked", "adjacent") from_ = lang.variable("from", cell_t) to = lang.variable("to", cell_t) c = lang.variable("c", cell_t) problem.action(name='move', parameters=[from_, to], precondition=land(adjacent(from_, to), at(from_), unblocked(to), exists(c, reward(c)), flat=True), effects=[DelEffect(at(from_)), AddEffect(at(to)), # AddEffect(visited(to)), DelEffect(reward(to))])
def test_effect_writing(): problem, loc, clear, b1, table = get_bw_elements() e1 = loc(b1) << table e2 = AddEffect(clear(b1)) e3 = DelEffect(clear(b1)) s1, s2, s3 = [print_effect(e) for e in [e1, e2, e3]] assert s1 == "(assign (loc b1) table)" assert s2 == "(clear b1)" assert s3 == "(not (clear b1))" assert print_effects([e1, e2, e3]) == "(and\n {}\n {}\n {})".format( s1, s2, s3)
def test_symbol_classification_with_nested_effect_heads(): lang = generate_fstrips_bw_language(nblocks=3) problem = create_fstrips_problem(lang, domain_name='blocksworld', problem_name='test-instance') block, place, clear, loc, table = lang.get('block', 'place', 'clear', 'loc', 'table') x = lang.variable('x', 'block') problem.action('dummy-action', [x], precondition=loc(x) == table, effects=[AddEffect(clear(loc(x)))]) fluent, static = approximate_symbol_fluency(problem, include_builtin=True) assert loc in static and clear in fluent, "loc has not been detected as fluent even though it " \ "appears (nested) in the head of an effect"
def transform_universal_effects(lang, uni_eff) : """ Elimates univeral effects by transforming to multiple conditional effects Arguments ========= lang: object of type FirstOrderLanguage uni_effect: object of type UniversalEffect Returns ======= list: list of instantiated effects """ assert isinstance(uni_eff, UniversalEffect) effect_l = [] # new list of effects for effect in uni_eff.effects : # eliminate quantifiers from formula effect.condition = process_formula(effect.condition, lang) # if effect is Uni. Effect then transform to a list of Add/Del effects if isinstance(effect, UniversalEffect): effect_l += transform_universal_effects(lang, effect) continue # else if Add/Del effect, just instantiate condition and atom assert isinstance(effect, AddEffect) or isinstance(effect, DelEffect) card, syms, substs = _enumerate_instantiations(uni_eff.variables) if card == 0 : raise TransformationError("universal effect elimination", uni_eff, "No constants were defined!") cond_effects = [] for values in itertools.product(*substs) : subst = create_substitution(syms, values) cond_sub = term_substitution(lang, effect.condition, subst) atom_sub = term_substitution(lang, effect.atom, subst) if isinstance(effect, AddEffect) : ce = AddEffect(atom_sub, cond_sub) elif isinstance(effect, DelEffect) : ce = DelEffect(atom_sub, cond_sub) else : raise TransformationError("universal effect elimination", uni_eff, "Effect type can't be handled!") cond_effects.append(ce) effect_l = effect_l + cond_effects return effect_l
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)'
def generate_propositional_domain(nnodes, nedges, add_noop=False): lang = language(theories=[Theory.EQUALITY]) problem = create_fstrips_problem( domain_name='graph-traversal-strips', problem_name="graph-traversal-{}x{}".format(nnodes, nedges), language=lang) node_t = lang.sort('node') at = lang.predicate('at', node_t) adjacent = lang.predicate('adjacent', node_t, node_t) # Create the actions from_, to = [lang.variable(name, node_t) for name in ("from", "to")] problem.action(name='move', parameters=[from_, to], precondition=adjacent(from_, to) & at(from_), effects=[DelEffect(at(from_)), AddEffect(at(to))]) if add_noop: create_noop(problem) def node_name(i): return "n_{}".format(i) # Declare the constants: node_ids = list(range(0, nnodes)) nodes = [lang.constant(node_name(i), node_t) for i in node_ids] # Declare the adjacencies: adjacencies = random.sample(list(itertools.permutations(nodes, 2)), nedges) for n1, n2 in adjacencies: problem.init.add(adjacent, n1, n2) source_node = nodes[0] target_node = nodes[-1] problem.init.add(at, source_node) problem.goal = at(target_node) return problem
def test_complex_action_grounding(): problem = generate_strips_blocksworld_problem(nblocks=1) lang = problem.language handempty, clear, b1 = lang.get('handempty', 'clear', 'b1') problem.actions = OrderedDict() problem.goal = ~handempty() # Just to make the goal reachable x = lang.variable('x', 'object') ue = UniversalEffect([], effects=[AddEffect(clear(x)), DelEffect(handempty())]) action = problem.action('fake', [x], precondition=handempty(), effects=[ue]) op = ground_schema_into_plain_operator_from_grounding(action, (b1, )) assert len(op.effects) == 1 eff = op.effects[0] assert all(is_ground(sube.atom) for sube in eff.effects)
def process_effects(eff, action, lang, task_id=[ 0, ]): """ Elimates univeral effects by transforming to multiple conditional effects Arguments ========= lang: object of type FirstOrderLanguage eff: any effect type object task_id - Usage same as 'process_problem' method Returns ======= list: list of effects """ effect_l = [] # new list of effects if isinstance(eff, UniversalEffect) and (0 in task_id or 1 in task_id): for effect in eff.effects: effect.condition = process_formula(effect.condition, lang) # if Uni. Effect then transform to a list of Add/Del Effects if isinstance(effect, UniversalEffect): effect_l += process_effects(effect, action, lang) continue # else if Add/Del effect, just instantiate condition and atom assert isinstance(effect, AddEffect) or isinstance( effect, DelEffect) card, syms, substs = _enumerate_instantiations(eff.variables) if card == 0: raise TransformationError("universal effect elimination", eff, "No constants were defined!") cond_effects = [] for values in itertools.product(*substs): subst = create_substitution(syms, values) cond_sub = process_formula( term_substitution(lang, effect.condition, subst), lang) atom_sub = term_substitution(lang, effect.atom, subst) if isinstance(effect, AddEffect): ce = AddEffect(atom_sub, cond_sub) elif isinstance(effect, DelEffect): ce = DelEffect(atom_sub, cond_sub) else: raise TransformationError("universal effect elimination", eff, "Effect type can't be handled!") cond_effects.append(ce) effect_l += cond_effects elif isinstance( eff, FunctionalEffect) and (eff.lhs.symbol.symbol == 'total-cost') and (0 in task_id or 2 in task_id): action.cost = eff.rhs elif (isinstance(eff, AddEffect) or isinstance(eff, DelEffect)) and \ (0 in task_id or 1 in task_id) : eff.condition = process_formula(eff.condition, lang) effect_l.append(eff) else: effect_l.append(eff) return effect_l