예제 #1
0
 def __init__(self, premise: Term, conclusion: Optional[Term] = None):
     self.premise = premise
     self.steps: List[Tuple[RewriteRule, int]] = list()
     self.current_step = deepcopy(premise)
     self.conclusion = conclusion if conclusion is not None else Boolean.trueb
     self.unproven_subgoals: List['Lemma'] = list()
     self.proven_subgoals: List['Lemma'] = list()
     self.hypotheses = RewriteSystem()
     self._auto_load_systems()
예제 #2
0
def simplify(x: Term, bound: int = -1):
    """Load in theory systems needed to normalize a term."""
    hypotheses = RewriteSystem()
    sorts = set((v.sort for v in get_vars_or_constants(x, True)))
    for sort in sorts:
        tsystem: Optional[TheorySystem] = system_from_sort(sort)
        if tsystem is not None:
            print(tsystem.rules)
            hypotheses.extend(tsystem.rules)
    return normal(x, hypotheses, bound)
예제 #3
0
class TheorySystem:
    """
    Contains a sort and the
    RewriteSystem that governs it.
    """
    sort: Sort = None
    rules: RewriteSystem = RewriteSystem()
    definitions: Dict[Function, RewriteSystem] = dict()

    @classmethod
    def simplify(cls, x: Term, bound: int = -1) -> Optional[Term]:
        """
        Simplify a term using the convergent
        rewrite rules known.
        """
        if not isinstance(x, FuncTerm):
            raise ValueError("simplify function expects a FuncTerm.")
        return normal(x, cls.rules, bound)[0]

    @classmethod
    def signature(cls) -> List[Term]:
        """List the signature of the system."""
        el = []
        for term in cls.__dict__.values():
            if not isinstance(term, (Constant, Function)):
                continue
            el.append(deepcopy(term))
        return el

    @classmethod
    def __len__(cls) -> int:
        """Return the number of elements."""
        return len(filter(lambda x: isinstance(x, Constant)),
                   cls.__dict__.values())

    @classmethod
    def add_rule(cls, rule: RewriteRule) -> None:
        """Add a rule to the system."""
        if not isinstance(rule, RewriteRule):
            raise ValueError(
                f"add_rule expected a RewriteRule not a '{type(rule)}'.")
        cls.rules.append(rule)

    @classmethod
    def define(cls, function: Function, rules: RewriteSystem):
        """Define a function by a rewrite system."""
        setattr(cls, function.symbol, function)
        # TODO: Make sure RewriteSystem terminates
        # TODO: Does composition of terminating rewrite systems terminate?
        for rule in rules:
            cls.add_rule(rule)
        cls.definitions[function] = rules
예제 #4
0
#!/usr/bin/env python3
from symcollab.algebra import Constant, Function, Variable
from symcollab.rewrite import RewriteRule, RewriteSystem, narrow, is_finite, Variants

f = Function("f", 2)
x = Variable("x")
a = Constant("a")
b = Constant("b")

r = RewriteRule(f(x, x), x)
r2 = RewriteRule(f(a, x), b)
print("Rewrite Rule 1:", r)
print("Rewrite Rule 2:", r2)
term = f(a, f(b, b))
rs = RewriteSystem({r, r2})
vt = Variants(term, rs)
print("Variants of", term, ":", list(vt))

print("Variants Finite?", is_finite(vt, -1))

print("Rewrite rule from", term, "to", f(a, b), narrow(term, f(a,b), rs, -1))
예제 #5
0
from symcollab.algebra import Function, Variable
from symcollab.rewrite import RewriteRule, RewriteSystem
from .inductive import Inductive, TheorySystem


@Inductive
class Prop(TheorySystem):
    pass


A = Variable("A", sort=Prop.sort)
B = Variable("B", sort=Prop.sort)
C = Variable("C", sort=Prop.sort)

