Esempio n. 1
0
 def empty_range(_i, _j, _f, assumptions):
     # If the start and end are literal ints and form an
     # empty range, then it should be straightforward to
     # prove that the range is empty.
     from proveit.numbers import is_literal_int, Add
     from proveit.logic import Equals
     from proveit import m
     _m = entries[0].start_index
     _n = entries[0].end_index
     empty_req = Equals(Add(_n, one), _m)
     if is_literal_int(_m) and is_literal_int(_n):
         if _n.as_int() + 1 == _m.as_int():
             empty_req.prove()
     if empty_req.proven(assumptions):
         _f = Lambda(
             (entries[0].parameter, entries[0].body.parameter),
             entries[0].body.body)
         _i = entry_map(_i)
         _j = entry_map(_j)
         return len_of_empty_range_of_ranges.instantiate(
             {
                 m: _m,
                 n: _n,
                 f: _f,
                 i: _i,
                 j: _j
             },
             assumptions=assumptions)
Esempio n. 2
0
    def _prove_direct_relationship_if_known(self, item1, item2):
        '''
        Apply necessary transitivities to prove a direct relationship
        between item1 and item2 there is a known chain.  There may not
        be a known chain if the order is relying on the assertion that
        added items cannot come before previous items.
        '''
        from proveit.logic import Equals
        item_pair_chains = self.item_pair_chains
        relation_class = self.relation_class
        assumptions = self.assumptions
        eq_sets = self.eq_sets
        if (item1, item2) not in item_pair_chains:
            # We may not have the chain for these specific items, but
            # we should have it for something equivalent to each of the
            # items (unless item2 was added after item1 and only
            # presumed to come later w.r.t. the transitive relation).
            for eq_item1, eq_item2 in itertools.product(
                    eq_sets[item1], eq_sets[item2]):

                if (eq_item1, eq_item2) not in item_pair_chains:
                    # Maybe the relationship is known even though it
                    # isn't in item_pair_chains.  This can be a useful
                    # check in cases of merge sorting where some of the
                    # relationships are presumed.
                    for rel_class in relation_class._RelationClasses():
                        try:
                            rel = rel_class(eq_item1, eq_item2)
                            rel = rel.prove(assumptions, automation=False)
                            item_pair_chains[(eq_item1, eq_item2)] = [rel]
                            break  # We got all we need
                        except:
                            pass

                if (eq_item1, eq_item2) in item_pair_chains:
                    # If item1, eq_item1 are not identical expressions,
                    # prove that they are logically equal.
                    if item1 != eq_item1:
                        prepend = [Equals(item1, eq_item1).prove(assumptions)]
                    else:
                        prepend = []
                    # If item2, eq_item2 are not identical expressions,
                    # prove that they are logically equal.
                    if item2 != eq_item2:
                        append = [Equals(eq_item2, item2).prove(assumptions)]
                    else:
                        append = []
                    # Make the (item1, item2) chain by
                    # prepending/appending necessary equalities to the
                    # (eq_item1, eq_item2) chain
                    chain = (prepend + item_pair_chains[(eq_item1, eq_item2)] +
                             append)
                    item_pair_chains[(item1, item2)] = chain
                    break  # We only need one.

        #print("after chains", item_pair_chains)
        if (item1, item2) in item_pair_chains:
            chain = item_pair_chains[(item1, item2)]
            #print("prove direct relationship via", chain)
            self.relation_class.applyTransitivities(chain, assumptions)
Esempio n. 3
0
 def pull(self,
          startIdx=None,
          endIdx=None,
          direction='left',
          assumptions=USE_DEFAULTS):
     '''
     Pull a subset of consecutive operands, self.operands[startIdx:endIdx],
     to one side or another. Returns the equality that equates self to 
     this new version.  Give any assumptions necessary to prove that the 
     operands are in Complexes so that the commutation theorem is applicable.
     '''
     if direction == "left":  # pull the factor(s) to the left
         if startIdx == 0 or startIdx is None:
             return Equals(self,
                           self).prove(assumptions)  # no move necessary
         return self.commute(None,
                             startIdx,
                             startIdx,
                             endIdx,
                             assumptions=assumptions)
     elif direction == "right":  # pull the factor(s) to the right
         if endIdx == len(self.operands) or endIdx is None:
             return Equals(self,
                           self).prove(assumptions)  # no move necessary
         return self.commute(startIdx,
                             endIdx,
                             endIdx,
                             None,
                             assumptions=assumptions)
     else:
         raise ValueError(
             "Invalid pull direction!  (Acceptable values are \"left\" and \"right\".)"
         )
