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)
class FolNaturalPartialOrder: lt = Identifier('<', 'predicate', 'lt') gt = Identifier('>', 'predicate', 'gt') le = Identifier(u'≤', 'predicate', 'le') ge = Identifier(u'≥', 'predicate', 'ge') STANDARD_INTERPRETATION = \ {lt: lambda x,y: x < y, gt: lambda x,y: x > y, le: lambda x,y: x <= y, ge: lambda x,y: x >= y, }
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)}
def __init__(self): import re m = self.ESCAPE_SEQ self._ck = re.compile(self.VALID_IDENTIFIER_RE) self._multisubst = MultiSubstitution(m) self._sscript_re = re.compile(ur'[₀₁₂₃₄₅₆₇₈₉]+') self._sscript_tab = { ord(k): ord(v) for k, v in zip(u"₀₁₂₃₄₅₆₇₈₉", "0123456789") } self.escape = self.When(self._should_escape, Identifier.lift(self._s_escape)) self.unescape = Identifier.lift( MultiSubstitution({v: k for k, v in m.iteritems()})) self._is_valid_identifier = Identifier.lift(self._s_is_valid)
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:])
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 instantiate(node, varsym): l = [] for s in node.subtrees: f = s.root new_var = Identifier(u"%s_%s" % (f, varsym), 'variable', ns=ns) img = _(self._rel(f), [q(varsym), q(new_var)]) imgs = _.conjunction([img] + instantiate(s, new_var)) l += [_(_.EXISTS, [q(new_var), imgs])] return l
class GraphStructure(object): E = Identifier('E', 'predicate') w = Identifier('w', 'function') def __init__(self, g, weighted=False): self.g = g self.weighted = weighted def structure(self): has_edge = Labeled("has_edge", lambda u, v: v in u.get_adjacent_out()) interpretation = {self.E: has_edge} if self.weighted: get_weight = Labeled( "weight", lambda u, v: has_edge(u, v) and min( e.label for e in u.get_edges_to(v)) or INF) interpretation[self.w] = get_weight m = FolStructure(self.g.nodes, interpretation) return m
def __call__(self, program_text, compose_prefix=''): ast = self.parser(program_text) astf = ApplyTo(nodes=Identifier.promote).inplace( FolFormula.reconstruct(ast)) if compose_prefix: for n in astf.nodes: if n.subtrees: n.root = Identifier(compose_prefix + n.root.literal, 'macro') return astf
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
class TypeDeclarations(FolManySortSignature): COLON_SEP = [':'] FUNC_SEP = [u"→", '->', FolFormula.IMPLIES] PARAM_SEP = [u"×", FolIntegerArithmetic.mul, "*"] EMPTY_MARKER = [FolFormula(Identifier("", '?'))] def to_sorts(self, phi): if not isinstance(phi, FolFormula) or phi.root not in self.COLON_SEP or len( phi.subtrees) != 2: raise ValueError, "expected a declaration, found '%s'" % phi name, typename = phi.subtrees if not name.subtrees: name = name.root else: raise ValueError, "expected atomic identifier, found '%s' (in declaration '%s')" % ( name, phi) if typename.root in self.FUNC_SEP: if len(typename.subtrees) == 2: left, right = typename.subtrees else: raise ValueError, "invalid usage of '%s' (in declaration '%s')" % ( self.FUNC_SEP[0], phi) else: left, right = self.EMPTY_MARKER, typename from_ = () if left == self.EMPTY_MARKER else map( self._typename, left.split(self.PARAM_SEP)) to_ = '' if right == self.EMPTY_MARKER or right.root == "bool" else self._typename( right) return FolSorts({name: FolSorts.FunctionType(from_, to_)}) def _typename(self, term): if term.subtrees: raise NotImplementedError, "Non-atomic type '%s'" % term return term.root def is_declaration(self, phi): return isinstance(phi, FolFormula) and phi.root in self.COLON_SEP def read_from(self, formulas): if not isinstance(formulas, (list, set, tuple)): formulas = (formulas, ) for phi in formulas: self |= self.from_sorts(self.to_sorts(phi)) return self
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 = ''
class TypeInference(object): SPECIALTIES = [Identifier("ite", 'connective'), Identifier("?:", 'macro')] def __init__(self): self.declarations = FolSorts() self.signature = FolManySortSignature(set(), set()) self.special_symbols = {sym.literal: sym for sym in self.SPECIALTIES} def __call__(self, formula_or_formulas): if isinstance(formula_or_formulas, (tuple, list)): for phi in formula_or_formulas: self._formula(phi) if isinstance(formula_or_formulas, FolTheory): formula_or_formulas.signature |= self.signature formula_or_formulas.signature = formula_or_formulas.vocabulary else: self._formula(formula_or_formulas) return formula_or_formulas def _formula(self, phi, result_type='', bound_vars=set()): """ (changes formula in-place, and also affects self.signature) """ r, s, arity = phi.root, phi.subtrees, len(phi.subtrees) if isinstance(r, Identifier): if r.kind == '?' and r.literal in self.special_symbols: phi.root = r = self.special_symbols[r.literal] if r.kind == 'quantifier': v = self._variable(phi.subtrees[0]) for expr in phi.subtrees[1:]: self._formula(expr, '', bound_vars | v) return '' elif r.kind == 'connective': for expr in phi.subtrees: self._formula(expr, '', bound_vars) return '' elif r == "?:": # @@ hard-coded for now self._formula(s[0], '', bound_vars) term_types = [self._formula(x, '?', bound_vars) for x in s[1:]] if term_types and all(x == term_types[0] for x in term_types[1:]): return term_types[0] else: return '?' elif r in bound_vars: phi.root = [v for v in bound_vars if v == r][0] sort = self.declarations.ary(phi.root, 0) self._infer(phi, result_type) return sort[0].to_ if sort else ' ' else: sort = self.declarations.ary(r, arity) if len(sort) == 1: # matching declaration subtypes = sort[0].from_ result_type = sort[0].to_ else: # undeclared or ambiguous subtypes = (' ', ) * arity # Try to assign a kind (predicate or function) to identifier if r.kind == '?': if (r, arity) in self.signature.funcs: cr = [ s for s, a in self.signature.funcs if (s, a) == (r, arity) ][0] elif (r, arity) in self.signature.preds: cr = [ s for s, a in self.signature.preds if (s, a) == (r, arity) ][0] else: cr = copy.copy(r) # TODO somtimes this is 'bool' when it should be '' if result_type == 'bool': result_type = '' cr.kind = 'predicate' if result_type == '' else 'function' if sort: self.signature.sorts[cr] = sort if cr.kind == 'function': self.signature.funcs.add((cr, arity)) else: self.signature.preds.add((cr, arity)) phi.root = cr self._infer(phi, result_type) for expr, subtype in zip(phi.subtrees, subtypes): self._formula(expr, subtype, bound_vars) return result_type def _variable(self, variable_expr): if not variable_expr.subtrees: v = variable_expr.root if isinstance(v, Identifier) and v.kind == '?': cv = copy.copy(v) cv.kind = 'variable' else: cv = v sort = self.declarations.ary(cv, 0) if sort: self.signature.sorts[cv] = sort return set([cv]) return set() def _infer(self, expr, expected_type): sorts = self.signature.sorts r = expr.root if expected_type not in [' ', '', '?' ] and not expr.subtrees and r not in sorts: sorts[r] = [((), expected_type)]
def _xform_protect(self, t): r = t.root if r in self.opaque: return type(t)(Identifier(self, 'opaque', ns=[t]))
def __init__(self, context, inner): self.context = context self.inner = inner if isinstance(inner, self.__class__): self.__class__ = inner.__class__ else: class NestedException(self.__class__, inner.__class__): __str__ = __repr__ = self.__class__.__str__ self.__class__ = NestedException def __str__(self): return "In: %r\n%r" % (self.context, self.inner) # Snippet if __name__ == '__main__': from logic.fol import Identifier i = Identifier('i', 'function') sigma = FolSignature([(i, 1)], []) m = FolStructure([1, 2, 3], {i: lambda x: x % 3 + 1}) p = FolDomainProjection(sigma, lambda t: t * 2) n = p(m) print n.domain print n.interpretation['i'] print[n.interpretation['i'](x) for x in n.domain] print FolResample().structure(n, sigma) print m.evaluate(FolFormula(i, [FolFormula(2)]))
def obligations(self, t, collect=[]): if t.root == 'valid': collect += [ type(t)(Identifier('lemma', '?'), [x]) for x in t.subtrees ] return FolFormula(FolFormula.TRUE)
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 Signature: ter_op = Identifier('?:', 'macro') ite = Identifier('ite', 'connective')
class Signature: REDUCE_GLOB = Identifier(u"Я", "quantifier") formal = FolSignature()
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 _rel(self, f): return Identifier("R_%s" % f, 'predicate')
def _img(self, f, x, ns=None): f = self.BracketedModifier(f, 'modifier') return Identifier(FolFormula(f, [FolFormula(x)]), 'function', ns=ns)
def _mkuniq(self, identifier): return Identifier(identifier.literal, identifier.kind, ns=self.NS())