def __init__(self, signature=FolManySortSignature(), logic="QF_UF"): self.signature = signature if not isinstance(signature, FolManySortSignature): self.signature = FolManySortSignature(signature.funcs, signature.preds) self.logic = logic self.builtin_mappings = { 'R': "Real", 'Z': "Int", FolWithEquality.Signature.eq: "=" }
def demo2(): V = DeclareSort("V") R = Function("R", V, V, BoolSort()) u, v, w = Consts("u v w", V) po = And( ForAll([u, v, w], Implies(And(R(u, v), R(v, w)), R(u, w))), # transitive ForAll([u, v], Not(And(R(u, v), R(v, u)))) # antisymmetric ) s = Solver() s.add(po) s.add(u != v) s.add(u != w) s.add(And(Or(R(u, v), R(v, u)), Or(R(u, w), R(w, u)))) print s.check() m = s.model() 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→'}) sig = FolManySortSignature.from_sorts(_.sorts) z3m = Z3ModelToFolStructure(sig, {_.u: u, _.v: v, _.w: w, _.R: R}) mm = z3m(m) print mm from adt.graph.format import DEFAULT as FORMATTER mm.domain = mm.domain['V'] print FORMATTER(AlgebraicStructureGraphTool(mm, [_.R])())
def __call__(self, phi): """ Makes sure any two identifiers that are not equal (not __eq__(x,y)) have distinct literals. Note: performs modification of formulas in-place. @param phi a FolFormula instance it may also be: * an Identifier, in which case the corresponding unique identifier is returned * a FolManySortSignature, in which case returns a *new* signature where all symbols are translated to unique ones """ if isinstance(phi, FolFormula): symset = OrderedSet(node.root for node in phi.nodes if node.root.ns is not None) symdict = {sym: self.gen_uniq(sym) for sym in symset} return TreeNodeRename(symdict).inplace(phi) elif isinstance(phi, Identifier): sym = phi return self.gen_uniq(sym) if sym.ns is not None else sym elif isinstance(phi, FolManySortSignature): renamed_sorts = FolSorts( {self(k): v for k, v in phi.sorts.sorts.iteritems()}) return FolManySortSignature.from_sorts(renamed_sorts) else: raise TypeError, "expected identifier, formula, or signature; found '%s'" % ( type(phi).__name__)
def declare_relations(self, signature): for f in self.funcs: Rf = self._rel(f) if Rf not in signature.preds: for from_, to_ in signature.sort_of(f): signature |= FolManySortSignature.from_sorts( FolSorts({Rf: [(tuple(from_) + (to_, ), 'bool')]}))
def __init__(self): self.z3_sort_map = OneToOne({ 'bool': BoolSort(), '': BoolSort() }).of(self._mksort) self.z3_decls = {} self.signature = FolManySortSignature() self.expansion = None
class Signature(FolWithEquality.Signature): add = Identifier("+", 'function') cos = Identifier("cos", 'function') sin = Identifier("sin", 'function') x = Identifier("x", 'function') sorts = FolSorts({add: "R×R→R", sin: "R→R", cos: "R→R", x: "→R"}) formal = FolManySortSignature.from_sorts(sorts)
def domain_of(self, symbol, signature): d = MultiDomain.promote(self.domain) s = FolManySortSignature.promote(signature) for (from_, _) in s.sort_of(symbol): if len(from_) == 1: l = d[from_[0]] else: l = d[from_] for el in l: yield el
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 structure(self, structure, signature, domain=None): if domain is None: domain = structure.domain domain = MultiDomain.promote(domain) s = FolManySortSignature.promote(signature) i = structure.interpretation explicit_i = {} for f, _ in signature.funcs: explicit_i[f] = self.join( self.function(i[f], from_, domain) for from_, _ in s.sort_of(f)) for p, _ in signature.preds: explicit_i[p] = self.join( self.predicate(i[p], from_, domain) for from_, _ in s.sort_of(p)) return FolStructure(domain, explicit_i)
class Signature(FolWithEquality.Signature): add = Identifier("+", 'function') cos = Identifier("cos", 'function') sin = Identifier("sin", 'function') x = Identifier("[x]", 'function', mnemonic="x") sorts = FolSorts({add: "R×R→R", sin: "R→R", cos: "R→R", x: "→R"}) formal = FolManySortSignature.from_sorts(sorts) standard_interpretation = \ {sin: lambda x: math.sin(x*math.pi/180), cos: lambda x: math.cos(x*math.pi/180)}
class FolIntegerArithmetic(FolNaturalPartialOrder): """ Signature for basic arithmetic. """ add = Identifier('+', 'function') sub = Identifier(u'−', 'function') mul = Identifier(u'⋅', 'function') div = Identifier('/', 'function') neg = Identifier('-', 'function') sorts = FolSorts({add: u"Z×Z→Z", mul: u"Z×Z→Z", sub: u"Z×Z→Z", div: u"Z×Z→Z", neg: u"Z→Z", FolNaturalPartialOrder.gt: u"Z×Z→", FolNaturalPartialOrder.lt: u"Z×Z→", FolNaturalPartialOrder.ge: u"Z×Z→", FolNaturalPartialOrder.le: u"Z×Z→"}) formal = FolManySortSignature.from_sorts(sorts) STANDARD_INTERPRETATION = \ {add : operator.add, sub: lambda a,b=None: -a if b is None else a-b, u'−': operator.sub, mul: operator.mul, u'*': operator.mul, div: operator.div # integer division } FolFormula.INFIXES += [mul, sub] class Sugar: """FolSymbolic mix-in""" def _b(self, root, subs): return type(self)(root, [self.promote(x) for x in subs]) def __add__(self, other): return self.build(self._.add, [self, other]) def __radd__(self, other): return self.build(self._.add, [other, self]) def __sub__(self, other): return self.build(self._.sub, [self, other]) def __rsub__(self, other): return self.build(self._.sub, [other, self]) def __mul__(self, other): return self.build(self._.mul, [self, other]) def __rmul__(self, other): return self.build(self._.mul, [other, self]) def __neg__(self): return self.build(self._.neg, [self]) # Naturally should be part of FolWithEquality def __eq__(self, other): return self.build(self._.eq, [self, other]) # Naturally should be part of FolNaturalPartialOrder def __gt__(self, other): return self.build(self._.gt, [self, other]) def __lt__(self, other): return self.build(self._.lt, [self, other]) def __ge__(self, other): return self.build(self._.ge, [self, other]) def __le__(self, other): return self.build(self._.le, [self, other])
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
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)
class Signature(FolWithEquality.Signature): add = Identifier("+", 'function') mul = Identifier("*", 'function') gt = Identifier(">", 'predicate', mnemonic="gt") ge = Identifier("≥", 'predicate', mnemonic="ge") lt = Identifier("<", 'predicate', mnemonic="lt") le = Identifier("≤", 'predicate', mnemonic="le") x = Identifier("[x]", 'function', mnemonic="x") y = Identifier("[y]", 'function', mnemonic="y") z = Identifier("[z]", 'function', mnemonic="z") b = Identifier(":b:", 'function', mnemonic="b") i = Identifier("i", 'variable') sorts = FolSorts({add: "Z×Z→Z", mul: "Z×Z→Z", gt: "Z×Z→", x: "Z→Z", y: "Z→Z", z: "Z→Z", b: "Z×Z→Z", i: "→Z"}) formal = FolManySortSignature.from_sorts(sorts)
def range_of(self, symbol, signature): d = MultiDomain.promote(self.domain) s = FolManySortSignature.promote(signature) for r in set(to_ for _, to_ in s.sort_of(symbol)): for el in d[r]: yield el
def __init__(self): self.declarations = FolSorts() self.signature = FolManySortSignature(set(), set()) self.special_symbols = {sym.literal: sym for sym in self.SPECIALTIES}
body_prime = self._add_quantifier_prefix(body_prime, r, new_names) return _(t.root, [s[0], body_prime]) def is_fine(self, atom): '''Only atoms of the form f(x)=y are allowed to have functions.''' r, s = atom.root, atom.subtrees if r == FolWithEquality.eq and len(s) == 2: return all(not w.subtrees for x in s for w in x.subtrees) elif r.kind == 'predicate': return all(not x.subtrees for x in s) else: return True if __name__ == '__main__': from logic.fol.syntax.parser import FolFormulaParser from eprv.synopsis.declare import TypeInference L = FolFormulaParser() f = Identifier('f', 'function') g = Identifier('g', 'function') sigma = FolManySortSignature.from_sorts(FolSorts({f: u'V→V', g: u'V→V'})) ti = TypeInference() ti.declarations = sigma.sorts phi = ti(L * "forall u (ite(u=u, f(u) = u, f(u) = g(u)))") from eprv.synopsis.proof import ProofSynopsis ef = EasyFunctionsExtension() ef.inspect_formula(phi, ProofSynopsis.Context(None, sigma)) print phi
class SmtLibInputFormat(object): class Attribute(object): def __init__(self, name, value): self.name = name self.value = value def __str__(self): return ":%s %s" % (self.name, self.value) def __init__(self, signature=FolManySortSignature(), logic="QF_UF"): self.signature = signature if not isinstance(signature, FolManySortSignature): self.signature = FolManySortSignature(signature.funcs, signature.preds) self.logic = logic self.builtin_mappings = { 'R': "Real", 'Z': "Int", FolWithEquality.Signature.eq: "=" } def predicates(self, preds): S = SchemeExpression return S("", [ S(p, self.sort_of(p, a) or [""]) for p, a in preds if p not in self.builtin_mappings ]) def functions(self, funcs): S = SchemeExpression return S("", [ S(f, self.sort_of(f, a)) for f, a in funcs if f not in self.builtin_mappings ]) def quantified_expression(self, variable): S = SchemeExpression return S("?%s" % variable, self.sort_of(variable, 0)) def mkid(self, identifier, *a): x = identifier return SchemeExpression(self.builtin_mappings.get(x, x), *a) def sort_of(self, symbol, arity): S = self.mkid sr = self.signature.sort_of(symbol, arity) if not sr: raise TypeError, "No sort for '%s/%d'" % (symbol, arity) from_, to_ = sr[0] # TODO support more than one to_ = [x for x in [to_] if x is not None] return [S(f) for l in (from_, to_) for f in l] def benchmark(self, title): return SchemeExpression("benchmark %s" % title) def list(self, l): #@ReservedAssignment S = SchemeExpression if l: return S("", [S.promote(x) for x in l]) else: return S("", [""]) def formula(self, formula): r = formula.root quantifiers_and_connectives = { FolFormula.FORALL: "forall", FolFormula.EXISTS: "exists", FolFormula.IMPLIES: "implies", FolFormula.AND: "and", FolFormula.OR: "or", FolFormula.IFF: "iff", FolFormula.NOT: "not" } it = r kind = None if isinstance(r, FolFormula.Identifier): kind = r.kind if r.kind == 'quantifier' or r.kind == 'connective': it = quantifiers_and_connectives[r] if r.kind == 'variable': it = "?%s" % r S = self.mkid if kind == 'quantifier': expr = S(it, [ self.quantified_expression(s.root) for s in formula.subtrees[:-1] ] + [self.formula(s) for s in formula.subtrees[-1:]]) else: expr = S(it, [self.formula(s) for s in formula.subtrees]) return self._tree_fold(expr) def theory(self, formulas, title="theory"): bm = self.benchmark(title) A = self.Attribute signature = self.signature all_sorts = set(["V"]) | self.signature.sorts.set() all_sorts = set(x for x in all_sorts if x not in self.builtin_mappings) attrs = [ A("logic", SchemeExpression(self.logic)), A("extrasorts", self.list(all_sorts)), A("extrafuns", self.functions(signature.funcs)), A("extrapreds", self.predicates(signature.preds)) ] attrs = [a for a in attrs if a.value] bm.attributes.extend(attrs) if formulas: bm.attributes.extend( [A("assumption", self.formula(f)) for f in formulas[:-1]]) bm.attributes.append(A("formula", self.formula(formulas[-1]))) return bm def __call__(self, thing): if isinstance(thing, list): thing = self.theory(thing, "theory") elif isinstance(thing, FolFormula): thing = self.theory([thing], "formula") return thing def _tree_fold(self, tree, foldables=("and", "or")): r = tree.root if r in foldables: subs = [] for s in tree.subtrees: if s.root == r: subs.extend(self._tree_fold(s, foldables).subtrees) else: subs.append(s) else: subs = tree.subtrees return type(tree)(r, [self._tree_fold(s, foldables) for s in subs])