Beispiel #1
0
 def __init__(self, *operands):
     r'''
     Add together any number of operands.
     '''
     Operation.__init__(self, Add._operator_, operands)
     self.terms = self.operands
     if len(self.terms)==2 and all(term in DIGITS for term in self.terms):
         if self not in Add.addedNumerals:
             try:
                 # for single digit addition, import the theorem that provides the evaluation
                 Add.addedNumerals.add(self)
                 proveit.number.numeral.decimal._theorems_.__getattr__('add_%d_%d'%(self.terms[0].asInt(), self.terms[1].asInt()))
             except:
                 # may fail before the relevent _commons_ and _theorems_ have been generated
                 pass # and that's okay
Beispiel #2
0
 def deduceInBool(self, assumptions=USE_DEFAULTS):
     '''
     Attempt to deduce, then return, that this forall expression is in the set of BOOLEANS,
     as all forall expressions are (they are taken to be false when not true).
     '''
     raise NotImplementedError("Need to update")
     from _axioms_ import forallInBool
     P_op, P_op_sub = Operation(P, self.instanceVars), self.instanceExpr
     Q_op, Q_op_sub = Operation(Qmulti, self.instanceVars), self.conditions
     return forallInBool.specialize({
         P_op: P_op_sub,
         Q_op: Q_op_sub,
         xMulti: self.instanceVars,
         S: self.domain
     })
Beispiel #3
0
 def __init__(self, operators, operands, doMinSizeCheck=True):
     if doMinSizeCheck and len(operators) < 2:
         raise ValueError("Do not use a TransitiveSequence for fewer than two relationship (it is unnecessary)")
     if len(operators)+1 != len(operands):
         raise ValueError("There must be one more operand than operator in a TransitiveSequence")
     relation_class = self.__class__.RelationClass()
     assert issubclass(relation_class, TransitiveRelation), "The Relation class of a TransitiveSequence should be a TransitiveRelation"
     equiv_class = relation_class.EquivalenceClass()
     relation_operators = (relation_class.WeakRelationClass()._operator_, 
                           relation_class.StrongRelationClass()._operator_, 
                           equiv_class._operator_)
     for operator in operators:
         if operator not in relation_operators:
             raise TypeError("Operators of TransitiveSequence should be %s, %s, or %s"%tuple(str(relation_operator) for relation_operator in relation_operators))
     Operation.__init__(self, operators, operands)
Beispiel #4
0
 def _formatted(self, format_type, fence=False):
     formatted_gate_operation = (self.gate_operation.formatted(format_type,
                                                               fence=False))
     if format_type == 'latex':
         return r'\gate{' + formatted_gate_operation + r'}'
     else:
         return Operation.formatted(self, format_type, fence)
Beispiel #5
0
    def conclude(self, assumptions):
        '''
        Try to automatically conclude this bi-directional implication by
        reducing its operands to true/false.
        '''
        from . import iff_t_t, iff_t_f, iff_f_t, iff_f_f, true_iff_true, false_iff_false
        if self in {true_iff_true, false_iff_false}:
            # should be proven via one of the imported theorems as a simple
            # special case
            try:
                self.evaluation(assumptions)
            except BaseException:
                return self.prove()
        try:
            # try to prove the bi-directional implication via evaluation reduction.
            # if that is possible, it is a relatively straightforward thing to
            # do.
            return Operation.conclude(assumptions)
        except BaseException:
            pass
        try:
            # Use a breadth-first search approach to find the shortest
            # path to get from one end-point to the other.
            return TransitiveRelation.conclude(self, assumptions)
        except BaseException:
            pass

        # the last attempt is to introduce the Iff via implications each way, an
        # essentially direct consequence of the definition.
        return self.conclude_by_definition(assumptions)
Beispiel #6
0
 def evaluation(self, assumptions=USE_DEFAULTS):
     '''
     Given operands that evaluate to TRUE or FALSE, derive and
     return the equality of this expression with TRUE or FALSE. 
     '''
     from _theorems_ import iffTT, iffTF, iffFT, iffFF  # IMPORTANT: load in truth-table evaluations
     return Operation.evaluation(self, assumptions)
Beispiel #7
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)
Beispiel #8
0
 def concludeAsFolded(self, assumptions=USE_DEFAULTS):
     '''
     Prove and return some NotExists_{x | Q(x)} P(x) assuming Not(Exists_{x | Q(x)} P(x)).
     This is automatically derived; see Not.deriveSideEffects(..) and Not.deriveNotExists(..).
     '''
     from ._theorems_ import notExistsFolding
     P_op, P_op_sub = Operation(P, self.instanceVars), self.instanceExpr
     Q_op, Q_op_sub = Etcetera(Operation(
         Q, self.instanceVars)), self.conditions
     folding = notExistsFolding.specialize({
         P_op: P_op_sub,
         Q_op: Q_op_sub,
         xMulti: self.instanceVars,
         S: self.domain
     })
     return folding.deriveConclusion(assumptions)