Esempio n. 4
0
    def shallow_simplification(self, *, must_evaluate=False, **defaults_config):
        '''
        For the simple binary case Max(a, b), returns a proven
        simplification equation for this Max expression assuming the
        operands 'a' and 'b' have been simplified and that we know or
        have assumed that either a >= b or b > a. If such relational
        knowledge is not to be had, we simply return the equation of
        the Max expression with itself.
        Cases with more than 2 operands are not yet handled.
        '''
        from proveit.logic import Equals
        from proveit.numbers import greater_eq

        # We're only set up to deal with binary operator version
        if not self.operands.is_double():
            # Default is no simplification if not a binary operation.
            return Equals(self, self).prove()

        # If binary and we know how operands 'a' and 'b' are related ...
        op_01, op_02 = self.operands[0], self.operands[1]
        if (greater_eq(op_01, op_02).proven()
            or greater_eq(op_02, op_01).proven()):
            from proveit import x, y
            from proveit.numbers.ordering import max_def_bin
            return max_def_bin.instantiate({x: op_01, y: op_02})

        # Otherwise still no simplification.
        return Equals(self, self).prove()
Esempio n. 5
0
 def substitution(self, replacement, assumptions=USE_DEFAULTS):
     '''
     Equate the top level expression with a similar expression
     with the inner expression replaced by the replacement.
     '''
     from proveit.logic import Equals
     cur_inner_expr = self.expr_hierarchy[-1]
     equality = Equals(cur_inner_expr, replacement).prove(assumptions)
     equality.substitution(self.repl_lambda(), assumptions=assumptions)
Esempio n. 6
0
 def __init__(self, expr, assumptions=USE_DEFAULTS):
     '''
     Create a TransRelUpdater starting with the given
     expression and forming the trivial relation of
     expr=expr.  By providing 'assumptions', they
     can be used as default assumptions when applying
     updates.
     '''
     from proveit.logic import Equals
     self.expr = expr
     self.relation = Equals(expr, expr).conclude_via_reflexivity()
     self.assumptions = assumptions
Esempio n. 7
0
    def deduce_equality(self, equality, **defaults_config):
        '''
        Prove the given equality with self on the left-hand side.
        
        '''
        from proveit.logic import Equals
        if not isinstance(equality, Equals):
            raise ValueError("The 'equality' should be an Equals expression")
        if equality.lhs != self:
            raise ValueError("The left side of 'equality' should be 'self'")
        if equality.proven():
            return equality  # Already proven.
        with defaults.temporary() as temp_defaults:
            # Auto-simplify everything except the left and right sides
            # of the equality.
            temp_defaults.preserved_exprs = {equality.lhs, equality.rhs}
            temp_defaults.auto_simplify = True

            # Try a special-case "typical equality".
            if isinstance(equality.rhs, Len):
                if (isinstance(equality.rhs.operands, ExprTuple)
                        and isinstance(self.operands, ExprTuple)):
                    if (equality.rhs.operands.num_entries() == 1 and
                            isinstance(equality.rhs.operands[0], ExprRange)):
                        try:
                            eq = self.typical_eq()
                            if eq.expr == equality:
                                return eq
                        except (NotImplementedError, ValueError):
                            pass

            # Next try to compute each side, simplify each side, and
            # prove they are equal.
            lhs_computation = equality.lhs.computation()
            if isinstance(equality.rhs, Len):
                # Compute both lengths and see if we can prove that they
                # are equal.
                rhs_computation = equality.rhs.computation()
                eq = Equals(lhs_computation.rhs, rhs_computation.rhs)
                if eq.lhs == eq.rhs:
                    # Trivial reflection
                    eq = eq.conclude_via_reflexivity()
                else:
                    eq = eq.conclude_via_transitivity()
                return Equals.apply_transitivities(
                    [lhs_computation, eq, rhs_computation])
            else:
                # Compute the lhs length and see if we can prove that it is
                # equal to the rhs.
                eq = Equals(lhs_computation.rhs, equality.rhs)
                if eq.lhs == eq.rhs:
                    # Trivial reflection
                    eq = eq.conclude_via_reflexivity()
                else:
                    eq = eq.conclude_via_transitivity()
                return lhs_computation.apply_transitivity(eq)