Not = Function("not", 1, domain_sort=Prop.sort, range_sort=Prop.sort)
Prop.define(Not, RewriteSystem({RewriteRule(Not(Not(A)), A)}))

And = Function("and", 2, domain_sort=Prop.sort, range_sort=Prop.sort)
Prop.define(And, RewriteSystem({
    RewriteRule(And(A, A), A),
}))

Or = Function("or", 2, domain_sort=Prop.sort, range_sort=Prop.sort)
Prop.define(Or, RewriteSystem({
    RewriteRule(Or(A, A), A),
}))

Implies = Function("implies", 2, domain_sort=Prop.sort, range_sort=Prop.sort)
Prop.define(Implies, RewriteSystem({RewriteRule(Implies(A, B), Or(Not(A),
                                                                  B))}))
예제 #6
0
"""Definition and properties for two-arity tuple."""
from symcollab.algebra import Function, Variable
from symcollab.rewrite import RewriteRule, RewriteSystem
from .inductive import TheorySystem, Inductive


@Inductive
class Pair(TheorySystem):
    pair = Function("pair", 2)


# Fix domain of pair to take anything
Pair.pair.domain_sort = None

# Variables for later rules
_a = Variable("a", sort=Pair.sort)
_b = Variable("b", sort=Pair.sort)

fst = Function("fst", 1, domain_sort=Pair.sort)
Pair.define(fst, RewriteSystem({
    RewriteRule(fst(Pair.pair(_a, _b)), _a),
}))

lst = Function("lst", 1, domain_sort=Pair.sort)
Pair.define(lst, RewriteSystem({
    RewriteRule(lst(Pair.pair(_a, _b)), _b),
}))
예제 #7
0
        """Converts a Boolean to an bool."""
        if not isinstance(x, FuncTerm) or x != Boolean.trueb or x != Boolean.falseb:
            raise ValueError("to_bool function expects a simplified Boolean.")
        return x == Boolean.trueb


# Variables for later rules
_n = Variable("n", sort=Boolean.sort)
_m = Variable("m", sort=Boolean.sort)

# Negation
neg = Function("neg", 1, domain_sort=Boolean.sort, range_sort=Boolean.sort)
Boolean.define(
    neg,
    RewriteSystem({
        RewriteRule(neg(Boolean.trueb), Boolean.falseb),
        RewriteRule(neg(Boolean.falseb), Boolean.trueb)
    })
)

# Boolean And
andb = Function("andb", 2, domain_sort=Boolean.sort, range_sort=Boolean.sort)
Boolean.define(
    andb,
    RewriteSystem({
        RewriteRule(andb(Boolean.trueb, _n), _n),
        RewriteRule(andb(Boolean.falseb, _n), Boolean.falseb)
    })
)

# Boolean Or
orb = Function("orb", 2, domain_sort=Boolean.sort, range_sort=Boolean.sort)
예제 #8
0
class Ring(TheorySystem):
    """
    A ring is an abelian group with another binary
    operation that is associative, distributive over the
    abelian operation, and has an ientity element.
    """
    add = Function("add", 2)
    mul = Function("mul", 2)
    negate = Function("neg", 1)
    zero = Constant("0")

_x = Variable("x", sort=Group.sort)
_y = Variable("y", sort=Group.sort)
_z = Variable("z", sort=Group.sort)
# TODO: Make Group.rules.rules match what the function symbols are
Ring.rules = RewriteSystem(Group.rules.rules | {
    ## Associativity Rules
    # (x * y) * z → x * (y * z)
    RewriteRule(Ring.mul(Ring.mul(_x, _y), _z), Ring.mul(_x, Ring.mul(_y, _z))),
    ## Zero rules
    # 0 * x → 0
    RewriteRule(Ring.mul(Ring.zero, _x), Ring.zero),
    # x * 0 → 0
    RewriteRule(Ring.mul(_x, Ring.zero), Ring.zero),
    ## Distributivity rules
    # x * (y + z) → (x * y) + (x * z)
    RewriteRule(Ring.mul(_x, Ring.add(_y, _z)), Ring.add(Ring.mul(_x, _y), Ring.mul(_x, _z))),
    # (y + z) * x → (y * x) + (z * x)
    RewriteRule(Ring.mul(Ring.add(_y, _z), _x), Ring.add(Ring.mul(_y, _x), Ring.mul(_z, _x)))
})
예제 #9
0
#!/usr/bin/env python3
"""
A thought experiment on how to define
recursive MOOs.
"""
from symcollab.algebra import Constant, Function, Variable
from symcollab.rewrite import RewriteRule, RewriteSystem, normal
from symcollab.xor import xor
from symcollab.theories.nat import Nat

