def contains_variables(literal): for ele in literal: if is_variable(ele): return True elif isinstance(ele, tuple) and contains_variables(ele): return True return False
def successors(self, node): h = node.state args, pos, pos_mapping, gensym = node.extra print("H", h) # remove literals for literal in h: removable = True for ele in literal[1:]: if not is_variable(ele): removable = False break if (ele in args or count_occurances(ele, h) > 1): removable = False break if removable: new_h = frozenset(x for x in h if x != literal) # yield Node(new_h, node, ('remove', literal), node.cost()+1, # node.extra) # replace constants with variables. for literal in h: for new_l in get_variablizations(literal, gensym): new_h = frozenset([x if x != literal else new_l for x in h]) yield Node(new_h, node, ('variablize', literal, new_l), node.cost() + 1, node.extra)
def remove_vars(literal): """ This removes all variables by putting XXX at the front of the string, so it cannot be unified anymore. """ return tuple('XXX' + ele if is_variable(ele) else remove_vars(ele) if isinstance(ele, tuple) else ele for ele in literal)
def generalize_literal(literal, gensym): """ This takes a literal and returns the most general version of it possible. i.e., a version that has all the values replaced with new veriables. """ return (literal[0],) + tuple(ele if is_variable(ele) else # '?gen%s' % hash(ele) gensym() for ele in literal[1:])
def get_variablizations(literal, gensym): for i, ele in enumerate(literal[1:]): if isinstance(ele, tuple): for inner in get_variablizations(ele, gensym): yield tuple([literal[0]] + [ inner if j == i else iele for j, iele in enumerate(literal[1:]) ]) elif not is_variable(ele): yield tuple([literal[0]] + [ gensym() if j == i else iele for j, iele in enumerate(literal[1:]) ])
def count_elements(x, var_counts): """ Counts the number of constants and keeps track of variable occurnaces. """ if x is None: return 0 c = 0 if isinstance(x, tuple): c = sum([count_elements(ele, var_counts) for ele in x]) elif is_variable(x): if x not in var_counts: var_counts[x] = 0 var_counts[x] += 1 else: c = 1 return c
def get_variablizations(literal): """ Takes a literal and returns all possible variablizations of it. Currently, this replaces constants only. Also, it replaces them with a variable that is generated based on the hash of the constant, so that similar constants map to the same variable. """ if isinstance(literal, tuple): head = literal[0] possible_bodies = [[e] + list(get_variablizations(e)) for e in literal[1:]] for body in product(*possible_bodies): new = (head,) + tuple(body) if new != literal: yield new elif not is_variable(literal): yield '?gen%s' % repr(literal)
def successors(self, node): h = node.state # print("EXPANDING H", h) args, constraints, pset, neg, neg_mapping, gensym = node.extra all_args = set(s for x in h.union(constraints) for s in extract_strings(x) if is_variable(s)) if len(pset) == 0: return p, pm = choice(pset) p_index = build_index(p) operator = Operator(tuple(('Rule', ) + tuple(all_args)), h.union(constraints), []) # operator = Operator(tuple(('Rule',) + args), h, []) found = False for m in operator.match(p_index, initial_mapping=pm): reverse_m = {m[a]: a for a in m} pos_partial = set([rename(reverse_m, x) for x in p]) found = True break if not found: return n_index = build_index(neg) found = False for nm in operator.match(n_index, initial_mapping=neg_mapping): # print(nm) reverse_nm = {nm[a]: a for a in nm} neg_partial = set([rename(reverse_nm, x) for x in neg]) found = True break if not found: return unique_pos = pos_partial - neg_partial unique_neg = neg_partial - pos_partial # print("UNIQUE POS", unique_pos) # print("UNIQUE NEG", unique_neg) # Yield all minimum specializations of current vars for a in m: # TODO make sure m[a] is a minimum specialization sub_m = {a: m[a]} new_h = frozenset([subst(sub_m, ele) for ele in h]) # print("SPECIALIZATION", new_h, sub_m) # print() yield Node(new_h, node, ('specializing', (a, m[a])), node.cost() + 1, node.extra) # Add Negations for all neg specializations # for a in nm: # sub_nm = {a: nm[a]} # new_nh = set() # for ele in h: # new = subst(sub_nm, ele) # if new != ele and new not in h: # new_nh.add(('not', new)) # new_h = h.union(new_nh) # print("NEGATION SPECIALIZATION", new_nh) # yield Node(new_h, node, ('negation specialization', (a, nm[a])), # node.cost()+1, node.extra) # if current vars then add all relations that include current vars if len(all_args) > 0: added = set() for literal in unique_pos: if literal in h or literal in constraints: continue args = set(s for s in extract_strings(literal) if is_variable(s)) if len(args.intersection(all_args)) > 0: key = (literal[0], ) + tuple( ele if is_variable(ele) else '?' for ele in literal[1:]) if key in added: continue added.add(key) literal = generalize_literal(literal, gensym) new_h = h.union(frozenset([literal])) # print("ADD CURRENT", new_h) # print() yield Node(new_h, node, ('adding current', literal), node.cost() + 1, node.extra) else: added = set() for literal in unique_pos: if literal in h or literal in constraints: continue if literal[0] in added: continue added.add(literal[0]) literal = generalize_literal(literal, gensym) new_h = h.union(frozenset([literal])) # print("ADD NEW", new_h) # print() yield Node(new_h, node, ('adding', literal), node.cost() + 1, node.extra)
def generalize_literal(literal, gensym): return (literal[0], ) + tuple(ele if is_variable(ele) else # '?gen%s' % hash(ele) gensym() for ele in literal[1:])
def remove_vars(literal): return tuple('XXX' + ele if is_variable(ele) else remove_vars(ele) if isinstance(ele, tuple) else ele for ele in literal)