Esempio n. 8
0
    def simplification(self, assumptions=USE_DEFAULTS):
        '''
        If possible, return a KnownTruth of this expression equal to a
        canonically simplified form. Checks for an existing simplifcation.
        If it doesn't exist, try some default strategies including a reduction.
        Attempt the Expression-class-specific "doReducedSimplication"
        when necessary.
        '''
        from proveit.logic import Equals, defaultSimplification, SimplificationError
        from proveit import KnownTruth, ProofFailure

        method_called = None
        try:
            # First try the default tricks. If a reduction succesfully occurs,
            # simplification will be called on that reduction.
            simplification = defaultSimplification(self.innerExpr(),
                                                   assumptions=assumptions)
            method_called = defaultSimplification
        except SimplificationError as e:
            # The default did nothing, let's try the Expression-class specific versions of
            # evaluation and simplification.
            try:
                # first try evaluation.  that is as simple as it gets.
                simplification = self.doReducedEvaluation(assumptions)
                method_called = self.doReducedEvaluation
            except (NotImplementedError, SimplificationError):
                try:
                    simplification = self.doReducedSimplification(assumptions)
                    method_called = self.doReducedSimplification
                except (NotImplementedError, SimplificationError):
                    # Simplification did not work.  Just use self-equality.
                    self_eq = Equals(self, self)
                    simplification = self_eq.prove()
                    method_called = self_eq.prove

        if not isinstance(simplification, KnownTruth) or not isinstance(
                simplification.expr, Equals):
            msg = ("%s must return a KnownTruth "
                   "equality, not %s for %s assuming %s" %
                   (method_called, simplification, self, assumptions))
            raise ValueError(msg)
        if simplification.lhs != self:
            msg = ("%s must return a KnownTruth "
                   "equality with 'self' on the left side, not %s for %s "
                   "assuming %s" %
                   (method_called, simplification, self, assumptions))
            raise ValueError(msg)
        # Remember this simplification for next time:
        Equals.simplifications.setdefault(self, set()).add(simplification)

        return simplification
Esempio n. 9
0
def apply_association_thm(expr,
                          start_idx,
                          length,
                          thm,
                          *,
                          repl_map_extras=None,
                          **defaults_config):
    from proveit.logic import Equals
    beg, end = start_and_end_indices(expr,
                                     start_index=start_idx,
                                     length=length)
    if beg == 0 and end == expr.operands.num_entries():
        # association over the entire range is trivial:
        return Equals(expr, expr).prove()  # simply the self equality
    if repl_map_extras is None:
        repl_map_extras = dict()
    i, j, k, A, B, C = [
        _var for _var in thm.all_instance_vars() if _var not in repl_map_extras
    ]
    _A = expr.operands[:beg]
    _B = expr.operands[beg:end]
    _C = expr.operands[end:]
    _i = _A.num_elements()
    _j = _B.num_elements()
    _k = _C.num_elements()
    with expr.__class__.temporary_simplification_directives() as \
            tmp_directives:
        tmp_directives.ungroup = False
        repl_map = {i: _i, j: _j, k: _k, A: _A, B: _B, C: _C}
        repl_map.update(repl_map_extras)
        return thm.instantiate(repl_map)
Esempio n. 10
0
 def _check_tensor_equality(tensor_equality, allow_unary=False):
     '''
     Check that the tensor_equality has the appropriate form.
     '''
     if isinstance(tensor_equality, Judgment):
         tensor_equality = tensor_equality.expr
     if not isinstance(tensor_equality, Equals):
         raise ValueError("tensor_equality should be an Equals expression; "
                          " instead received: {}.".format(tensor_equality))
     if (not isinstance(tensor_equality.lhs, TensorProd) or
         not isinstance(tensor_equality.rhs, TensorProd)):
         if allow_unary:
             # If we are allowing the sides to by unary tensor 
             # products, make it so.
             tensor_equality = Equals(TensorProd(tensor_equality.lhs),
                                      TensorProd(tensor_equality.rhs))
         else:
             raise ValueError(
                     "tensor_equality should be an Equals expression of "
                     "tensor products; "
                     "instead received: {}.".format(tensor_equality))
     if (tensor_equality.lhs.factors.num_elements() !=
         tensor_equality.rhs.factors.num_elements()):
         raise ValueError(
                 "tensor_equality should be an Equals expression of tensor "
                 "products with the same number of factors; "
                 "instead received: {}.".format(tensor_equality))
     return tensor_equality