Beispiel #9
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)
Beispiel #10
0
 def join(self, secondSummation, assumptions=frozenset()):
     '''
     Join the "second summation" with "this" summation, deducing and returning
     the equivalence of these summations added with the joined summation.
     Both summation must be over Intervals.
     The relation between the first summation upper bound, UB1, and the second
     summation lower bound, LB2 must be explicitly either UB1 = LB2-1 or LB2=UB1+1.
     '''
     from theorems import sumSplitAfter, sumSplitBefore
     from proveit.number.common import one
     from proveit.number import Sub, Add
     if not isinstance(self.domain, Interval) or not isinstance(secondSummation.domain, Interval):
         raise Exception('Sum joining only implemented for Interval domains')
     if self.summand != secondSummation.summand:
         raise Exception('Sum joining only allowed when the summands are the same')            
     if self.domain.upperBound == Sub(secondSummation.domain.lowerBound, one):
         sumSplit = sumSplitBefore 
         splitIndex = secondSummation.domain.lowerBound
     elif secondSummation.domain.lowerBound == Add(self.domain.upperBound, one):
         sumSplit = sumSplitAfter
         splitIndex = self.domain.upperBound
     else:
         raise Exception('Sum joining only implemented when there is an explicit increment of one from the upper bound and the second summations lower bound')
     lowerBound, upperBound = self.domain.lowerBound, secondSummation.domain.upperBound
     deduceInIntegers(lowerBound, assumptions)
     deduceInIntegers(upperBound, assumptions)
     deduceInIntegers(splitIndex, assumptions)
     return sumSplit.specialize({Operation(f, self.instanceVars):self.summand}).specialize({a:lowerBound, b:splitIndex, c:upperBound, x:self.indices[0]}).deriveReversed()
Beispiel #11
0
 def shallow_simplification(self,
                            *,
                            must_evaluate=False,
                            **defaults_config):
     '''
     If the left side has a 'not_equal' method, use that for
     evalaution.  Otherwise, if appropriate (must_evaluate is TRUE
     or the answer is already known) apply the definition to
     perform the evaluation: A ≠ B via ¬(A = B).
     '''
     from proveit import ProofFailure
     from proveit.logic import evaluate_truth
     if self.lhs != self.rhs and hasattr(self.lhs, 'not_equal'):
         try:
             # If there is a 'not_equal' method, try to use that.
             neq = self.lhs.not_equal(self.rhs, automation=must_evaluate)
             return evaluate_truth(neq)
         except ProofFailure:
             pass
     eq = Equals(self.lhs, self.rhs)
     if must_evaluate or eq.proven() or eq.disproven():
         # Evaluate A ≠ B via evaluating ¬(A = B),
         definition_equality = self.definition()
         unfolded_evaluation = definition_equality.rhs.evaluation(
             automation=must_evaluate)
         return definition_equality.apply_transitivity(unfolded_evaluation)
     return Operation.shallow_simplification(self)
Beispiel #12
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
Beispiel #13
0
 def remake_constructor(self):
     if self.is_reversed():
         # Use the 'not_proper_superset' function if it 
         # is reversed.
         return 'not_proper_superset'
     # Use the default.
     return Operation.remake_constructor(self)
Beispiel #14
0
 def split(self, splitIndex, side='after', assumptions=frozenset()):
     r'''
     Splits summation over one Interval {a ... c} into two summations.
     If side == 'after', it splits into a summation over {a ... splitIndex} plus
     a summation over {splitIndex+1 ... c}.  If side == 'before', it splits into
     a summation over {a ... splitIndex-1} plus a summation over {splitIndex ... c}.
     As special cases, splitIndex==a with side == 'after' splits off the first single
     term.  Also, splitIndex==c with side == 'before' splits off the last single term.
     r'''
     if not isinstance(self.domain, Interval):
         raise Exception(
             'Sum splitting only implemented for Interval domains')
     if side == 'before' and self.domain.upperBound == splitIndex:
         return self.splitOffLast()
     if side == 'after' and self.domain.lowerBound == splitIndex:
         return self.splitOffFirst()
     if isinstance(self.domain, Interval) and len(self.instanceVars) == 1:
         from theorems import sumSplitAfter, sumSplitBefore
         sumSplit = sumSplitAfter if side == 'after' else sumSplitBefore
         deduceInIntegers(self.domain.lowerBound, assumptions)
         deduceInIntegers(self.domain.upperBound, assumptions)
         deduceInIntegers(splitIndex, assumptions)
         # Also needs lowerBound <= splitIndex and splitIndex < upperBound
         return sumSplit.specialize({
             Operation(f, self.instanceVars):
             self.summand
         }).specialize({
             a: self.domain.lowerBound,
             b: splitIndex,
             c: self.domain.upperBound,
             x: self.indices[0]
         })
     raise Exception(
         "splitOffLast only implemented for a summation over a Interval of one instance variable"
     )
