def goal_test(self, node, goal): index = build_index(node.state) for m in pattern_match(goal.state, index, {}): for v in m: goal.action[1][v] = m[v] return True return False
def generate_del_constraints(del_effects, positive_goals): # print(del_effects, list(positive_goals)) return [ or_constraints([(ne, match[v], v) for v in match]) for e in positive_goals for match in pattern_match([e], build_index(del_effects), {}) ]
def test_partial_match(): kb = [('Number', '5')] q = [ ('Number', '5'), # ('Number', '?y') ] print(list(pattern_match(q, build_index(kb), partial=True)))
def __init__(self, state, goals, operators): state = frozenset(state) self.operators = operators self.goal = GoalNode(frozenset(goals)) self.initial = Node(state, parent=None, action=None, node_cost=0) achievable = set(e for o in self.operators for e in o.add_effects) achievable.update(e for e in state) self.achievable = build_index(achievable)
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)
conditions = set(subst(sub, c) for c in self.conditions) effects = set(subst(sub, e) for e in self.effects) return Operator(self.name, conditions, effects, self.cost, reverse_sub) def __str__(self): s = "Name: %s" % self.name + "\n" s += "Cost: %0.2f" % self.cost + "\n" s += "Conditions: %s" % self.conditions + "\n" s += "Effects: %s" % self.effects + "\n" return s def __repr__(self): return str(self.name) if __name__ == "__main__": from py_plan.pattern_matching import build_index kb = [('A'), ('B'), ('C')] q = [('A'), ('B')] index = build_index(kb) o = Operator("test", q, []) print(o) for m in o.match(index): print("MATCH FOUND", m)
def generate_add_constraints(add_effects, negative_goals): return [ or_constraints([(ne, match[v], v) for v in match]) for e in negative_goals for match in pattern_match([e], build_index(add_effects), {}) ]
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 goal_test(self, node, goal): index = build_index(node.state) for m in pattern_match(goal.state, index, {}): return True return False
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)