Esempio n. 11
0
def apply_association_thm(expr,
                          startIdx,
                          length,
                          thm,
                          assumptions=USE_DEFAULTS):
    from proveit.logic import Equals
    from proveit.number import num
    beg, end = startIdx, startIdx + length
    if beg < 0: beg = len(expr.operands) + beg  # use wrap-around indexing
    if not length >= 2:
        raise IndexError(
            "The 'length' must be 2 or more when applying association.")
    if end > len(expr.operands):
        raise IndexError("'startIdx+length' out of bounds: %d > %d." %
                         (end, len(expr.operands)))
    if beg == 0 and end == len(expr.operands):
        # association over the entire range is trivial:
        return Equals(expr, expr).prove()  # simply the self equality
    l, m, n, AA, BB, CC = thm.allInstanceVars()
    return thm.specialize(
        {
            l: num(beg),
            m: num(end - beg),
            n: num(len(expr.operands) - end),
            AA: expr.operands[:beg],
            BB: expr.operands[beg:end],
            CC: expr.operands[end:]
        },
        assumptions=assumptions)
Esempio n. 12
0
 def do_reduced_evaluation(self, assumptions=USE_DEFAULTS, **kwargs):
     '''
     Attempt to form evaluation of whether (element not in domain) is
     TRUE or FALSE.  If the domain has a 'membership_object' method,
     attempt to use the 'equivalence' method from the object it generates.
     '''
     from proveit.logic import Equals, TRUE, InSet
     # try an 'equivalence' method (via the nonmembership object)
     equiv = self.nonmembership_object.equivalence(assumptions)
     val = equiv.evaluation(assumptions).rhs
     evaluation = Equals(equiv, val).prove(assumptions=assumptions)
     # try also to evaluate this by deducing membership or non-membership
     # in case it generates a shorter proof.
     try:
         if evaluation.rhs == TRUE:
             if hasattr(self, 'nonmembership_object'):
                 self.nonmembership_object.conclude(assumptions=assumptions)
         else:
             in_domain = In(self.element, self.domain)
             if hasattr(in_domain, 'membership_object'):
                 in_domain.membership_object.conclude(
                     assumptions=assumptions)
     except BaseException:
         pass
     return evaluation
Esempio n. 13
0
 def _redundant_mod_elimination(
         expr, mod_elimination_thm, mod_elimination_in_sum_thm):
     '''
     For use by Mod and ModAbs for shallow_simplification.
     '''
     dividend = expr.dividend
     divisor = expr.divisor
     if isinstance(dividend, Mod) and dividend.divisor==divisor:
         # [(a mod b) mod b] = [a mod b]
         return mod_elimination_thm.instantiate(
                 {a:dividend.dividend, b:divisor})
     elif isinstance(dividend, Add):
         # Eliminate 'mod L' from each term.
         eq = TransRelUpdater(expr)
         _L = divisor
         mod_terms = []
         for _k, term in enumerate(dividend.terms):
             if isinstance(term, Mod) and term.divisor==_L:
                 mod_terms.append(_k)
         for _k in mod_terms:
             # Use preserve_all=True for all but the last term.
             preserve_all = (_k != mod_terms[-1])
             _a = expr.dividend.terms[:_k]
             _b = expr.dividend.terms[_k].dividend
             _c = expr.dividend.terms[_k+1:]
             _i = _a.num_elements()
             _j = _c.num_elements()
             expr = eq.update(
                     mod_elimination_in_sum_thm
                     .instantiate(
                             {i:_i, j:_j, a:_a, b:_b, c:_c, L:_L},
                             preserve_all=preserve_all))
         return eq.relation
     return Equals(expr, expr).conclude_via_reflexivity()
Esempio n. 14
0
    def conclude(self, assumptions):
        from ._theorems_ import subsetEqViaEquality
        from proveit import ProofFailure
        from proveit.logic import SetOfAll, Equals
        
        try:
            # first attempt a transitivity search
            return ContainmentRelation.conclude(self, assumptions)
        except ProofFailure:
            pass # transitivity search failed
        
        # Any set contains itself
        try:
            Equals(self.operands[0], self.operands[1]).prove(assumptions, automation=False)
            return subsetEqViaEquality.specialize({A: self.operands[0], B: self.operands[1]})
        except ProofFailure:
            pass

        # Check for special case of [{x | Q*(x)}_{x \in S}] \subseteq S
        if isinstance(self.subset, SetOfAll):
            from proveit.logic.set_theory.comprehension._theorems_ import comprehensionIsSubset
            setOfAll = self.subset
            if len(setOfAll.instanceVars)==1 and setOfAll.instanceElement == setOfAll.instanceVars[0] and setOfAll.domain==self.superset:
                Q_op, Q_op_sub = Operation(Qmulti, setOfAll.instanceVars), setOfAll.conditions
                return comprehensionIsSubset.specialize({S:setOfAll.domain, Q_op:Q_op_sub}, relabelMap={x:setOfAll.instanceVars[0]}, assumptions=assumptions)
        
        # Finally, attempt to conclude A subseteq B via forall_{x in A} x in B.
        # Issue: Variables do not match when using safeDummyVar: _x_ to x.
        # We need to automate this better, right now it is only practical to do concludeAsFolded manually.
        return self.concludeAsFolded(elemInstanceVar=safeDummyVar(self), assumptions=assumptions)
