def mksymbol(literal): if literal == 'true': return True if literal == 'false': return False try: return signature_vars[literal] except KeyError: return Identifier(literal, '?')
class MainLoop( collections.namedtuple("MainLoop", "prologue cond body epilogue")): SEMI = Identifier(";", '?') SKIP = Identifier("skip", '?') BAD = "~ite(cond, wp_ae(loopBody,true), wp_ae(epilogue, post))" @classmethod def factor_loop(cls, program): stmts = program.split(";") for i, stmt in enumerate(stmts): if stmt.root == "while": cond, _, body = stmt.subtrees return cls(prologue=stmts[:i], cond=cond, body=body, epilogue=stmts[i + 1:]) return None @classmethod def locate_loop(cls, expansion): [program] = expansion("program") if program.subtrees: l = cls.factor_loop(program) if l: return l [cond] = expansion("cond") [body] = expansion("loopBody") return cls(prologue=[], cond=cond, body=body, epilogue=[]) def redefine(self, synopsis): """ Defines macros 'cond', 'loopBody', 'epilogue', and 'bad' in the environment. """ stmts = lambda x: FolFormula.join(self.SEMI, x, self.SKIP) delta = synopsis.expansion.delta delta.transformers += [ DeltaReduction.Transformer(delta, name, params=[], body=expr) for name, expr in [("cond", self.cond), ( "loopBody", self.body), ("epilogue", stmts(self.epilogue))] ] if not any( getattr(t, 'head', None) == "bad" for t in delta.transformers): bad = synopsis.expansion.parser * self.BAD delta.transformers += [ DeltaReduction.Transformer(delta, "bad", params=[], body=bad) ]
class FolRegister(object): UNDEF = Identifier("?", 'predicate') def __init__(self, subset_of_symbols): self.symbols = subset_of_symbols def blur(self, phi): reg = self s = self.symbols class FormulaWalk(RichTreeWalk.Visitor): def enter(self, subtree, prune=lambda: None): r = subtree.root if isinstance(r, Identifier) and \ r.kind in ['function', 'predicate'] and r not in reg.symbols: prune() return reg.UNDEF else: return r def join(self, node, prefix, infix, postfix): known = [a for a in infix if a.root != reg.UNDEF] if len(known) == len(infix): return type(node)(prefix, known) elif prefix == FolFormula.AND and len(known) == 1: return known[0] else: return type(node)(reg.UNDEF) def done(self, root, final): return final if isinstance(phi, FolFormula): return RichTreeWalk(FormulaWalk())(phi) elif isinstance(phi, FolTheory): sig = self.blur(phi.signature) t = (y for y in (self.blur(x) for x in phi) if y.root != self.UNDEF) return FolTheory(t).with_signature(sig) elif isinstance(phi, FolManySortSignature): return FolManySortSignature([(f, a) for f, a in phi.funcs if f in s], [(p, a) for p, a in phi.preds if p in s], self.blur(phi.sorts)) elif isinstance(phi, FolSignature): return FolSignature([(f, a) for f, a in phi.funcs if f in s], [(p, a) for p, a in phi.preds if p in s]) elif isinstance(phi, FolSorts): return FolSorts(self.blur(phi.sorts)) elif isinstance(phi, FolStructure): return FolStructure(domain=phi.domain, interpretation=self.blur(phi.interpretation)) elif isinstance(phi, dict): return dict( (sym, v) for sym, v in phi.iteritems() if sym in self.symbols) else: raise TypeError, phi
def _past_tense(consts, type_decls): consts0 = [] for p in consts: p0 = Identifier('%s0' % p, p.kind) type_decls.sorts[p0] = type_decls.sorts[p][:] consts0 += [p0] return consts0
def _get_free_var(self, var): i = get_var_index(var) if i in self.vars: return self.vars[i].identifier else: self.vars[i] = v = self.Var(Identifier("$%d" % i, 'variable'), var.sort()) return v.identifier
def signature(self): """ Extracts a first-order sorted signature describing the type of the structure. """ sorts = FolSorts() for name, (args, ret, _) in self.funcs.iteritems(): # ~ symbols with '!' are reserved for compiler-generated aux if not "!" in name: nameid = Identifier( name, '?') # 'kind' will be filled by FolManySortSignature argtypes = [ Identifier(a.subtrees[0].root, 'sort') for a in args ] rettype = Identifier(ret.root, 'sort') if rettype == 'bool': rettype = '' sorts[nameid] = [FolSorts.FunctionType(argtypes, rettype)] return FolManySortSignature.from_sorts(sorts)
def generate_order_and_sorting_properties(syn, vocab): sorted_templ = FolScheme(syn * "sorted(ivlco([?u],[?v],n*))") null = Identifier('null', 'function') a = AbstractionProperties.from_named_formulas( [('sorted%s%s' % (u, v), sorted_templ(u, v)) for u in vocab.consts for v in [null]], vocab) #a.props += generate_binary_properties_from_template\ # (FolScheme(syn * "R([?u],[?v])"), vocab.consts) return a
def lookup(self, literal): for sig in self.signatures: for symbol in sig.itersymbols(): if symbol == literal or \ isinstance(symbol, Identifier) and \ symbol.mnemonic == literal: return symbol else: return Identifier.promote(literal)
def generate_named_properties(name_property_list, type_decls): named_axioms = [] for name, property_formula in name_property_list: p = Identifier(name, 'predicate') type_decls.sorts[p] = [((), '')] axiom = FolFormula(FolFormula.IFF, [FolFormula(p), property_formula]) named_axioms += [(p, axiom)] return named_axioms
def escaping(t): if t not in FolFormula.INFIXES and t not in [ FolFormula.FORALL, FolFormula.EXISTS, FolFormula.NOT ]: if not (isinstance(t, Identifier) and isinstance(t.literal, (int, float))): u = unicode(t) if not idre.match(u): t = Identifier(u'[%s]' % u, '?') return t
def gen_uniq(self, sym): hist = self.histogram g = self.assigned.get(sym) if g is not None: return g literal = sym.literal hist[literal] = i = hist[literal] + 1 ssc = '$%s' % i #ssc = self.num_sscript(i) self.assigned[sym] = g = Identifier(literal + ssc, sym.kind) return g
def _quantify_forall(self, t): vars0 = [ self.Var(Identifier(t.var_name(i), 'variable'), None) for i in reversed(xrange(t.num_vars())) ] body = self.with_some_vars(vars0)(t.body()) phi = body for v in vars0: phi = FolFormula(FolFormula.FORALL, [FolFormula(v.identifier), phi]) return phi
class FolFormula(Tree): Identifier = Identifier AND = Identifier(u"∧", 'connective') OR = Identifier(u"∨", 'connective') NOT = Identifier(u"¬", 'connective') IMPLIES = Identifier(u"➝", 'connective') IFF = Identifier(u"↔", 'connective') FORALL = Identifier(u"∀", 'quantifier') EXISTS = Identifier(u"∃", 'quantifier') TRUE = Identifier(True, 'predicate') FALSE = Identifier(False, 'predicate') INFIXES = [ IMPLIES, IFF, AND, OR, "=", "<", "<=", ">", ">=", "!=", u"≠", u"≤", u"≥", u"∈", u"∉", "+", "-", "*", "/", "^" ] LEFT = "LEFT" RIGHT = "RIGHT" ASSOC = "ASSOC" PREC = { AND: (1, ASSOC), OR: (2, ASSOC), IMPLIES: (3, RIGHT), IFF: (3, RIGHT) } def __unicode__(self): if self.root in [self.FORALL, self.EXISTS] and len(self.subtrees) == 2: return u"%s%r (%r)" % ((self.root, ) + tuple(self.subtrees)) elif self.root in self.INFIXES and len(self.subtrees) == 2: p = lambda x, pos, r=self.root: self._parenthesize(r, x, pos) return u"%s %s %s" % (p(self.subtrees[0], self.LEFT), self.root, p(self.subtrees[1], self.RIGHT)) elif isinstance(self.root, RepresentationForm): return self.root.repr(self.subtrees) elif isinstance(self.root, Identifier): if len(self.subtrees) == 0: return unicode(self.root) else: subreprs = u", ".join( ` x ` for x in self.subtrees) return u"%s(%s)" % (self.root, subreprs)
def xform(self, phi): if phi.root == 'fresh' and phi.subtrees: symbols = phi.subtrees[:-1] if any(x.subtrees for x in symbols): raise ValueError, "invalid fresh symbols '%s'" % symbols symbols = [x.root for x in symbols] phi = phi.subtrees[-1] newscope = AlphaRenaming.NS() return TreeNodeRename({ k: Identifier(k.literal, k.kind, k.mnemonic, ns=newscope) for k in symbols })(phi)
def _ident(self, tok, arity): """ Creates an identifier from a given token. """ if isinstance(tok, Identifier): return tok elif any(isinstance(tok, t) for t in self.native_types): return Identifier(tok, 'function') try: return self.OPERATOR_MAP[tok] except KeyError: try: return self.OPERATOR_MAP[(tok, arity)] except KeyError: return self.lookup(tok)
def display_invariant(inv, abs_props): z3g = Z3Gate() fol_inv = z3g.formula_back(inv) bnd = [t.subtrees[0] for t in fol_inv.nodes if t.root.kind == 'quantifier'] subst = { v: FolFormula(Identifier("x%d" % i, 'variable')) for i, v in enumerate(bnd) } subst.update(abs_props.defs) fol_inv = FolSubstitution(subst)(fol_inv) print " - " * 20 print fol_inv print " - " * 20
def __call__(self, t): if is_var(t): return FolFormula(self._get_free_var(t)) elif is_true(t) or is_false(t): return FolFormula(is_true(t)) elif is_const(t): kind = 'predicate' if is_bool(t) else 'function' return FolFormula(Identifier(unicode(t), kind)) elif is_quantifier(t) and t.is_forall(): return self._quantify_forall(t) elif is_app(t): r = t.decl() for k, v in self.o.map_ops.iteritems(): if is_app_of(t, k): r = v break else: r = Identifier(unicode(r), '?') if callable(r): return r([self(x) for x in t.children()]) else: return FolFormula(r, [self(x) for x in t.children()]) else: raise NotImplementedError
def __call__(self, z3_elements): sorts = FolSorts() decls = {} for z3_symbol in z3_elements: idf = Identifier(z3_symbol.name(), self._get_kind(z3_symbol)) decls[idf] = z3_symbol if is_const(z3_symbol): sorts[idf] = FolSorts.FunctionType((), z3_symbol.sort()) elif is_func_decl(z3_symbol): z3_domains = [ z3_symbol.domain(i) for i in xrange(z3_symbol.arity()) ] z3_range = z3_symbol.range() sorts[idf] = FolSorts.FunctionType(tuple(z3_domains), z3_range) sigma = FolManySortSignature.from_sorts(sorts) sigma.z3_decls = decls return sigma
class Signature: eq = Identifier('=', 'predicate') neq = Identifier(u'≠', 'predicate') formal = FolSignature([], [(eq, 2), (neq, 2)])
def p_tagged_leaf(self, p): """atom : TAG IDENTIFIER | TAG ESCAPED_SYMBOL """ p[0] = Tree(Identifier.promote(p[2], kind=p[1]))
class _: u = Identifier('u', 'function') v = Identifier('v', 'function') w = Identifier('w', 'function') R = Identifier('R', 'predicate') sorts = FolSorts({u: u'→V', v: u'→V', w: u'→V', R: u'V×V→'})
def prime(self): prime = lambda x: Identifier("%s'" % x.literal, x.kind) vocab_prime = TwoVocabulary() vocab_prime.locals = [(x, prime(x)) for _, x in self.locals] return vocab_prime
def p_tagged_func_leaf(self, p): """atom : FUNCTION_TAG IDENTIFIER | FUNCTION_TAG ESCAPED_SYMBOL """ p[0] = Tree(Identifier.promote(p[2], kind='function'))
def generate_gamma(syn, preds, decls): dtca = Identifier('dtca', '?') starred = [z for z in preds if '*' in z.literal] gamma = FolFormula.conjunction( [FolFormula(dtca, [FolFormula(z)]) for z in starred]) return generate_z3_condition(gamma, syn, decls)
def unescape_identifier(s): return Identifier(self.naming.unescape(s.literal), s.kind, s.ns)
if y.root != self.UNDEF) return FolTheory(t).with_signature(sig) elif isinstance(phi, FolManySortSignature): return FolManySortSignature([(f, a) for f, a in phi.funcs if f in s], [(p, a) for p, a in phi.preds if p in s], self.blur(phi.sorts)) elif isinstance(phi, FolSignature): return FolSignature([(f, a) for f, a in phi.funcs if f in s], [(p, a) for p, a in phi.preds if p in s]) elif isinstance(phi, FolSorts): return FolSorts(self.blur(phi.sorts)) elif isinstance(phi, FolStructure): return FolStructure(domain=phi.domain, interpretation=self.blur(phi.interpretation)) elif isinstance(phi, dict): return dict( (sym, v) for sym, v in phi.iteritems() if sym in self.symbols) else: raise TypeError, phi if __name__ == '__main__': from logic.fol import FolSymbolic p = lambda x: Identifier(x, 'predicate') f = lambda x: Identifier(x, 'function') L = FolSymbolic.Language().with_(a=p('a'), b=f('b'), c=f('c'), d=f('d')) phi = L * "(a(b,c,d) | a(b,c,c)) & a(b,b,c)" print phi print FolRegister(set([p('a'), f('b'), f('c')])).blur(phi)
from pattern.collection.basics import OneToOne from logic.fol.semantics.graphs import AlgebraicStructureGraphTool from z3support.adapter import Z3ModelToFolStructure, Z3FormulaToFolFormula from mini_bmc import BMC from logic.fol.syntax.transform.delta import DeltaReduction #------------------------------------------------------------------------------# # Declarations # impSort = V = DeclareSort('V') n = Function('n*', V, V, BoolSort()) n0 = Function('n*0', V, V, BoolSort()) n_prime = Function('n*@', V, V, BoolSort()) eqrel = Identifier('eqrel', 'macro') eqpred = Identifier('eqpred', 'macro') def nPlus(x, y): return And(x != y, n(x, y)) # #------------------------------------------------------------------------------# class Z3Gate(object): def __init__(self): self.z3_sort_map = OneToOne({ 'bool': BoolSort(),
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 __call__(self, program): wps = WeakestPreSynthesis() wps.configure(detptr_libraries()) wps.syn.libs += [self.VC] #TODO - change formulas , decls = wps_formula_get(wps,program) I_args = inv_args_get(wps, "I") formula = FolFormula.conjunction(formulas) prefix = wp_forall_prefix_get(formula)| set([Identifier('null', 'const')]) bounded_prefix = AuxTransformers.get_all_bound_vars(formula) prefix-=bounded_prefix pprint( formulas ) print prefix z3_formulas_with_blasting = [] from shape2horn import hoist_forall from shape2horn import blast_horn from shape2horn import hoist_horn formulas_with_implies = [] ackm_bools = {} ackm_bools_to_vars = {} #sanity = FormulaSanity() watch = Stopwatch() with watch: for f in formulas: if f.root == 'true': continue head = f.subtrees[1] body = f.subtrees[0] head_ls = FolFormula.split(head) #splits conjunctions in head for i in head_ls: #creates new formulas of form: body -> i f_with_implies = create_f_with_implies(body,i) formulas_with_implies.append( f_with_implies ) for s in formulas_with_implies: print '-------- Input Clause ----------------' print s s_with_gamma = gamma_add( s ) #renumber_bound_vars() renames bounded vars to unique numbers s_with_gamma = AuxTransformers.renumber_bound_vars( s_with_gamma ) print s_with_gamma z3_f = transform_formula_to_z3(prefix, s_with_gamma, decls) for f in hoist_horn(z3_f[0]): z3_f_hoisted = hoist_forall(f) print '-------- Hoisted Formula ------------------' print z3_f_hoisted blasted_f = blast_horn(z3_f_hoisted) print '-------- Blasted Formula ---------------------' #print blasted_f if 0: blasted_f_with_replaced_n = replace_nstar_with_bools( blasted_f, \ decls, ackm_bools, ackm_bools_to_vars ) f_with_ackm_reduction = ackerman_reduction_get( \ blasted_f_with_replaced_n , ackm_bools_to_vars ) #print ackm_bools_to_vars z3_formulas_with_blasting.append( blasted_f ) #benchmark_print_to_file(h, z3_formulas_with_blasting) formulas_solver ( self, z3_formulas_with_blasting, decls["I"], I_args ) print 'Total sovling time: ',watch.total_time,'sec'
class FolSymbolic(Tree, promote.SimplisticPromoteMixIn): """ Provides syntactic sugar for building first-order formulas. There are two recommended usage forms: 1. Define variables of type FolSymbolic, each representing a single symbol (variable, function, predicate), then compose them using operators {~, &, |, >>, %, **, //}, and eventually call .to_formula(). e.g. a = FolSymbolic(Identifier('a', 'predicate')) u = FolSymbolic(Identifier('u', 'variable')) phi = (u ** (a(u) >> ~a(u))).to_formula() 2. Define a lambda function with arguments each representing a symbol (variable, function, predicate) and performing logical operations on them using {~, &, |, >>, %, **, //}; then call .formula(...). e.g. sig = {'a': Identifier('a', 'predicate'), 'u': Identifier('u', 'predicate')} phi = FolSymbolic(lambda a,u: u ** (a(u) >> ~a(u))) ~ stands for logical not (¬) & stands for logical and (∧) | stands for logical or (∨) >> stands for implication (➝) % stands for if-and-only-if (↔) ** stands for universal quantification (∀) // stands for existential quantification (∃) """ SUGAR = { '~': FolFormula.NOT, '&': FolFormula.AND, '|': FolFormula.OR, '>>': FolFormula.IMPLIES, '%': FolFormula.IFF, '**': FolFormula.FORALL, '//': FolFormula.EXISTS } VECTOR = Identifier(u"◦⃗", "macro") def __invert__(self): return type(self)('~', [self]) def __and__(self, other): return type(self)('&', [self, other]) def __or__(self, other): return type(self)('|', [self, other]) def __rshift__(self, other): return type(self)('>>', [self, other]) def __mod__(self, other): return type(self)('%', [self, other]) def __pow__(self, other): return type(self)('**', [self, other]) def __floordiv__(self, other): return type(self)('//', [self, other]) def __sub__(self, operator): if isinstance(operator, FolSymbolic): operator = operator.root if isinstance(operator, Callable): return type(self)(operator(self.root), self.subtrees) else: return NotImplemented def __call__(self, *args): if self.subtrees: raise SyntaxError, "invalid use of () after '%r'" % self elif isinstance(self.root, Identifier): return type(self)(self.root, [ x if isinstance(x, FolSymbolic) else FolSymbolic(x) for x in args ]) else: return type(self)( self.root(*((x.root if isinstance(x, FolSymbolic) else x) for x in args))) def __getitem__(self, subscript): if isinstance(self.root, (Sequence, Mapping)): return type(self)(self.root[subscript]) else: return NotImplemented def build(self, root, subtrees): return type(self)(root, [self.promote(x) for x in subtrees]) def with_identifiers(self, identifiers): self.identifiers = identifiers return self def to_formula(self): r = self.root if isinstance(r, FolFormula): return r elif isinstance(r, list): r = [isinstance(x, FolFormula) and x or FolFormula(x) for x in r] return FolFormula(self.VECTOR, r) else: formula = FolFormula(self.SUGAR.get(r, r), [sub.to_formula() for sub in self.subtrees]) return self.expand_vectors(formula) def expand_vectors(self, formula): root = formula.root subtrees = formula.subtrees if root in [FolFormula.FORALL, FolFormula.EXISTS ] and subtrees[0].root == self.VECTOR: formula = reduce(lambda x, y: FolFormula(root, [y, x]), reversed(subtrees[0].subtrees), subtrees[1]) elif isinstance(root, Identifier) and root.kind != "connective": flatten = [ x for s in subtrees for x in (s.root != self.VECTOR and [s] or s.subtrees) ] formula = FolFormula(root, flatten) elif root == self.VECTOR: raise ValueError, "a vector is not allowed here: '%s'" % formula formula = FolFormula( formula.root, [self.expand_vectors(x) for x in formula.subtrees]) return formula @classmethod def construct(cls, lambda_expr, signature_vars={}): import inspect #@UnresolvedImport if isinstance(lambda_expr, str) or isinstance(lambda_expr, unicode): lambda_expr = flam(lambda_expr) symbols, _, _, _ = inspect.getargspec(lambda_expr) def mksymbol(literal): if literal == 'true': return True if literal == 'false': return False try: return signature_vars[literal] except KeyError: return Identifier(literal, '?') ids = [mksymbol(s) for s in symbols] ids_genuine = [i for i in ids if isinstance(i, Identifier)] id_args = tuple(cls(i) for i in ids) retval = lambda_expr(*id_args) return cls.promote(retval).with_identifiers(ids_genuine) @classmethod def formula(cls, lambda_expr, signature_vars={}): return cls.construct(lambda_expr, signature_vars).to_formula() class Language(object): """ Just a bit of syntactic sugar to avoid too much repetition in programs where there are lots of formulas. """ def __init__(self, signatures=[]): if not isinstance(signatures, collections.Sequence): signatures = [signatures] self.signatures = [] for sig in signatures: if hasattr(sig, '__bases__'): ex = [c for c in oop.all_ur_base(sig) if c is not object] else: ex = [new.classobj('Signature', (), {'formal': sig})] self.signatures.extend(ex) self.dict = {} self.FolSymbolic = FolSymbolic for signature in reversed(self.signatures): self.dict.update(signature.__dict__) def with_(self, **kw): c = copy.copy(self) c.dict = copy.copy(c.dict) c.dict.update(kw) return c def with_sugar(self, *sugars): """ Combines the functionality of one or more FolSymbolic mix-ins, for use in the syntax of formulas processed by this language. """ bases = (CovertOps, ) + sugars + (self.FolSymbolic, ) self.FolSymbolic = new.classobj('FolSymbolic+', bases, {'_': self.signatures[0]}) return self @property def signature(self): return reduce(lambda x, y: x | y, (s.formal for s in self.signatures if hasattr(s, 'formal'))) def formula(self, expr): return self.FolSymbolic.formula(expr, self.dict) def __mul__(self, expr): if isinstance(expr, list): from logic.fol.syntax.theory import FolTheory return FolTheory(self.formula(el) for el in expr)\ .with_signature(self.signature) else: return self.formula(expr)