Beispiel #15
0
 def evaluation(self, assumptions=USE_DEFAULTS, automation=True):
     '''
     Given operands that evaluate to TRUE or FALSE, derive and
     return the equality of this expression with TRUE or FALSE.
     '''
     from ._theorems_ import impliesTT, impliesFT, impliesFF, impliesTF  # load in truth-table evaluations
     return Operation.evaluation(self, assumptions, automation=automation)
Beispiel #16
0
 def formatted(self, format_type, fence=False):
     formatted_gate_operation = self.target_gate.formatted(format_type,
                                                           fence=False)
     if format_type == LATEX:
         return r'\gate{' + formatted_gate_operation + r'}'
     else:
         return Operation.formatted(self, format_type, fence)
Beispiel #17
0
 def conclude(self, assumptions):
     from proveit.logic import FALSE
     if is_irreducible_value(self.lhs) and is_irreducible_value(self.rhs):
         # prove that two irreducible values are not equal
         return self.lhs.not_equal(self.rhs, assumptions)
     if self.lhs == FALSE or self.rhs == FALSE:
         try:
             # prove something is not false by proving it to be true
             return self.conclude_via_double_negation(assumptions)
         except BaseException:
             pass
     if hasattr(self.lhs, 'not_equal') and is_irreducible_value(self.rhs):
         try:
             return self.lhs.not_equal(self.rhs, assumptions)
         except BaseException:
             pass
     if hasattr(self.lhs, 'deduce_not_equal'):
         # If there is a 'deduce_not_equal' method, use that.
         # The responsibility then shifts to that method for
         # determining what strategies should be attempted
         # (with the recommendation that it should not attempt
         # multiple non-trivial automation strategies).
         eq = self.lhs.deduce_not_equal(self, assumptions)
         if eq.expr != self:
             raise ValueError("'deduce_not_equal' not implemented "
                              "correctly; must deduce the 'inequality' "
                              "that it is given if it can: "
                              "'%s' != '%s'" % (eq.expr, self))
         return eq
     try:
         return self.conclude_as_folded(assumptions)
     except BaseException:
         # try the default (reduction)
         return Operation.conclude(assumptions)
Beispiel #18
0
 def evaluation(self, assumptions=USE_DEFAULTS, automation=True):
     '''
     Given operands that evaluate to TRUE or FALSE, derive and
     return the equality of this expression with TRUE or FALSE.
     '''
     from . import iff_t_t, iff_t_f, iff_f_t, iff_f_f  # IMPORTANT: load in truth-table evaluations
     return Operation.evaluation(self, assumptions, automation)
Beispiel #19
0
 def shallow_simplification(self,
                            *,
                            must_evaluate=False,
                            **defaults_config):
     if must_evaluate and hasattr(self.operand, 'compute_norm'):
         return self.evaluation()
     return Operation.shallow_simplification(self)
Beispiel #20
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, Subtract, 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, Subtract):
         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__)
Beispiel #21
0
 def latex(self, **kwargs):
     if self.getStyle('division')=='fraction':
         # only fence if forceFence=True (a fraction within an exponentiation is an example of when fencing should be forced)
         kwargs['fence'] = kwargs['forceFence'] if 'forceFence' in kwargs else False        
         return maybeFencedLatex(r'\frac{'+self.numerator.latex()+'}{'+self.denominator.latex()+'}', **kwargs)
     else:
         return Operation.latex(**kwargs) # normal division
Beispiel #22
0
 def deduceInBool(self, assumptions=USE_DEFAULTS):
     '''
     Deduce, then return, that this exists expression is in the set of BOOLEANS as
     all exists expressions are (they are taken to be false when not true).
     '''
     raise NotImplementedError("Need to update")
     from ._theorems_ import existsInBool
     P_op, P_op_sub = Operation(P, self.instanceVars), self.instanceExpr
     Q_op, Q_op_sub = Operation(Qmulti, self.instanceVars), self.conditions
     return existsInBool.specialize(
         {
             P_op: P_op_sub,
             Q_op: Q_op_sub,
             S: self.domain
         },
         relabelMap={xMulti: self.instanceVars},
         assumptions=assumptions)
Beispiel #23
0
 def __init__(self, operands, *, styles=None):
     '''
     Len can take an explicit ExprTuple as operands, or
     it may take an expression (such as a varaible) that
     represents a tuple.  Either way, this expression is
     taken as the 'operands'.
     '''
     if isinstance(operands, ExprRange):
         # An ExprRange cannot represent an ExprTuple,
         # so we must want this wrapped in an ExprTuple.
         operands = ExprTuple(operands)
     # In order to always recognize that Len only takes a single
     # operand, we must wrap it as an ExprTuple with one entry.
     Operation.__init__(self,
                        Len._operator_,
                        operands=operands,
                        styles=styles)