Esempio n. 15
0
 def substitute(self, replacement, assumptions=USE_DEFAULTS):
     '''
     Substitute the replacement in place of the inner expression
     and return a new proven statement (assuming the top
     level expression is proven, or can be proven automatically).
     '''
     from proveit import x, P
     from proveit.logic import TRUE, FALSE, Equals
     from proveit.logic.equality import (substitute_truth,
                                         substitute_falsehood)
     cur_inner_expr = self.expr_hierarchy[-1]
     if cur_inner_expr == TRUE:
         return substitute_truth.instantiate(
             {
                 P: self.repl_lambda(),
                 x: replacement
             },
             assumptions=assumptions)
     elif cur_inner_expr == FALSE:
         return substitute_falsehood.instantiate(
             {
                 P: self.repl_lambda(),
                 x: replacement
             },
             assumptions=assumptions)
     else:
         Equals(cur_inner_expr,
                replacement).sub_right_side_into(self.repl_lambda(),
                                                 assumptions=assumptions)
Esempio n. 16
0
 def deduce_equality(self, equality, **defaults_config):
     from proveit.logic import Equals
     if not isinstance(equality, Equals):
         raise ValueError("The 'equality' should be an Equals expression")
     if equality.lhs != self:
         raise ValueError("The left side of 'equality' should be 'self'")
     if (isinstance(equality.rhs, Conditional)
             and equality.lhs.condition == equality.rhs.condition):
         value_eq = Equals(equality.lhs.value, equality.rhs.value)
         value_eq.prove(assumptions=defaults.assumptions +
                        (self.condition, ))
         return equality.lhs.value_substitution(value_eq)
     raise NotImplementedError(
         "Conditional.deduce_equality only implemented "
         "for equating Conditionals with the same "
         "condition.")
Esempio n. 17
0
def apply_association_thm(expr,
                          startIdx,
                          length,
                          thm,
                          assumptions=USE_DEFAULTS):
    from proveit import ExprTuple
    from proveit.logic import Equals
    beg = startIdx
    if beg < 0: beg = len(expr.operands) + beg  # use wrap-around indexing
    end = beg + length
    if end > len(expr.operands):
        raise IndexError("'startIdx+length' out of bounds: %d > %d." %
                         (end, len(expr.operands)))
    if beg == 0 and end == len(expr.operands):
        # association over the entire range is trivial:
        return Equals(expr, expr).prove()  # simply the self equality
    i, j, k, A, B, C = thm.allInstanceVars()
    _A = ExprTuple(*expr.operands[:beg])
    _B = ExprTuple(*expr.operands[beg:end])
    _C = ExprTuple(*expr.operands[end:])
    _i = _A.length(assumptions)
    _j = _B.length(assumptions)
    _k = _C.length(assumptions)
    return thm.specialize({
        i: _i,
        j: _j,
        k: _k,
        A: _A,
        B: _B,
        C: _C
    },
                          assumptions=assumptions)
Esempio n. 18
0
    def conclude(self, assumptions):
        from ._theorems_ import supersetEqViaEquality
        from proveit import ProofFailure
        from proveit.logic import Equals

        try:
            # first attempt a transitivity search
            return ContainmentRelation.conclude(self, assumptions)
        except ProofFailure:
            pass  # transitivity search failed

        # Any set contains itself
        try:
            Equals(self.operands[0], self.operands[1]).prove(assumptions,
                                                             automation=False)
            return supersetEqViaEquality.specialize({
                A: self.operands[0],
                B: self.operands[1]
            })
        except ProofFailure:
            pass

        # Finally, attempt to conclude A supseteq B via forall_{x in B} x in A.
        return self.concludeAsFolded(elemInstanceVar=safeDummyVar(self),
                                     assumptions=assumptions)
