def successors(self, node): index = build_index(node.state) for o in self.operators: for m in pattern_match(o.conditions, index): dels = frozenset(execute_functions(e, m) if is_functional_term(e) else subst(m, e) for e in o.del_effects) adds = frozenset(execute_functions(e, m) if is_functional_term(e) else subst(m, e) for e in o.add_effects) new_state = node.state.difference(dels).union(adds) yield Node(new_state, node, (o, m), node.cost() + o.cost)
def replace_constants(ele, sub): """ Return the element with all functionals replaced, at the top level. Builds up sub along the way. """ if is_variable(ele): return ele if is_functional_term(ele): return ele if isinstance(ele, tuple) and ele[0] == 'not': return ele if isinstance(ele, tuple): new_ele = (ele[0],) + tuple(replace_constants(e, sub) for e in ele[1:]) return new_ele sk = gen_skolem() sub[sk] = ele return sk
def predecessors(self, node): for o in self.operators: # Rename variables to prevent collisions. # TODO figure out how to reverse this for printing plans o = o.standardized_copy() # Convert constants into equality constraints, so that goals with # constants can be matched in reverse. constant_mapping = {} var_state = frozenset( replace_constants(e, constant_mapping) for e in node.state) equality_constraints = set( (eq, e, constant_mapping[e]) for e in constant_mapping) # Generate constraints that prevent operator inconsistency # prevent delete effects that match positive goals del_constraints = generate_del_constraints(o.del_effects, [ e for e in var_state if not is_functional_term(e) and not is_negated_term(e) ]) # prevent positive effects that produce negated goals add_constraints = generate_add_constraints(o.add_effects, [ e[1] for e in var_state if not is_functional_term(e) and is_negated_term(e) ]) # TODO figure out how to add any applicable constraints to var # state in order to prevent variables bindings that are # inconsistent this requires comparing the vars in the state with # those in the constraints and only adds constraints that have var # subsets. var_state = var_state.union(equality_constraints) for m in pattern_match(var_state, build_index(o.add_effects), partial=True): new_state = frozenset(subst(m, e) for e in var_state) new_state = new_state.difference(o.add_effects) new_state = new_state.union(o.conditions) cons = set( subst(m, e) for e in new_state if is_functional_term(e)) cons.update(subst(m, e) for e in del_constraints) cons.update(subst(m, e) for e in add_constraints) new_state = frozenset(e for e in new_state if not is_functional_term(e)) # print("Constraints", cons) # Check equality constraints that disagree invalid = False assignment_mapping = {} for c in cons: if is_var_assignment(c): var = c[1] const = c[2] if var in assignment_mapping: invalid = True break assignment_mapping[var] = const if invalid: continue # substitute assignment equality constraints # back in, i.e., replace all var with constants. cons = set( subst(assignment_mapping, e) for e in cons if not is_var_assignment(e)) new_state = frozenset( subst(assignment_mapping, e) for e in new_state) # Check for any other functional constraints. # Terminate branches with false functions # Eliminate constraints that are satisfied new_cons = set() for c in cons: try: if execute_functions(c, m) is False: invalid = True break except TypeError: new_cons.add(c) if invalid: continue # REACHABILITY ANALYSIS, check if there are any # new_state elements that cannot be generated by an # operator and do not exist in the state for e in new_state: if is_negated_term(e): continue temp_m = {} new_e = replace_constants(e, temp_m) p = set((eq, e, temp_m[e]) for e in temp_m) p.add(new_e) try: next(pattern_match(p, self.achievable, partial=True)) except Exception: invalid = True break if invalid: continue # Add any surviving constraints back into the state new_state = new_state.union(new_cons) yield GoalNode(new_state, node, (o, m), node.cost() + o.cost)
def predecessors(self, node): # print() # pprint(node.state) # if node.parent is not None: # return for o in self.operators: o = o.standardized_copy() # convert constants into equality constraints. constant_mapping = {} var_state = frozenset(replace_constants(e, constant_mapping) for e in node.state) equality_constraints = set((eq, e, constant_mapping[e]) for e in constant_mapping) var_state = var_state.union(equality_constraints) # print() # pprint(var_state) # print(o) for m in pattern_match(var_state, build_index(o.add_effects), partial=True): # pprint(m) new_state = frozenset(subst(m, e) for e in var_state) new_state = new_state.difference(o.add_effects) new_state = new_state.union(o.conditions) cons = set(subst(m, e) for e in new_state if is_functional_term(e)) new_state = frozenset(e for e in new_state if not is_functional_term(e)) # print("Constraints", cons) # Check equality constraints that disagree invalid = False assignment_mapping = {} for c in cons: if is_var_assignment(c): var = c[1] const = c[2] if var in assignment_mapping: invalid = True break assignment_mapping[var] = const if invalid: continue # substitute assignment equality constraints # back in, i.e., replace all var with constants. cons = set(subst(assignment_mapping, e) for e in cons if not is_var_assignment(e)) new_state = frozenset(subst(assignment_mapping, e) for e in new_state) # check for any other functional constraints. new_cons = set() for c in cons: try: if execute_functions(c, m) is False: invalid = True break except TypeError: new_cons.add(c) if invalid: continue # REACHABILITY ANALYSIS, check if there are any # new_state elements that cannot be generated by an # operator and do not exist in the state # print() # pprint(new_state) # print(build_index(self.achievable)) for e in new_state: if is_negated_term(e): continue temp_m = {} new_e = replace_constants(e, temp_m) p = set((eq, e, temp_m[e]) for e in temp_m) p.add(new_e) try: next(pattern_match(p, self.achievable, partial=True)) except Exception as e: # print(e) # print("ACHIEVABLE") # pprint(self.achievable) # print("HUH?", p) # print('OP', o, m) # print(new_state) invalid = True break if invalid: continue new_state = new_state.union(new_cons) # pprint(new_state) yield GoalNode(new_state, node, (o, m), node.cost() + o.cost)