C = Function("C", 1, domain_sort=Nat.sort)
P = Function("P", 1, domain_sort=Nat.sort)
f = Function("f", 1)
IV = Constant("IV")
n = Variable("n", sort=Nat.sort)

r0 = RewriteRule(C(Nat.zero), IV)
rn = RewriteRule(C(Nat.S(n)), f(xor(P(Nat.S(n)), C(n))))
moo_system = RewriteSystem({r0, rn})
print("Cipher Block Chaining:", moo_system)

three = Nat.from_int(3)
print("Simplified form of the 3rd ciphertext:", normal(C(three), moo_system)[0])
예제 #10
0
class Lemma:
    """
    Holds an implication proof and provides
    utilities to automate it.
    """
    def __init__(self, premise: Term, conclusion: Optional[Term] = None):
        self.premise = premise
        self.steps: List[Tuple[RewriteRule, int]] = list()
        self.current_step = deepcopy(premise)
        self.conclusion = conclusion if conclusion is not None else Boolean.trueb
        self.unproven_subgoals: List['Lemma'] = list()
        self.proven_subgoals: List['Lemma'] = list()
        self.hypotheses = RewriteSystem()
        self._auto_load_systems()

    def add_hypotheses(self, r: Union[RewriteRule, RewriteSystem,
                                      Type[TheorySystem]]):
        """Add hypotheses via rewrite rules, systems, or theory systems."""
        if isinstance(r, RewriteRule):
            self.hypotheses.append(r)
        elif isinstance(r, RewriteSystem):
            self.hypotheses.extend(r)
        elif isclass(r) and issubclass(r, TheorySystem):
            self.hypotheses.extend(r.rules)
        else:
            raise ValueError("simplify must be passed either\
                 a RewriteRule, RewriteSystem, or TheorySystem.")

    @property
    def proven(self):
        """
        Return whether the current ground term matches the
        conclusion ground term syntactically.
        """
        return self.current_step == self.conclusion \
               and len(self.unproven_subgoals) == 0

    def apply(self, r: RewriteRule):
        """Apply a rewrite rule to the current step."""
        if not isinstance(r, RewriteRule):
            raise ValueError("apply must be given a RewriteRule")
        x_new = r.apply(self.premise)
        if x_new is None:
            return
        self.current_step = x_new
        self.steps.append(r)
        return x_new

    def simplify(self, bound: int = -1):
        """Attempt to simplify the current state."""
        new_steps = narrow(self.current_step, self.conclusion, self.hypotheses,
                           bound)
        if new_steps is None:
            return
        self.current_step = self.conclusion
        self.steps.extend(new_steps)
        return self.conclusion

    def auto(self, bound: int = -1):
        """
        Automate the proof by rewriting the
        current step into normal form, and applying
        the opposite steps that it takes to get
        the conclusion into normal form.
        """
        for subgoal in self.unproven_subgoals:
            subgoal.auto(self.hypotheses, bound)
        self._process_subgoals()

        # Find normal form of current step and goal term
        current_normal, steps = normal(self.current_step, self.hypotheses,
                                       bound)
        goal_normal, goal_normal_steps = normal(self.conclusion,
                                                self.hypotheses, bound)
        if current_normal != goal_normal:
            print("Auto: Normal Term Mismatch.")
            return

        # Reverse goal_normal_rules and add to steps list
        steps.extend([(converse(rule), pos)
                      for rule, pos in goal_normal_steps[::-1]])

        self.current_step = self.conclusion
        self.steps.extend(steps)
        return self.conclusion

    def undo(self):
        # TODO: Not sure how this function will behave with subgoals
        """Undo the last rewrite rule."""
        if len(self.steps) == 0:
            print("No steps to undo")
            return
        last_rule, last_pos = self.steps[-1]
        converse_rule = converse(last_rule)
        old_term = converse_rule.apply(self.current_step, last_pos)
        self.current_step = old_term
        del self.steps[-1]

    def _auto_load_systems(self):
        """
        Based on the sorts of constants and variables in the Lemma,
        auto load those TheorySystems.
        """
        terms = get_vars_or_constants(self.premise, True) | \
            get_vars_or_constants(self.conclusion, True)

        sorts = set((v.sort for v in terms))
        for sort in sorts:
            tsystem: Optional[TheorySystem] = system_from_sort(sort)
            if tsystem is not None:
                self.add_hypotheses(tsystem)

    def _process_subgoals(self):
        """
        Go through all subgoals,
        if proven then remove subgoal and
        add to hypothesis list.
        """
        for i, subgoal in reversed(list(enumerate(self.unproven_subgoals))):
            # Add proven subgoals to internal hypotheses list
            if subgoal.proven:
                new_rule = RewriteRule(subgoal.premise, subgoal.conclusion)
                self.hypotheses.append(new_rule)
                self.unproven_subgoals.pop(i)
                self.proven_subgoals.append(subgoal)

    def __repr__(self):
        question_str = "?" if not self.proven else ""
        return f"{self.premise} →{question_str} {self.conclusion}"