Esempio n. 19
0
 def conclude(self, **defaults_config):
     '''
     Conclude something of the form 
     a ≤ b.
     '''
     from proveit.logic import InSet
     from proveit.numbers import Add, zero, RealNonNeg, deduce_number_set
     from . import non_neg_if_real_non_neg
     if Equals(self.lower, self.upper).proven():
         # We know that a = b, therefore a ≤ b.
         return self.conclude_via_equality()
     if self.upper == zero:
         # Special case with upper bound of zero.
         from . import non_pos_if_real_non_pos
         concluded = non_pos_if_real_non_pos.instantiate({a: self.lower})
         return concluded
     if self.lower == zero:
         # Special case with lower bound of zero.
         deduce_number_set(self.upper)
         if InSet(self.upper, RealNonNeg).proven():
             return non_neg_if_real_non_neg.instantiate({a: self.upper})
     if ((isinstance(self.lower, Add)
          and self.upper in self.lower.terms.entries)
             or (isinstance(self.upper, Add)
                 and self.lower in self.upper.terms.entries)):
         try:
             # Conclude an sum is bounded by one of its terms.
             return self.conclude_as_bounded_by_term()
         except UnsatisfiedPrerequisites:
             # If prerequisites weren't satisfied to do this,
             # we can still try something else.
             pass
     return NumberOrderingRelation.conclude(self)
Esempio n. 20
0
 def coord2param(axis, coord):
     if subbed_indices[axis] == iterParams[axis]:
         return coord  # direct indexing that does not need to be inverted
     # The indexing is not direct; for example, x_{f(p)}.
     # We need to invert f to obtain p from f(p)=coord and register the inversion as a requirement:
     # f(p) = coord.
     param = Equals.invert(Lambda(iterParams[axis],
                                  subbed_indices[axis]),
                           coord,
                           assumptions=assumptions)
     inversion = Equals(
         subbed_indices[axis].substituted(
             {iterParams[axis]: param}), coord)
     requirements.append(
         inversion.prove(assumptions=assumptions))
     return param
Esempio n. 21
0
 def evaluation(self, assumptions=USE_DEFAULTS):
     '''
     Attempt to form evaluation of whether (element in domain) is
     TRUE or FALSE.  If the domain has a 'membershipObject' method,
     attempt to use the 'equivalence' method from the object it generates.
     '''
     from proveit.logic import Equals, TRUE, NotIn
     evaluation = None
     try:  # try an 'equivalence' method (via the membership object)
         equiv = self.membershipObject.equivalence(assumptions)
         val = equiv.evaluation(assumptions).rhs
         evaluation = Equals(equiv, val).prove(assumptions=assumptions)
     except:
         # try the default evaluation method if necessary
         evaluation = Operation.evaluation(self, assumptions)
     # try also to evaluate this by deducing membership or non-membership in case it
     # generates a shorter proof.
     try:
         if evaluation.rhs == TRUE:
             if hasattr(self, 'membershipObject'):
                 self.membershipObject.conclude(assumptions=assumptions)
         else:
             notInDomain = NotIn(self.element, self.domain)
             if hasattr(notInDomain, 'nonmembershipObject'):
                 notInDomain.nonmembershipObject.conclude(
                     assumptions=assumptions)
     except:
         pass
     return evaluation
Esempio n. 22
0
def apply_association_thm(expr,
                          start_idx,
                          length,
                          thm,
                          assumptions=USE_DEFAULTS):
    from proveit import ExprTuple
    from proveit.logic import Equals
    beg = start_idx
    if beg < 0:
        beg = expr.operands.num_entries() + beg  # use wrap-around indexing
    end = beg + length
    if end > expr.operands.num_entries():
        raise IndexError("'start_idx+length' out of bounds: %d > %d." %
                         (end, expr.operands.num_entries()))
    if beg == 0 and end == expr.operands.num_entries():
        # association over the entire range is trivial:
        return Equals(expr, expr).prove()  # simply the self equality
    i, j, k, A, B, C = thm.all_instance_vars()
    _A = expr.operands[:beg]
    _B = expr.operands[beg:end]
    _C = expr.operands[end:]
    _i = _A.num_elements(assumptions)
    _j = _B.num_elements(assumptions)
    _k = _C.num_elements(assumptions)
    return thm.instantiate({
        i: _i,
        j: _j,
        k: _k,
        A: _A,
        B: _B,
        C: _C
    },
                           assumptions=assumptions)
