Example #1
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)
Example #2
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)
Example #3
0
 def conclude(self, assumptions):
     from ._theorems_ import subsetEqViaEquality
     from proveit import ProofFailure
     from proveit.logic import SetOfAll
     
     try:
         # first attempt a transitivity search
         return ContainmentRelation.conclude(self, assumptions)
     except ProofFailure:
         pass # transitivity search failed
     
     # Any set contains itself
     if self.operands[0] == self.operands[1]:
         return subsetEqViaEquality.specialize({A:self.operands[0], B:self.operands[1]})
         
     # 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.
     return self.concludeAsFolded(elemInstanceVar=safeDummyVar(self), assumptions=assumptions)
Example #4
0
 def distribute(self, assumptions=frozenset()):
     r'''
     Distribute the denominator through the numerate.  
     Returns the equality that equates self to this new version.
     Examples: 
         :math:`(a + b + c) / d = a / d + b / d + c / d`
         :math:`(a - b) / d = a / d - b / d`
         :math:`\left(\sum_x f(x)\right / y = \sum_x [f(x) / y]`
     Give any assumptions necessary to prove that the operands are in Complexes so that
     the associative and commutation theorems are applicable.            
     '''
     from proveit.number import Add, Sub, Sum
     from ._theorems_ import distributeFractionThroughSum, distributeFractionThroughSubtract, distributeFractionThroughSummation
     if isinstance(self.numerator, Add):
         return distributeFractionThroughSum.specialize({
             xEtc:
             self.numerator.operands,
             y:
             self.denominator
         })
     elif isinstance(self.numerator, Sub):
         return distributeFractionThroughSubtract.specialize({
             x:
             self.numerator.operands[0],
             y:
             self.numerator.operands[1],
             z:
             self.denominator
         })
     elif isinstance(self.numerator, Sum):
         # Should deduce in Complexes, but distributeThroughSummation doesn't have a domain restriction right now
         # because this is a little tricky.   To do.
         #deduceInComplexes(self.operands, assumptions)
         yEtcSub = self.numerator.indices
         Pop, Pop_sub = Operation(
             P, self.numerator.indices), self.numerator.summand
         S_sub = self.numerator.domain
         dummyVar = safeDummyVar(self)
         spec1 = distributeFractionThroughSummation.specialize({
             Pop: Pop_sub,
             S: S_sub,
             yEtc: yEtcSub,
             z: dummyVar
         })
         return spec1.deriveConclusion().specialize(
             {dummyVar: self.denominator})
     else:
         raise Exception("Unsupported operand type to distribute over: " +
                         self.numerator.__class__)
Example #5
0
    def conclude(self, assumptions):
        from proveit import ProofFailure
        from proveit.logic import Equals

        # Any set contains itself
        try:
            Equals(*self.operands).prove(assumptions, automation=False)
            return self.concludeViaEquality(assumptions)
        except ProofFailure:
            pass

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

        # Finally, attempt to conclude A supseteq B via forall_{x in B} x in A.
        return self.concludeAsFolded(elemInstanceVar=safeDummyVar(self),
                                     assumptions=assumptions)
Example #6
0
    def conclude(self, assumptions):
        from _theorems_ import supersetEqViaEquality
        from proveit import ProofFailure

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

        # any set is a superset of itself
        if self.operands[0] == self.operands[1]:
            return supersetEqViaEquality.specialize({
                A: self.operands[0],
                B: self.operands[1]
            })

        # Finally, attempt to conclude A supseteq B via forall_{x in B} x in A.
        return self.concludeAsFolded(elemInstanceVar=safeDummyVar(self),
                                     assumptions=assumptions)