예제 #11
0
            return 0
        if isinstance(x, FuncTerm) and x.function == Nat.S:
            return 1 + cls.to_int(x.arguments[0])
        raise ValueError("to_int: Only accepts signature {0, S}")


# Variables for later rules
_n = Variable("n", sort=Nat.sort)
_m = Variable("m", sort=Nat.sort)

# Decrement
dec = Function("dec", 1, domain_sort=Nat.sort, range_sort=Nat.sort)
Nat.define(
    dec,
    RewriteSystem({
        RewriteRule(dec(Nat.S(_n)), _n),
        RewriteRule(dec(Nat.zero), Nat.zero)
    }))

## Parity Test

even = Function("even", 1, domain_sort=Nat.sort, range_sort=Boolean.sort)
Nat.define(
    even,
    RewriteSystem({
        RewriteRule(even(Nat.zero), Boolean.trueb),
        RewriteRule(even(Nat.S(Nat.zero)), Boolean.falseb),
        RewriteRule(even(Nat.S(Nat.S(_n))), even(_n))
    }))

odd = Function("odd", 1, domain_sort=Nat.sort, range_sort=Boolean.sort)
Nat.define(odd, RewriteSystem({RewriteRule(odd(_n), Boolean.neg(even(_n)))}))
예제 #12
0
# Variables for later rules
_element = Variable("element")
_list = Variable("alist", sort=Listing.sort)
_list2 = Variable("blist", sort=Listing.sort)

# Repeat
_count = Variable("n", sort=Nat.sort)
repeat = Function("repeat",
                  2,
                  domain_sort=[None, Nat.sort],
                  range_sort=Listing.sort)
Listing.define(
    repeat,
    RewriteSystem({
        RewriteRule(repeat(_element, Nat.zero), Listing.nil),
        RewriteRule(repeat(_element, Nat.S(_count)),
                    Listing.cons(_element, repeat(_element, _count)))
    }))