Esempio n. 23
0
 def factor(self,
            theFactor,
            pull="left",
            groupFactor=True,
            groupRemainder=False,
            assumptions=USE_DEFAULTS):
     '''
     Factor out "theFactor" from this product, pulling it either to the "left" or "right".
     If "theFactor" is a product, this may factor out a subset of the operands as
     long as they are next to each other (use commute to make this happen).  If
     there are multiple occurrences, the first occurrence is used.  If groupFactor is
     True and theFactor is a product, these operands are grouped together as a sub-product.
     If groupRemainder is True and there are multiple remaining operands (those not in
     "theFactor"), then these remaining operands are grouped together as a sub-product.
     Returns the equality that equates self to this new version.
     Give any assumptions necessary to prove that the operands are in Complexes so that
     the associative and commutation theorems are applicable.
     '''
     idx, num = self.index(theFactor, alsoReturnNum=True)
     expr = self.pull(idx, idx + num, pull, assumptions)
     if groupFactor and num > 1:
         if pull == 'left':  # use 0:num type of convention like standard pythong
             expr = expr.rhs.group(endIdx=num, assumptions=assumptions)
         elif pull == 'right':
             expr = expr.rhs.group(startIdx=-num, assumptions=assumptions)
     if groupRemainder and len(self.operands) - num > 1:
         # if the factor has been group, effectively there is just 1 factor operand now
         numFactorOperands = 1 if groupFactor else num
         if pull == 'left':
             expr = expr.rhs.group(startIdx=numFactorOperands,
                                   assumptions=assumptions)
         elif pull == 'right':
             expr = expr.rhs.group(endIdx=-numFactorOperands,
                                   assumptions=assumptions)
     return Equals(self, expr.rhs)
Esempio n. 24
0
class TransRelUpdater:
    '''
    Transitive relation updater: A convenient class for
    updating a transitive relation (equality, less, subset,
    etc.) by adding relations that modify the relation
    via transitivity.
    '''
    def __init__(self, expr, assumptions=USE_DEFAULTS):
        '''
        Create a TransRelUpdater starting with the given
        expression and forming the trivial relation of
        expr=expr.  By providing 'assumptions', they
        can be used as default assumptions when applying
        updates.
        '''
        from proveit.logic import Equals
        self.expr = expr
        self.relation = Equals(expr, expr).conclude_via_reflexivity()
        self.assumptions = assumptions

    def update(self, relation, assumptions=None):
        '''
        Update the internal relation by applying transitivity
        with the given relation.  Return the new expression
        that is introduced.  For example, if the internal
        expression is 'b' and the internal relation is
        'a < b' and 'b < c' is provided, deduce
        'a < c' as the new internal relation and
        return 'c' as the new internal expression.
        '''
        if assumptions is None:
            assumptions = self.assumptions
        relation_reversed = relation.is_reversed()
        self.relation = self.relation.apply_transitivity(
            relation, assumptions=assumptions, preserve_all=True)
        if relation.lhs == self.expr:
            self.expr = relation.rhs
        elif relation.rhs == self.expr:
            self.expr = relation.lhs
        else:
            raise ValueError("Relation %s should match expression %s "
                             "on one of its sides." % (relation, self.expr))
        if relation_reversed != self.relation.is_reversed():
            # Reverse to match the "direction" of the provided relation.
            self.relation = self.relation.with_direction_reversed()
        return self.expr
Esempio n. 25
0
 def notEqual(self, rhs, assumptions=USE_DEFAULTS):
     from ._theorems_ import multNotEqZero
     if rhs == zero:
         return multNotEqZero.specialize({xMulti: self.operands},
                                         assumptions=assumptions)
     raise ProofFailure(
         Equals(self, zero), assumptions,
         "'notEqual' only implemented for a right side of zero")