Beispiel #24
0
 def splitOffFirst(self, assumptions=frozenset()):
     from theorems import sumSplitFirst # only for associative summation
     if isinstance(self.domain, Interval) and len(self.instanceVars) == 1:
         deduceInIntegers(self.domain.lowerBound, assumptions)
         deduceInIntegers(self.domain.upperBound, assumptions)
         # Also needs lowerBound < upperBound
         return sumSplitFirst.specialize({Operation(f, self.instanceVars):self.summand}).specialize({a:self.domain.lowerBound, b:self.domain.upperBound, x:self.indices[0]})
     raise Exception("splitOffLast only implemented for a summation over a Interval of one instance variable")
Beispiel #25
0
 def formatted(self, formatType, fence=False):
     print("Entering Target.formatted().")  # for testing; delete later
     formattedGateOperation = self.target_gate.formatted(formatType,
                                                         fence=False)
     if formatType == 'latex':
         return r'\gate{' + formattedGateOperation + r'}'
     else:
         return Operation._formatted(self, formatType, fence)
Beispiel #26
0
 def evaluation(self, assumptions=USE_DEFAULTS, *, automation=True,
                **kwargs):
     '''
     Given an operand that evaluates to TRUE or FALSE, derive and
     return the equality of this expression with TRUE or FALSE. 
     '''
     from ._theorems_ import notT, notF # load in truth-table evaluations
     return Operation.evaluation(self, assumptions, automation=automation)
Beispiel #27
0
 def formatted(self, formatType, fence=False, subFence=True):
     # Temporary hack to get quantum bra and ket products to display properly.
     # This should eventually be done differently because we shouldn't need to
     # know anything about the quantum application here.
     from proveit.physics.quantum import Bra, Ket, RegisterBra, RegisterKet
     if len(self.operands) == 2 and (isinstance(self.operands[0], Bra) or isinstance(self.operands[0], RegisterBra)) and (isinstance(self.operands[1], Ket) or isinstance(self.operands[1], RegisterKet)):
         return self.operands[0].formatted(formatType) + self.operands[1].formatted(formatType, no_lvert=True)
     # return Operation.formatted(self, formatType, fence, subFence)
     return Operation._formatted(self, formatType=formatType, fence=fence, subFence=subFence)
Beispiel #28
0
 def remakeConstructor(self):
     if self.getStyle('exponent') == 'radical':
         # Use a different constructor if using the 'radical' style.
         if self.exponent == frac(one, two):
             return 'sqrt' 
         else:
             raise ValueError("Unkown radical type, exponentiating to the power "
                              "of %s"%str(self.exponent))
     return Operation.remakeConstructor(self)
Beispiel #29
0
 def __init__(self, *operands):
     r'''
     Multiply together any number of operands from first operand.
     '''
     Operation.__init__(self, Mult._operator_, operands)
     self.factors = operands
     if len(self.factors) == 2 and all(factor in DIGITS
                                       for factor in self.factors):
         if self not in Mult.multipliedNumerals:
             try:
                 # for single digit addition, import the theorem that provides the evaluation
                 Mult.multipliedNumerals.add(self)
                 proveit.number.numeral.deci._theorems_.__getattr__(
                     'mult_%d_%d' %
                     (self.factors[0].asInt(), self.factors[1].asInt()))
             except:
                 # may fail before the relevent _commons_ and _theorems_ have been generated
                 pass  # and that's okay
Beispiel #30
0
 def deduceInNumberSet(self, numberSet, assumptions=USE_DEFAULTS):
     from ._theorems_ import summationNatsClosure, summationIntsClosure, summationRealsClosure, summationComplexesClosure
     P_op, P_op_sub = Operation(P, self.instanceVars), self.instanceExpr
     Q_op, Q_op_sub = Operation(Qmulti, self.instanceVars), self.conditions
     Operation(P, self.instanceVars)
     self.summand
     if numberSet == Naturals:
         thm = summationNatsClosure
     elif numberSet == Integers:
         thm = summationIntsClosure
     elif numberSet == Reals:
         thm = summationRealsClosure
     elif numberSet == Complexes:
         thm = summationComplexesClosure
     else:
         raise ProofFailure(InSet(self, numberSet), assumptions, "'deduceInNumberSet' not implemented for the %s set"%str(numberSet))
     return thm.specialize({P_op:P_op_sub, S:self.domain, Q_op:Q_op_sub}, relabelMap={xMulti:self.instanceVars}, 
                             assumptions=assumptions).deriveConsequent(assumptions=assumptions)