# Length
length = Function("length", 1, domain_sort=Listing.sort, range_sort=Nat.sort)
Listing.define(
    length,
    RewriteSystem({
        RewriteRule(length(Listing.nil), Nat.zero),
        RewriteRule(length(Listing.cons(_element, _list)),
                    Nat.S(length(_list)))
    }))

# Extends
extend = Function("extend",
예제 #13
0
_x = Variable("x", sort=Group.sort)
_y = Variable("y", sort=Group.sort)
_z = Variable("z", sort=Group.sort)
# From page 184 of Term Rewriting and All That
Group.rules = RewriteSystem({
    ## Associativity
    # (x * y) * z → x * (y * z)
    RewriteRule(Group.op(Group.op(_x, _y), _z), Group.op(_x, Group.op(_y, _z))),
    ## Identity Rules
    # 1 * x → x
    RewriteRule(Group.op(Group.identity, _x), _x),
    # x * 1 → x
    RewriteRule(Group.op(_x, Group.identity), _x),
    ## Inverse Rules
    # x * i(x) → 1
    RewriteRule(Group.op(_x, Group.inverse(_x)), Group.identity),
    # i(x) * x → 1
    RewriteRule(Group.op(Group.inverse(_x), _x), Group.identity),
    # i(1) → 1
    RewriteRule(Group.inverse(Group.identity), Group.identity),
    # i(i(x)) → x
    RewriteRule(Group.inverse(Group.inverse(_x)), _x),
    # i(x * y) → i(y) * i(x)
    RewriteRule(Group.inverse(Group.op(_x, _y)), Group.op(Group.inverse(_y), Group.inverse(_x))),
    ## Interplay between associativity and inverses
    # x * (i(x) * y) → y
    RewriteRule(Group.op(_x, Group.op(Group.inverse(_x), _y)), _y),
    # i(x) * (x * y) → y
    RewriteRule(Group.op(Group.inverse(_x), Group.op(_x, _y)), _y)
})
예제 #14
0
Field.rules = RewriteSystem(
    Ring.rules.rules | {
        ## One and Zero
        # 1 * 0 -> 0
        RewriteRule(Field.mul(Field.unity, Field.zero), Field.zero),
        # 0 * 1 -> 0
        RewriteRule(Field.mul(Field.zero, Field.unity), Field.zero),
        # 1 + 0 -> 1
        RewriteRule(Field.add(Field.unity, Field.zero), Field.unity),
        # 0 + 1 -> 1
        RewriteRule(Field.add(Field.zero, Field.unity), Field.unity),
        ## Unity Rules
        # 1 * x → x
        RewriteRule(Field.mul(Field.unity, _x), _x),
        # x * 1 → x
        RewriteRule(Field.mul(_x, Field.unity), _x),
        # -1 * x → -x
        RewriteRule(Field.mul(Field.negate(Field.unity), _x), Field.negate(_x)
                    ),
        # x * -1 → -x
        RewriteRule(Field.mul(_x, Field.negate(Field.unity)), Field.negate(_x)
                    ),
        # x * i(x) → 1
        RewriteRule(Field.mul(_x, Field.inverse(_x)), Field.unity),
        # i(x) * x → 1
        RewriteRule(Field.mul(Field.inverse(_x), _x), Field.unity),
        ## Inverse Rules
        # i(i(x)) → x
        RewriteRule(Field.inverse(Field.inverse(_x)), _x),
        # i(x * y) → i(y) * i(x)
        RewriteRule(Field.inverse(Field.mul(_x, _y)),
                    Field.mul(Field.inverse(_y), Field.inverse(_x))),
        ## Interplay between associativity and inverses
        # x * (i(x) * y) → y
        RewriteRule(Field.mul(_x, Field.mul(Field.inverse(_x), _y)), _y),
        # i(x) * (x * y) → y
        RewriteRule(Field.mul(Field.inverse(_x), Field.mul(_x, _y)), _y)
    })