Esempio n. 26
0
    def deduce_equality(self,
                        equality,
                        assumptions=USE_DEFAULTS,
                        minimal_automation=False):
        from proveit.logic import Equals
        if not isinstance(equality, Equals):
            raise ValueError("The 'equality' should be an Equals expression")
        if equality.lhs != self:
            raise ValueError("The left side of 'equality' should be 'self'")
        # Try a special-case "typical equality".
        if isinstance(equality.rhs, Len):
            if (isinstance(equality.rhs.operand, ExprTuple)
                    and isinstance(self.operand, ExprTuple)):
                if (equality.rhs.operand.num_entries() == 1
                        and isinstance(equality.rhs.operand[0], ExprRange)):
                    try:
                        eq = \
                            self.typical_eq(assumptions=assumptions)
                        if eq.expr == equality:
                            return eq
                    except (NotImplementedError, ValueError):
                        pass

        # Next try to compute each side, simplify each side, and
        # prove they are equal.
        lhs_computation = equality.lhs.computation(assumptions=assumptions)
        if isinstance(equality.rhs, Len):
            # Compute both lengths and see if we can prove that they
            # are equal.
            rhs_computation = equality.rhs.computation(assumptions=assumptions)
            eq = Equals(lhs_computation.rhs, rhs_computation.rhs)
            if eq.lhs == eq.rhs:
                # Trivial reflection -- automation is okay for that.
                eq = eq.prove()
            else:
                eq = eq.prove(assumptions, automation=not minimal_automation)
            return Equals.apply_transitivities(
                [lhs_computation, eq, rhs_computation],
                assumptions=assumptions)
        else:
            # Compute the lhs length and see if we can prove that it is
            # equal to the rhs.
            eq = Equals(lhs_computation.rhs, equality.rhs)
            if eq.lhs == eq.rhs:
                # Trivial reflection -- automation is okay for that.
                eq = eq.prove()
            else:
                eq = eq.prove(assumptions, automation=not minimal_automation)
            return lhs_computation.apply_transitivity(eq,
                                                      assumptions=assumptions)
Esempio n. 27
0
 def substitute_falsehood(self, lambda_map, **defaults_config):
     '''
     Given not(A), derive P(A) from P(FALSE).
     '''
     from proveit.logic.equality import substitute_falsehood
     from proveit.logic import Equals
     from proveit.common import P
     Plambda = Equals._lambda_expr(lambda_map, self.operand)
     return substitute_falsehood.instantiate({x: self.operand, P: Plambda})
Esempio n. 28
0
 def substituteFalsehood(self, lambdaMap, assumptions=USE_DEFAULTS):
     '''
     Given not(A), derive P(A) from P(False).
     '''
     from proveit.logic.equality._theorems_ import substituteFalsehood
     from proveit.logic import Equals
     from proveit.common import P
     Plambda = Equals._lambdaExpr(lambdaMap, self.operand)
     return substituteFalsehood.specialize({x:self.operand, P:Plambda}, assumptions=assumptions)            
Esempio n. 29
0
 def substitute_falsehood(self, lambda_map, assumptions=USE_DEFAULTS):
     '''
     Given not(A), derive P(A) from P(False).
     '''
     from proveit.logic.equality import substitute_falsehood
     from proveit.logic import Equals
     from proveit.common import P
     Plambda = Equals._lambda_expr(lambda_map, self.operand)
     return substitute_falsehood.instantiate(
         {x: self.operand, P: Plambda}, assumptions=assumptions)
Esempio n. 30
0
 def simplification(self, assumptions=USE_DEFAULTS):
     '''
     For trivial cases, a zero or one factor,
     derive and return this multiplication expression equated with a simplified form.
     Assumptions may be necessary to deduce necessary conditions for the simplification.
     '''
     from ._theorems_ import multOne, multZero
     expr = self
     try:
         zeroIdx = self.operands.index(zero)
         # there is a zero in the product.  We can simplify that.
         if zeroIdx > 0:
             # commute it so that the zero comes first
             expr = expr.commute(0, zeroIdx, zeroIdx, zeroIdx + 1,
                                 assumptions).rhs
         if len(expr.operands) > 2:
             # group the other operands so there are only two at the top level
             expr = expr.group(1, len(expr.operands), assumptions)
         return Equals(
             self,
             multZero.specialize(
                 {x: expr.operands[1]},
                 assumptions=assumptions)).prove(assumptions)
     except ValueError:
         pass  # no zero factor
     try:
         oneIdx = expr.operands.index(one)
         # there is a one in the product.  We can simplify that.
         if oneIdx > 0:
             # commute it so that the one comes first
             expr = expr.commute(0, oneIdx, oneIdx, oneIdx + 1,
                                 assumptions).rhs
         if len(expr.operands) > 2:
             # group the other operands so there are only two at the top level
             expr = expr.group(1, len(expr.operands), assumptions).rhs
         return Equals(
             self,
             multOne.specialize({x: expr.operands[1]},
                                assumptions=assumptions)).prove(assumptions)
     except ValueError:
         pass  # no one factor
     raise ValueError(
         'Only trivial simplification is implemented (zero or one factors)')