def relativize_quantifiers(self, phi): """ forall x (P(x)) ---> forall x (exists cx (R[f](x,cx)) -> P(x)) exists x (P(x)) ---> exists x (exists cx (R[f](x,cx)) & P(x)) """ def gen_tot(t, r, s, connective): for x in s[:-1]: if x.subtrees: raise ValueError, "nonterminal quantified variable '%s'" % ( x, ) imp = self.construct_totality([x.root for x in s[:-1]]) T = type(t) return T(r, s[:-1] + [T(connective, [imp, s[-1]])]) def xform(t): r, s = t.root, t.subtrees if r == 'disable-relativization': return FolFormula.conjunction(s) elif r.kind == 'quantifier' and t.context_sign == '--': return None # skip relativization for this quantifier (disable-relativization) elif r.kind == 'quantifier' and (u'β' in s[0].root.literal or u'γ' in s[0].root.literal): return None elif r == FolFormula.FORALL and t.context_sign == '+': return gen_tot(t, r, s, FolFormula.IMPLIES) elif r == FolFormula.EXISTS and t.context_sign == '-': return gen_tot(t, r, s, FolFormula.AND) elif r in [FolFormula.FORALL, FolFormula.EXISTS ] and t.context_sign == '+-': raise NotImplementedError, "ambiguous context for quantifier: '%s'" % ( t, ) self._mark_context_sign(phi) return TreeTransform([xform], dir=TreeTransform.BOTTOM_UP).inplace(phi)
def __call__(self, text): t, = self.forestify(self.b(self.l(text))) t = TreeTransform( [functools.partial(AuxTransformers.unfold, symbols={';': 2})], dir=TreeTransform.BOTTOM_UP, recurse=True)(t) return t
def normalize(self): def transformer(self): if isinstance(self.root, Identifier) and \ isinstance(self.root.literal, type(self)) and \ not self.subtrees: return self.root.literal return TreeTransform([transformer])(self)
def _rename_terms_over(self, phi, variable): ns = AlphaRenaming.NS() new_names = BidirectionalDict( {FolFormula(variable): FolFormula(variable)}) def _scan(t): if t.root != '=': return type(t)(t.root, [_collect(x) or x for x in t.subtrees]) def _collect(t): if t.root.kind == 'function': try: t_prime = new_names.get_backwards(t) return t_prime except KeyError: if t.subtrees and all( new_names.has_key(x) for x in t.subtrees): c = FolFormula( Identifier(u"β%d" % len(new_names), 'variable', ns=ns)) new_names[c] = t return c return TreeTransform([_scan], dir=TreeTransform.BOTTOM_UP)(phi), new_names
def __init__(self, naming_convention=NamingConvention()): _ = AuxTransformers fold_f = TreeTransform([_.fold], dir=TreeTransform.BOTTOM_UP) #fold_f.IS_DESCENDING = True self.naming = naming_convention regroup_f = TreeTransform([partial(_.regroup, head='forall', tag='')], dir=TreeTransform.BOTTOM_UP) synonyms = { FolFormula.FORALL: Identifier('forall', 'quantifier'), FolFormula.EXISTS: Identifier('exists', 'quantifier'), FolFormula.AND: Identifier('and', 'connective'), FolFormula.OR: Identifier('or', 'connective'), FolFormula.IFF: Identifier('iff', 'connective'), FolFormula.IMPLIES: Identifier('=>', 'connective'), FolFormula.NOT: Identifier('not', 'connective'), True: 'true', False: 'false' } synonyms_f = TreeSubstitution(synonyms) #e = Expansion() # must get rid of it; only needed for the parser L = DeltaReduction.Transformer._mkparser( ) # suggested optimization: use singleton for parser. Also, only parse macros once macros = [ "x != y := ~(x=y)", "forall x (psi) := [forall]([]([](x,V)), psi)", "exists x (psi) := [exists]([]([](x,V)), psi)" ] macros_f = DeltaReduction(dir=TreeTransform.BOTTOM_UP) macros_f.IS_DESCENDING = False macros_f.transformers += \ [DeltaReduction.Transformer(macros_f, L(m)) for m in macros] from adt.tree.transform.apply import ApplyTo # @Reimport escape_f = ApplyTo(nodes=naming_convention.escape_safe).inplace self.phases = ProcessingPhases([(macros_f, "Operators/quantifiers"), (SExpression.reconstruct, "S-expression"), (fold_f, "Fold"), (synonyms_f, "Rename keywords"), (regroup_f, "Regroup"), (escape_f, "Escape identifiers")]) self.preface = ''
def __call__(self, t): if t.root == self.head: if not self.params and not self.body.subtrees: # e.g. "r := q" return TreeTransform.Scalar(self.body.root) elif len(t.subtrees) == len( self.params): # e.g. "r := p(a,b)" or "r(a) := p(a,b)" tun = self.o.tuning subst = dict( map(self._single_out, zip(self.params, t.subtrees))) body = tun.local_.before(self.body) return tun.local_.after(TreeSubstitution(subst)(body))
def e_absapp(self, expr): is_value = self.is_value beta_reduce = self.beta_reduce class Transformer(object): def __init__(self): self.stop = False def __call__(self, t): if not self.stop and t.root == 'App' and \ all(is_value(x) for x in t.subtrees): assert len(t.subtrees) == 2 self.stop = True func, arg = t.subtrees return beta_reduce(func, arg) return TreeTransform([Transformer()])(expr)
def replace_equalities_with_atomic(self, phi, quantifier_type): '''f(x) = y ---> R[f](x, y) y = f(x) ---> R[f](x, y) f(x) = g(y) ---> forall z (R[f](x,z) -> R[g](y,z)) / exists z (R[f](x,z) & R[g](y,z)) The quantifier is determined according to quantifier_type (either FolFormula.FORALL or FolFormula.EXISTS) when the atomic formula occurs in a positive context. In a negative context, the other quantifier is used. ''' EQ = FolWithEquality.eq def xform(t): if not self.unnest.is_fine(t): raise ValueError, "nested term not allowed; in '%s'" % t r, s = t.root, t.subtrees s = sorted(s, key=lambda x: len(x.subtrees), reverse=True) if r == EQ and len(s) == 2 and s[0].root in self.funcs: if s[1].root in self.funcs: _ = FolFormula gamma = Identifier(u'γ', 'variable', ns=AlphaRenaming.NS()) if (quantifier_type, t.context_sign) in [(_.FORALL, "+"), (_.EXISTS, "-")]: quantifier, connective = _.FORALL, _.IMPLIES elif (quantifier_type, t.context_sign) in [(_.FORALL, "-"), (_.EXISTS, "+") ]: quantifier, connective = _.EXISTS, _.AND else: raise ValueError, "invalid quantifier context %s" % ( (quantifier_type, t.context_sign), ) return _(quantifier, [ _(gamma), _(connective, [ _(self._rel(s[0].root), s[0].subtrees + [_(gamma)]), _(self._rel(s[1].root), s[1].subtrees + [_(gamma)]) ]) ]) else: return FolFormula(self._rel(s[0].root), s[0].subtrees + s[1:]) self._mark_context_sign(phi) return TreeTransform([xform]).inplace(phi)
def __call__(self, tree): w = self.replace_what if isinstance(w, type(tree)): compare_with = w else: compare_with = type(tree)(w) if tree.root == w and isinstance(self.replace_with, list): return type(tree)([], self.replace_with) if tree.root == w and not isinstance(self.replace_with, type(tree)): return TreeTransform.Scalar(self.replace_with) elif tree == compare_with: if isinstance(self.replace_with, list): return type(tree)([], self.replace_with) elif isinstance(self.replace_with, type(tree)): return self.replace_with else: return type(tree)(self.replace_with)
def to_quantified(cls, phi, quantifier_context): ''' @param quantifier_context: either FolFormula.FORALL or FolFormula.EXISTS ''' def xform(t): r, s = t.root, t.subtrees if r == cls.LET: _ = FolFormula if t.quantifier_context == _.FORALL: return _(_.FORALL, [s[0].subtrees[0], _(_.IMPLIES, s)]) elif t.quantifier_context == _.EXISTS: return _(_.EXISTS, [s[0].subtrees[0], _(_.AND, s)]) else: raise ValueError, "invalid quantifier context '%s' for '%s'" % ( t.quantifier_context, t) cls._mark_quantifier_context(phi, quantifier_context) return TreeTransform([xform])(phi)
def __call__(self, formula): q = [] def pull_out(t, op_prefix=(), q=q): """ Extracts quantifiers nested in (sub-)formula t. """ r, s = t.root, t.subtrees if r in self.quantifiers: q += [self._apply_ops(op_prefix, type(t)(r, s[:-1]))] if r in self.instructions: ops = self.instructions[r] for x, op in zip(s, ops): pull_out(x, op_prefix + (op,)) def xform(t): r, s = t.root, t.subtrees if r in self.quantifiers: return s[-1] pull_out(formula) phi = TreeTransform([xform], recurse=True)(formula) for prefix in reversed(q): prefix.subtrees += [phi] phi = prefix return phi
def simplify(self, t): def transform(t): r, arity, s = t.root, len(t.subtrees), t.subtrees h = None if r == 'S' and arity == 1: h = s[0] #elif r == 'id' and arity == 1: # h = s[0] elif r == 'Abs' and arity == 3: h = type(t)(r, s[1:]) elif r == 'S' and arity == 3 and s[0].root == '(' and s[ 2].root == ')': h = s[1] elif isinstance(r, Tagged) and hasattr(r, 'token'): h = type(t)(r.token) if h is not None: return recurse(h) recurse = TreeTransform([transform]) return recurse(t)
def inspect_formula(self, phi, ctx): '''Collects constants occurring in assertions.''' # TODO: remove 'used_fragment', take all the functions ever s = ctx.signature #.used_fragment([phi]) self.constants = [ c for c, _ in s.funcs if s.sorts.is_const(c, of_sort="V") ] self.funcs = [ c for c, a in s.funcs if a == 1 and s.sorts.returns(c, "V") ] #self.rel_funcs = self.funcs #self.rel_funcs = [c for c in self.funcs if (c,1) in s.used_fragment([phi]).funcs or c in ["k0", "km0"]] _ = Tree #rel_funcs = _('', [_('k10', [_('k20'), _('km20')]), # _('km10', [_('k20'), _('km20')]) # ] + [_(x) for x in ["f", "g", "l0", "k0", "km0", "k20", "km20"]]) rel_funcs = _('', [ _(x) for x in ["f", "g", "l0", "k0", "km0", "k10", "km10", "k20", "km20", "en0"] ]) def xform(t): r, s = t.root, t.subtrees if r != '': f = [c for c in self.funcs if c.literal == r] if f: new_r = f[0] else: return Tree('') else: new_r = r return Tree(new_r, [x for x in s if x.root != '']) self.rel_funcs = TreeTransform([xform], dir=TreeTransform.BOTTOM_UP)(rel_funcs) #[c for c in self.funcs if c in ["f", "g", "l0", "k0", "km0", "k10", "km10", "k20", "km20", "k2k10", "km2k10", "k2km10", "km2km10"]] self.declare_relations(ctx.signature) self.inplace(phi)
def __call__(self, phi, ctx=None): occurrences = ListWithAdd() self._collect_ternies(phi, occurrences) def xform(phi): _ = FolFormula for (atom, ter) in occurrences: if phi is atom: if len(ter.subtrees) != 3: raise ValueError, "invalid ternary expression: '%s'" % ter cond, then_, else_ = ter.subtrees phi = _(self.Signature.ite, [ cond, self._choose(atom, ter, then_), self._choose(atom, ter, else_) ]) return self(phi) if occurrences: return TreeTransform([xform])(phi) else: return phi
def _collect(self, t, parts_f): parts = [] xform = TreeTransform([partial(parts_f, collect=parts)], dir=TreeTransform.BOTTOM_UP) parts += [xform(t)] return parts
def __call__(self, phi, ctx=None): return TreeTransform([self.xform], dir=TreeTransform.BOTTOM_UP)(phi)
astf = fe("k:=i.n ; i.n:=j; j:=i; i:=k", 'wp ') astf = fe( "( if $C( i )$ then ( t := i.n ; j.n := null ; j.n := t ) else j := i ) ; i := i.n", 'wp ') astf.subtrees += [FolFormula.promote("Q")] def compose_xform(t): import copy r, s = t.root, t.subtrees a = len(s) if r == 'wp ;' and a == 3: c1 = copy.deepcopy(s[0]) c2 = copy.deepcopy(s[1]) c2.subtrees += [s[2]] c1.subtrees += [c2] return c1 if r == 'wp if' and a == 4: ct, ce = copy.deepcopy(s[1]), copy.deepcopy(s[2]) ct.subtrees += [s[3]] ce.subtrees += [s[3]] return type(t)(r, [s[0], ct, ce]) print astf xf = TreeTransform([compose_xform], dir=TreeTransform.TOP_DOWN, recurse=True) xf.IS_DESCENDING = True print xf(astf)
def unprotect(self): return TreeTransform([self._xform_unprotect])
#print unicode(FOL_GRAMMAR) for rule in FOL_GRAMMAR.rules: if rule.head == 'fml': print rule #raise SystemExit class TX(ParserXforms): PRIM = {'forall': FolFormula.FORALL, '|': FolFormula.OR, '&': FolFormula.AND, '~': FolFormula.NOT, '->': FolFormula.IMPLIES, '<->': FolFormula.IFF} for v in PRIM.values(): PRIM[v.literal] = v def singl(self, t): return FolFormula(Identifier((t.subtrees[0] if t.subtrees else t).root.token.value, '?')) def qua(self, t): return FolFormula(self.PRIM[t.subtrees[0].root.token.value], [self.singl(t.subtrees[1]), t.subtrees[3]]) def cal(self, t): return FolFormula(self.singl(t).root, self.split(t.subtrees[2], ('term*', 'term+', ','))) def bin(self, t): return FolFormula(self.PRIM[t.subtrees[1].root.token.value], [t.subtrees[0], t.subtrees[2]]) def un(self, t): return FolFormula(self.PRIM[t.subtrees[0].root.token.value], [t.subtrees[1]]) def sam(self, t): return t.subtrees[0] def sam1(self, t): return t.subtrees[1] lG = set((Tagged(tok).with_(annotation='sam'), tok) for tok in tokens) ast = Earley(FOL_GRAMMAR.rules, lG, tokens, lexer=lambda x: x) PrintTrees(ast) assert len(ast) == 1 ast = FolFormula.reconstruct(ast[0]) print ast phi = TreeTransform([TX()], dir=TreeTransform.BOTTOM_UP)(ast) print phi
def _choose(self, atom, point_of_choice, choice): def xform(phi): if phi is point_of_choice: return choice return TreeTransform([xform])(atom)
def __call__(self, phi, constants, quantifier_context): phi = TreeTransform([self._xform], dir=TreeTransform.BOTTOM_UP)(phi) return self._xform_toplevel(phi, constants, quantifier_context)