Example #7
0
    def conclude(self, assumptions=USE_DEFAULTS):
        from proveit import ProofFailure
        from proveit.logic import SetOfAll, Equals

        # Any set contains itself
        try:
            Equals(*self.operands).prove(assumptions, automation=False)
            return self.concludeViaEquality(assumptions)
        except ProofFailure:
            pass

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

        # 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.allInstanceVars())==1 and
                setOfAll.instanceElement == setOfAll.allInstanceVars()[0] and
                setOfAll.domain==self.superset):
                Q_op, Q_op_sub = (
                        Operation(QQ, setOfAll.allInstanceVars()),
                        setOfAll.conditions)
                return comprehensionIsSubset.specialize(
                        {S:setOfAll.domain, Q_op:Q_op_sub},
                        relabelMap={x:setOfAll.allInstanceVars()[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)
Example #8
0
def varIter(var, start, end):
    from proveit import safeDummyVar
    from .indexed import Indexed
    param = safeDummyVar(var)
    return Iter(Lambda(param, Indexed(var, param)), start, end)
Example #9
0
    def cancel(self, operand, pull="left", assumptions=frozenset()):
        from proveit.number import Mult
        if self.numerator == self.denominator == operand:
            # x/x = 1
            from ._theorems_ import fracCancelComplete
            return fracCancelComplete.specialize({
                x: operand
            }).checked(assumptions)

        if not isinstance(self.numerator, Mult):
            from ._theorems_ import fracCancelNumerLeft
            newEq0 = self.denominator.factor(
                operand,
                pull=pull,
                groupFactor=True,
                groupRemainder=True,
                assumptions=assumptions).substitution(
                    Fraction(self.numerator, safeDummyVar(self)),
                    safeDummyVar(self)).checked(assumptions)
            newEq1 = fracCancelNumerLeft.specialize({
                x:
                operand,
                y:
                newEq0.rhs.denominator.operands[1]
            })
            return newEq0.applyTransitivity(newEq1)

        assert isinstance(self.numerator, Mult)
        if isinstance(self.denominator, Mult):
            from ._theorems_ import fracCancelLeft
            newEq0 = self.numerator.factor(
                operand,
                pull=pull,
                groupFactor=True,
                groupRemainder=True,
                assumptions=assumptions).substitution(
                    Fraction(safeDummyVar(self), self.denominator),
                    safeDummyVar(self)).checked(assumptions)
            newEq1 = self.denominator.factor(
                operand,
                pull=pull,
                groupFactor=True,
                groupRemainder=True,
                assumptions=assumptions).substitution(
                    Fraction(newEq0.rhs.numerator, safeDummyVar(self)),
                    safeDummyVar(self)).checked(assumptions)
            newEq2 = fracCancelLeft.specialize({
                x:
                operand,
                y:
                newEq1.rhs.numerator.operands[1],
                z:
                newEq1.rhs.denominator.operands[1]
            })
            return newEq0.applyTransitivity(newEq1).applyTransitivity(newEq2)
#            newFracIntermediate = self.numerator.factor(operand).proven().subRightSideInto(self)
#            newFrac = self.denominator.factor(operand).proven().subRightSideInto(newFracIntermediate)
#            numRemainingOps = newFrac.numerator.operands[1:]
#            denomRemainingOps = newFrac.denominator.operands[1:]
#            return fracCancel1.specialize({x:operand,Etcetera(y):numRemainingOps,Etcetera(z):denomRemainingOps})
        else:
            from ._theorems_ import fracCancelDenomLeft
            newEq0 = self.numerator.factor(
                operand,
                pull=pull,
                groupFactor=True,
                groupRemainder=True,
                assumptions=assumptions).substitution(
                    Fraction(safeDummyVar(self), self.denominator),
                    safeDummyVar(self)).checked(assumptions)
            newEq1 = fracCancelDenomLeft.specialize({
                x:
                operand,
                y:
                newEq0.rhs.numerator.operands[1]
            })
            return newEq0.applyTransitivity(newEq1)
Example #10
0
 def factor(self,
            theFactor,
            pull="left",
            groupFactor=False,
            groupRemainder=None,
            assumptions=frozenset()):
     '''
     Pull out a factor from a fraction, pulling it either to the "left" or "right".
     The factor may be a product or fraction itself.  
     If groupFactor is True and theFactor is a product, it will be grouped together as a 
     sub-product.  groupRemainder is not relevant kept for compatibility with other factor
     methods.  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.
     '''
     from ._theorems_ import fracInProdRev, prodOfFracsRev, prodOfFracsLeftNumerOneRev, prodOfFracsRightNumerOneRev
     from proveit.number import Mult, num
     dummyVar = safeDummyVar(self)
     eqns = []
     if isinstance(theFactor, Frac):
         # factor the operand denominator out of self's denominator
         denomFactorEqn = self.denominator.factor(theFactor.denominator,
                                                  pull,
                                                  groupFactor=True,
                                                  groupRemainder=True,
                                                  assumptions=assumptions)
         factoredDenom = denomFactorEqn.rhs
         eqns.append(
             denomFactorEqn.substitution(Frac(self.numerator, dummyVar),
                                         dummyVar))
         if theFactor.numerator != num(1) and self.numerator != num(1):
             # factor the operand numerator out of self's numerator
             numerFactorEqn = self.numerator.factor(theFactor.numerator,
                                                    pull,
                                                    groupFactor=True,
                                                    groupRemainder=True,
                                                    assumptions=assumptions)
             factoredNumer = numerFactorEqn.rhs
             eqns.append(
                 numerFactorEqn.substitution(Frac(dummyVar, factoredDenom),
                                             dummyVar))
             # factor the two fractions
             eqns.append(
                 prodOfFracsRev.specialize({
                     x: factoredNumer.operands[0],
                     y: factoredNumer.operands[1],
                     z: factoredDenom.operands[0],
                     w: factoredDenom.operands[1]
                 }))
         else:
             # special case: one of the numerators is equal to one, no numerator factoring to be done
             if (pull == 'left') == (theFactor.numerator == num(1)):
                 thm = prodOfFracsLeftNumerOneRev
             else:
                 thm = prodOfFracsRightNumerOneRev
             # factor the two fractions
             eqns.append(
                 thm.specialize({
                     x: self.numerator,
                     y: factoredDenom.operands[0],
                     z: factoredDenom.operands[1]
                 }))
     else:
         numerFactorEqn = self.numerator.factor(theFactor,
                                                pull,
                                                groupFactor=False,
                                                groupRemainder=True,
                                                assumptions=assumptions)
         factoredNumer = numerFactorEqn.rhs
         eqns.append(
             numerFactorEqn.substitution(Frac(dummyVar, self.denominator),
                                         dummyVar))
         # factor the numerator factor from the fraction
         if pull == 'left':
             wEtcSub = factoredNumer.operands[:-1]
             xSub = factoredNumer.operands[-1]
             zEtcSub = []
         elif pull == 'right':
             wEtcSub = []
             xSub = factoredNumer.operands[0]
             zEtcSub = factoredNumer.operands[1:]
         eqns.append(
             fracInProdRev.specialize({
                 wEtc: wEtcSub,
                 x: xSub,
                 y: self.denominator,
                 zEtc: zEtcSub
             }))
         num = len(theFactor.operands) if isinstance(theFactor, Mult) else 1
         if groupFactor and num > 1:
             if pull == 'left':
                 eqns.append(eqns[-1].rhs.group(endIdx=num,
                                                assumptions=assumptions))
             elif pull == 'right':
                 eqns.append(eqns[-1].rhs.group(startIdx=-num,
                                                assumptions=assumptions))
     return Equals(eqns[0].lhs, eqns[-1].rhs).prove(assumptions)
Example #11
0
    def _computation(self, assumptions=USE_DEFAULTS, must_evaluate=False):
        # Currently not doing anything with must_evaluate
        # What it should do is make sure it evaluates to a number
        # and can circumvent any attempt that will not evaluate to
        # number.
        from proveit.number import one
        if not isinstance(self.operand, ExprTuple):
            # Don't know how to compute the length if the operand is
            # not a tuple. For example, it could be a variable that
            # represent a tuple.  So just return the self equality.
            from proveit.logic import Equals
            return Equals(self, self).prove()
        entries = self.operand
        has_range = any(isinstance(entry, ExprRange) for entry in entries)
        if (len(entries) == 1 and has_range
                and not isinstance(entries[0].body, ExprRange)):
            # Compute the length of a single range.  Examples:
            # |(f(1), ..., f(n))| = n
            # |(f(i), ..., f(j))| = j-i+1
            range_entry = entries[0]
            start_index = range_entry.start_index
            end_index = range_entry.end_index
            lambda_map = range_entry.lambda_map
            if start_index == one:
                from proveit.core_expr_types.tuples._theorems_ import \
                    range_from1_len
                return range_from1_len.instantiate(
                    {
                        f: lambda_map,
                        i: end_index
                    }, assumptions=assumptions)
            else:
                from proveit.core_expr_types.tuples._theorems_ import range_len
                return range_len.instantiate(
                    {
                        f: lambda_map,
                        i: start_index,
                        j: end_index
                    },
                    assumptions=assumptions)
        elif not has_range:
            # Case of all non-range entries.
            if len(entries) == 0:
                # zero length.
                from proveit.core_expr_types.tuples._axioms_ import tuple_len_0
                return tuple_len_0
            elif len(entries) < 10:
                # Automatically get the count and equivalence with
                # the length of the proper iteration starting from
                # 1.  For example,
                # |(a, b, c)| = 3
                # |(a, b, c)| = |(1, .., 3)|
                import proveit.number.numeral.deci
                _n = len(entries)
                len_thm = proveit.number.numeral.deci._theorems_\
                            .__getattr__('tuple_len_%d'%_n)
                repl_map = dict()
                for param, entry in zip(len_thm.explicitInstanceParams(),
                                        entries):
                    repl_map[param] = entry
                return len_thm.specialize(repl_map)
            else:
                raise NotImplementedError("Can't handle length computation "
                                          ">= 10 for %s" % self)
        elif (len(entries) == 2 and not isinstance(entries[1], ExprRange)
              and not isinstance(entries[0].body, ExprRange)):
            # Case of an extended range:
            # |(a_1, ..., a_n, b| = n+1
            from proveit.core_expr_types.tuples._theorems_ import \
                extended_range_len, extended_range_from1_len
            assert isinstance(entries[0], ExprRange)
            range_lambda = entries[0].lambda_map
            range_start = entries[0].start_index
            range_end = entries[0].end_index
            if range_start == one:
                return extended_range_from1_len.instantiate(
                    {
                        f: range_lambda,
                        b: entries[1],
                        i: range_end
                    },
                    assumptions=assumptions)
            else:
                return extended_range_len.instantiate(
                    {
                        f: range_lambda,
                        b: entries[1],
                        i: range_start,
                        j: range_end
                    },
                    assumptions=assumptions)
        else:
            # Handle the general cases via general_len_val,
            # len_of_ranges_with_repeated_indices, or
            # len_of_ranges_with_repeated_indices_from_1
            from proveit.core_expr_types.tuples._theorems_ import (
                general_len, len_of_ranges_with_repeated_indices,
                len_of_ranges_with_repeated_indices_from_1)
            _x = safeDummyVar(self)

            def entry_map(entry):
                if isinstance(entry, ExprRange):
                    if isinstance(entry.body, ExprRange):
                        # Return an ExprRange of lambda maps.
                        return ExprRange(entry.parameter,
                                         entry.body.lambda_map,
                                         entry.start_index, entry.end_index)
                    else:
                        # Use the ExprRange entry's map.
                        return entry.lambda_map
                # For individual elements, just map to the
                # elemental entry.
                return Lambda(_x, entry)

            def entry_start(entry):
                if isinstance(entry, ExprRange):
                    if isinstance(entry.body, ExprRange):
                        # Return an ExprRange of lambda maps.
                        return ExprRange(entry.parameter,
                                         entry.body.start_index,
                                         entry.start_index, entry.end_index)
                    else:
                        return entry.start_index
                return one  # for individual elements, use start=end=1

            def entry_end(entry):
                if isinstance(entry, ExprRange):
                    if isinstance(entry.body, ExprRange):
                        # Return an ExprRange of lambda maps.
                        return ExprRange(entry.parameter, entry.body.end_index,
                                         entry.start_index, entry.end_index)
                    else:
                        return entry.end_index
                return one  # for individual elements, use start=end=1

            _f = [entry_map(entry) for entry in entries]
            _i = [entry_start(entry) for entry in entries]
            _j = [entry_end(entry) for entry in entries]
            _n = Len(_i).computed(assumptions=assumptions, simplify=False)
            if all(_ == _i[0] for _ in _i) and all(_ == _j[0] for _ in _j):
                if isinstance(_i[0], ExprRange):
                    if _i[0].is_parameter_independent:
                        # A parameter independent range means they
                        # are all the same.
                        _i = [_i[0].body]
                if isinstance(_j[0], ExprRange):
                    if _j[0].is_parameter_independent:
                        # A parameter independent range means they
                        # are all the same.
                        _j = [_j[0].body]
                if (not isinstance(_i[0], ExprRange)
                        and not isinstance(_j[0], ExprRange)):
                    # special cases where the indices are repeated
                    if _i[0] == one:
                        thm = len_of_ranges_with_repeated_indices_from_1
                        return thm.instantiate({
                            n: _n,
                            f: _f,
                            i: _j[0]
                        },
                                               assumptions=assumptions)
                    else:
                        thm = len_of_ranges_with_repeated_indices
                        return thm.instantiate(
                            {
                                n: _n,
                                f: _f,
                                i: _i[0],
                                j: _j[0]
                            },
                            assumptions=assumptions)
            return general_len.instantiate({
                n: _n,
                f: _f,
                i: _i,
                j: _j
            },
                                           assumptions=assumptions)