Example #1
0
 def right_mult_both_sides(self, multiplier, **defaults_config):
     '''
     Multiply both sides of the relation by the 'multiplier'
     on the right.
     '''
     from proveit.numbers import LessEq, zero, deduce_number_set
     from proveit.numbers.multiplication import (
         strong_bound_via_left_factor_bound,
         weak_bound_via_left_factor_bound,
         reversed_strong_bound_via_left_factor_bound,
         reversed_weak_bound_via_left_factor_bound)
     was_reversed = False
     deduce_number_set(multiplier)
     if Less(zero, multiplier).proven():
         new_rel = strong_bound_via_left_factor_bound.instantiate({
             a:
             multiplier,
             x:
             self.lower,
             y:
             self.upper
         })
     elif Less(multiplier, zero).proven():
         new_rel = reversed_strong_bound_via_left_factor_bound.instantiate({
             a:
             multiplier,
             x:
             self.lower,
             y:
             self.upper
         })
         was_reversed = True
     elif LessEq(zero, multiplier).proven():
         new_rel = weak_bound_via_left_factor_bound.instantiate({
             a:
             multiplier,
             x:
             self.lower,
             y:
             self.upper
         })
     elif LessEq(multiplier, zero).proven():
         new_rel = reversed_weak_bound_via_left_factor_bound.instantiate({
             a:
             multiplier,
             x:
             self.lower,
             y:
             self.upper
         })
         was_reversed = True
     else:
         raise Exception(
             "Cannot right-multiply both sides of %s by %s "
             "without knowing the multiplier's relation with zero." %
             (self, multiplier))
     new_rel = new_rel.with_mimicked_style(self)
     if was_reversed:
         new_rel = new_rel.with_direction_reversed()
     return new_rel
Example #2
0
 def divide_both_sides(self,
                       divisor,
                       *,
                       simplify=True,
                       assumptions=USE_DEFAULTS):
     '''
     Divide both sides of the relation by the 'divisor'.
     '''
     from proveit.numbers import Less, zero
     from proveit.numbers.division import (div_pos_lesseq, div_neg_lesseq)
     if Less(zero, divisor).proven(assumptions):
         new_rel = div_pos_lesseq.instantiate(
             {
                 a: divisor,
                 x: self.lower,
                 y: self.upper
             },
             assumptions=assumptions)._simplify_both_sides(
                 simplify=simplify, assumptions=assumptions)
     elif Less(divisor, zero).proven(assumptions):
         new_rel = div_neg_lesseq.instantiate(
             {
                 a: divisor,
                 x: self.lower,
                 y: self.upper
             },
             assumptions=assumptions)._simplify_both_sides(
                 simplify=simplify, assumptions=assumptions)
     else:
         raise Exception("Cannot 'divide' a LessEq relation without "
                         "knowing whether the divisor is greater than "
                         "or less than zero.")
     return new_rel.with_mimicked_style(self)
Example #3
0
 def right_mult_both_sides(self,
                           multiplier,
                           *,
                           simplify=True,
                           assumptions=USE_DEFAULTS):
     '''
     Multiply both sides of the relation by the 'multiplier'
     on the right.
     '''
     from proveit.numbers import LessEq, zero
     from proveit.numbers.multiplication import (right_mult_pos_less,
                                                 right_mult_nonneg_less,
                                                 right_mult_neg_less,
                                                 right_mult_nonpos_less)
     if Less(zero, multiplier).proven(assumptions):
         new_rel = right_mult_pos_less.instantiate(
             {
                 a: multiplier,
                 x: self.lower,
                 y: self.upper
             },
             assumptions=assumptions)._simplify_both_sides(
                 simplify=simplify, assumptions=assumptions)
     elif Less(multiplier, zero).proven(assumptions):
         new_rel = right_mult_neg_less.instantiate(
             {
                 a: multiplier,
                 x: self.lower,
                 y: self.upper
             },
             assumptions=assumptions)._simplify_both_sides(
                 simplify=simplify, assumptions=assumptions)
     elif LessEq(zero, multiplier).proven(assumptions):
         new_rel = right_mult_nonneg_less.instantiate(
             {
                 a: multiplier,
                 x: self.lower,
                 y: self.upper
             },
             assumptions=assumptions)._simplify_both_sides(
                 simplify=simplify, assumptions=assumptions)
     elif LessEq(multiplier, zero).proven(assumptions):
         new_rel = right_mult_nonpos_less.instantiate(
             {
                 a: multiplier,
                 x: self.lower,
                 y: self.upper
             },
             assumptions=assumptions)._simplify_both_sides(
                 simplify=simplify, assumptions=assumptions)
     else:
         raise Exception(
             "Cannot 'right_mult_both_sides' a Less relation without "
             "knowing the multiplier's relation with zero.")
     return new_rel.with_mimicked_style(self)
Example #4
0
 def exponentiate_both_sides(self,
                             exponent,
                             *,
                             simplify=True,
                             assumptions=USE_DEFAULTS):
     '''
     Exponentiate both sides of the relation by the 'exponent'.
     '''
     from proveit.numbers import Less, zero
     from proveit.numbers.exponentiation import (exp_pos_lesseq,
                                                 exp_nonneg_lesseq,
                                                 exp_neg_lesseq,
                                                 exp_nonpos_lesseq)
     if Less(exponent, zero).proven(assumptions):
         new_rel = exp_pos_lesseq.instantiate(
             {
                 a: exponent,
                 x: self.lower,
                 y: self.upper
             },
             assumptions=assumptions)._simplify_both_sides(
                 simplify=simplify, assumptions=assumptions)
     elif Less(exponent, zero).proven(assumptions):
         new_rel = exp_neg_lesseq.instantiate(
             {
                 a: exponent,
                 x: self.lower,
                 y: self.upper
             },
             assumptions=assumptions)._simplify_both_sides(
                 simplify=simplify, assumptions=assumptions)
     elif LessEq(exponent, zero).proven(assumptions):
         new_rel = exp_nonneg_lesseq.instantiate(
             {
                 a: exponent,
                 x: self.lower,
                 y: self.upper
             },
             assumptions=assumptions)._simplify_both_sides(
                 simplify=simplify, assumptions=assumptions)
     elif LessEq(exponent, zero).proven(assumptions):
         new_rel = exp_nonpos_lesseq.instantiate(
             {
                 a: exponent,
                 x: self.lower,
                 y: self.upper
             },
             assumptions=assumptions)._simplify_both_sides(
                 simplify=simplify, assumptions=assumptions)
     else:
         raise Exception("Cannot 'exponentiate' a Less relation without "
                         "knowing the exponent's relation with zero")
     return new_rel.with_mimicked_style(self)
Example #5
0
    def conclude(self, assumptions):
        from proveit.logic import InSet, NotEquals
        from proveit.numbers import (Rational, RationalNonZero, RationalPos,
                                     RationalNeg, RationalNonNeg, Less,
                                     greater, greater_eq, zero)

        # If we known the element is in Q, we may be able to
        # prove that is in RationalNonZero, RationalPos, RationalNeg, or
        # RationalNonNeg if we know its relation to zero.
        if (self.number_set != Rational
                and InSet(self.element, Rational).proven(assumptions)):
            if self.number_set == RationalNonZero:
                if NotEquals(self.element, zero).proven(assumptions):
                    from . import non_zero_rational_is_rational_non_zero
                    return non_zero_rational_is_rational_non_zero.instantiate(
                        {q: self.element}, assumptions=assumptions)
            if self.number_set == RationalPos:
                if greater(self.element, zero).proven(assumptions):
                    from . import positive_rational_is_rational_pos
                    return positive_rational_is_rational_pos.instantiate(
                        {q: self.element}, assumptions=assumptions)
            if self.number_set == RationalNeg:
                if Less(self.element, zero).proven():
                    from . import negative_rational_is_rational_neg
                    return negative_rational_is_rational_neg.instantiate(
                        {q: self.element}, assumptions=assumptions)
            if self.number_set == RationalNonNeg:
                if greater_eq(self.element, zero).proven():
                    from . import non_neg_rational_in_rational_neg
                    return non_neg_rational_in_rational_neg.instantiate(
                        {q: self.element}, assumptions=assumptions)

        # Resort to the default NumberMembership.conclude strategies.
        return NumberMembership.conclude(self, assumptions)
Example #6
0
 def not_equal(self, other, **defaults_config):
     from proveit.numbers import Less
     from proveit.numbers.ordering import less_is_not_eq
     _a, _b = Less.sorted_items([self, other])
     not_eq_stmt = less_is_not_eq.instantiate({a: _a, b: _b})
     if not_eq_stmt.lhs != self:
         # We need to reverse the statement.
         return not_eq_stmt.derive_reversed()
     return not_eq_stmt       
Example #7
0
    def derive_element_in_restricted_number_set(self, **defaults_config):
        '''
        From (member in Interval(x, y)), where x ≥ 0 or y ≤ 0,
        deduce that the element is in Natural, NaturalPos, IntegerNeg,
        or IntegerNonPos as appropriate.
        '''
        _a = self.domain.lower_bound
        _b = self.domain.upper_bound
        _n = self.element

        # We wish to deduce a fact based upon the following
        # membership fact:
        self.expr.prove()

        if (not InSet(_a, Natural).proven()
                and not InSet(_b, IntegerNonPos).proven()):
            # If we don't know that a ≥ 0 or b ≤ 0, we can't prove
            # the element is in either restricted number set
            # (NaturalPos or IntegerNeg).  So, try to sort a, b, 0
            # to work this out.
            LessEq.sort([_a, _b, zero])

        if InSet(_a, Natural).proven():
            try:
                _a.deduce_in_number_set(NaturalPos, automation=False)
            except Exception:
                pass
            if InSet(_a, NaturalPos).proven():
                # member in N^{>0}
                lower_bounding = self.derive_element_lower_bound()
                a_bounding = greater(_a, zero)
                lower_bounding.apply_transitivity(a_bounding)
                return InSet(_n, NaturalPos).prove()
            else:
                # member in N
                lower_bounding = self.derive_element_lower_bound()
                a_bounding = greater_eq(_a, zero)
                lower_bounding.apply_transitivity(a_bounding)
                return InSet(_n, Natural).prove()
        if InSet(_b, IntegerNonPos).proven():
            try:
                _b.deduce_in_number_set(IntegerNeg, automation=False)
            except Exception:
                pass
            if InSet(_b, IntegerNeg).proven():
                # member in Z^{<0}
                upper_bounding = self.derive_element_upper_bound()
                b_bounding = Less(_b, zero)
                upper_bounding.apply_transitivity(b_bounding)
                return InSet(_n, IntegerNeg).prove()
            else:
                # member in Z^{≤0}
                upper_bounding = self.derive_element_upper_bound()
                b_bounding = LessEq(_b, zero)
                upper_bounding.apply_transitivity(b_bounding)
                return InSet(_n, IntegerNonPos).prove()
Example #8
0
 def divide_both_sides(self, divisor, **defaults_config):
     '''
     Divide both sides of the relation by the 'divisor'.
     '''
     from proveit.numbers import Less, zero, deduce_number_set
     from proveit.numbers.division import (
         strong_div_from_numer_bound__pos_denom,
         strong_div_from_numer_bound__neg_denom)
     deduce_number_set(divisor)
     if Less(zero, divisor).proven():
         thm = strong_div_from_numer_bound__pos_denom
     elif Less(divisor, zero).proven():
         thm = strong_div_from_numer_bound__neg_denom
     else:
         raise Exception("Cannot divide both sides of %s by %s "
                         "without knowing the divisors "
                         "relation to zero." % (self, divisor))
     new_rel = thm.instantiate({a: divisor, x: self.lower, y: self.upper})
     return new_rel.with_mimicked_style(self)
Example #9
0
 def exponentiate_both_sides(self, exponent, **defaults_config):
     '''
     Exponentiate both sides of the relation by the 'exponent'.
     '''
     from proveit.numbers import Less, LessEq, zero, deduce_number_set
     from proveit.numbers.exponentiation import (exp_pos_less,
                                                 exp_nonneg_less,
                                                 exp_neg_less,
                                                 exp_nonpos_less)
     # We need to know how the exponent relates to zero.
     deduce_number_set(exponent)
     LessEq.sort([zero, exponent])
     if Less(zero, exponent).proven():
         new_rel = exp_pos_less.instantiate({
             a: exponent,
             x: self.lower,
             y: self.upper
         })
     elif Less(exponent, zero).proven():
         new_rel = exp_neg_less.instantiate({
             a: exponent,
             x: self.lower,
             y: self.upper
         })
     elif LessEq(zero, exponent).proven():
         new_rel = exp_nonneg_less.instantiate({
             a: exponent,
             x: self.lower,
             y: self.upper
         })
     elif LessEq(exponent, zero).proven():
         new_rel = exp_nonpos_less.instantiate({
             a: exponent,
             x: self.lower,
             y: self.upper
         })
     else:
         raise Exception("Cannot exponentiate both sides of %s by %s "
                         "without knowing the exponent's relation with "
                         "zero" % (self, exponent))
     return new_rel.with_mimicked_style(self)
Example #10
0
 def not_equal(self, other, assumptions=USE_DEFAULTS):
     from proveit.numbers import Less
     from proveit.numbers.ordering import less_is_not_eq
     _a, _b = Less.sorted_items([self, other], assumptions=assumptions)
     not_eq_stmt = less_is_not_eq.instantiate({
         a: _a,
         b: _b
     },
                                              assumptions=assumptions)
     if not_eq_stmt.lhs != self:
         # We need to reverse the statement.
         return not_eq_stmt.derive_reversed(assumptions)
     return not_eq_stmt
Example #11
0
 def deduce_in_interval(self, **defaults_config):
     '''
     Bound the interval of the Sin function evaluation depending
     upon what is known about the angle.
     '''
     from . import (sine_interval, sine_nonneg_interval, sine_pos_interval,
                    sine_nonpos_interval, sine_neg_interval)
     from proveit.numbers import (zero, pi, Less, LessEq, Neg)
     _theta = self.angle
     deduce_number_set(_theta)
     if (Less(zero, _theta).proven() and Less(_theta, pi).proven()):
         return sine_pos_interval.instantiate({theta: _theta})
     elif (LessEq(zero, _theta).proven() and LessEq(_theta, pi).proven()):
         return sine_nonneg_interval.instantiate({theta: _theta})
     elif (Less(Neg(pi), _theta).proven() and Less(_theta, zero).proven()):
         return sine_neg_interval.instantiate({theta: _theta})
     elif (Less(Neg(pi), _theta).proven() and Less(_theta, zero).proven()):
         return sine_neg_interval.instantiate({theta: _theta})
     elif (LessEq(Neg(pi), _theta).proven()
           and LessEq(_theta, zero).proven()):
         return sine_nonpos_interval.instantiate({theta: _theta})
     else:
         # Without knowing more, we can only bound it by +/-1.
         return sine_interval.instantiate({theta: _theta})
Example #12
0
    def bound_via_numerator_bound(self, relation, **defaults_config):
        '''
        Given a relation applicable to the numerator,  bound this
        division accordingly.  For example,
        if self is "a / b" and the relation is a < x
        return (a / b) < (x / b), provided b > 0.

        Also see NumberOperation.deduce_bound.
        '''
        from proveit.numbers import zero, Less, LessEq, greater
        from . import (strong_div_from_numer_bound__pos_denom,
                       weak_div_from_numer_bound__pos_denom,
                       strong_div_from_numer_bound__neg_denom,
                       weak_div_from_numer_bound__neg_denom)
        if isinstance(relation, Judgment):
            relation = relation.expr
        if not (isinstance(relation, Less) or isinstance(relation, LessEq)):
            raise TypeError("relation is expected to be Less "
                            "or LessEq number relations, not %s" % relation)
        if self.numerator not in relation.operands:
            raise ValueError("relation is expected to involve the "
                             "numerator of %s.  %s does not." %
                             (self, relation))
        _a = self.denominator
        _x = relation.normal_lhs
        _y = relation.normal_rhs
        try:
            deduce_number_set(self.denominator)
        except UnsatisfiedPrerequisites:
            pass
        if greater(self.denominator, zero).proven():
            if isinstance(relation, Less):
                bound = strong_div_from_numer_bound__pos_denom.instantiate({
                    a:
                    _a,
                    x:
                    _x,
                    y:
                    _y
                })
            elif isinstance(relation, LessEq):
                bound = weak_div_from_numer_bound__pos_denom.instantiate({
                    a: _a,
                    x: _x,
                    y: _y
                })
        elif Less(self.denominator, zero).proven():
            if isinstance(relation, Less):
                bound = strong_div_from_numer_bound__neg_denom.instantiate({
                    a:
                    _a,
                    x:
                    _x,
                    y:
                    _y
                })
            elif isinstance(relation, LessEq):
                bound = weak_div_from_numer_bound__neg_denom.instantiate({
                    a: _a,
                    x: _x,
                    y: _y
                })
        else:
            raise UnsatisfiedPrerequisites(
                "We must know whether the denominator of %s "
                "is positive or negative before we can use "
                "'bound_via_numerator_bound'." % self)
        if bound.rhs == self:
            return bound.with_direction_reversed()
        return bound
Example #13
0
 def conclude(self, **defaults_config):
     from proveit.numbers import zero, Less
     if (InSet(self.element, Real).proven() and
             Less(self.element, zero).proven()):
         return self.conclude_as_last_resort()
     return NumberMembership.conclude(self)
Example #14
0
def greater(a, b):
    '''
    Return an expression representing a > b, internally represented 
    as b < a but with a style that reverses the direction.    
    '''
    return Less(b, a).with_styles(direction='reversed')
Example #15
0
def deduce_number_set(expr, **defaults_config):
    '''
    Prove that 'expr' is an Expression that represents a number
    in a standard number set that is as restrictive as we can
    readily know.
    '''
    from proveit.logic import And, InSet, Equals, NotEquals
    from proveit.numbers import Less, LessEq, zero

    # Find the first (most restrictive) number set that
    # contains 'expr' or something equal to it.

    for number_set in sorted_number_sets:
        membership = None
        for eq_expr in Equals.yield_known_equal_expressions(expr):
            if isinstance(eq_expr, ExprRange):
                membership = And(
                    ExprRange(eq_expr.parameter,
                              InSet(eq_expr.body, number_set),
                              eq_expr.true_start_index,
                              eq_expr.true_end_index,
                              styles=eq_expr.get_styles()))
            else:
                membership = InSet(eq_expr, number_set)
            if membership.proven():
                break  # found a known number set membership
            else:
                membership = None
        if membership is not None:
            membership = InSet(expr, number_set).prove()
            break

    if hasattr(expr, 'deduce_number_set'):
        # Use 'deduce_number_set' method.
        try:
            deduced_membership = expr.deduce_number_set()
        except (UnsatisfiedPrerequisites, ProofFailure):
            deduced_membership = None
        if deduced_membership is not None:
            assert isinstance(deduced_membership, Judgment)
            if not isinstance(deduced_membership.expr, InSet):
                raise TypeError("'deduce_number_set' expected to prove an "
                                "InSet type expression")
            if deduced_membership.expr.element != expr:
                raise TypeError("'deduce_number_set' was expected to prove "
                                "that %s is in some number set" % expr)
            # See if this deduced number set is more restrictive than
            # what we had surmised already.
            deduced_number_set = deduced_membership.domain
            if membership is None:
                membership = deduced_membership
                number_set = deduced_number_set
            elif (deduced_number_set != number_set
                  and number_set.includes(deduced_number_set)):
                number_set = deduced_number_set
                membership = deduced_membership

    if membership is None:
        from proveit import defaults
        raise UnsatisfiedPrerequisites(
            "Unable to prove any number membership for %s" % expr)

    # Already proven to be in some number set,
    # Let's see if we can restrict it further.
    if Less(zero, expr).proven():  # positive
        number_set = pos_number_set.get(number_set, None)
    elif Less(expr, zero).proven():  # negative
        number_set = neg_number_set.get(number_set, None)
    elif LessEq(zero, expr).proven():  # non-negative
        number_set = nonneg_number_set.get(number_set, None)
    elif LessEq(expr, zero).proven():  # non-positive
        number_set = nonpos_number_set.get(number_set, None)
    elif NotEquals(expr, zero).proven():
        number_set = nonzero_number_set.get(number_set, None)
    if number_set is None:
        # Just use what we have already proven.
        return membership.prove()
    return InSet(expr, number_set).prove()
Example #16
0
    def deduce_in_number_set(self, number_set, **defaults_config):
        '''
        Given a number set number_set, attempt to prove that the given
        expression is in that number set using the appropriate closure
        theorem.
        '''
        from proveit import a, b
        from proveit.numbers import Less, zero
        from proveit.numbers.division import (
            div_rational_closure, div_rational_nonzero_closure,
            div_rational_pos_closure, div_rational_pos_from_double_neg,
            div_rational_neg_from_neg_denom, div_rational_neg_from_neg_numer,
            div_rational_nonneg_closure, div_rational_nonneg_from_double_neg,
            div_rational_nonpos_from_neg_denom,
            div_rational_nonpos_from_nonpos_numer, div_real_closure,
            div_real_nonzero_closure, div_real_pos_closure,
            div_real_pos_from_double_neg, div_real_neg_from_neg_denom,
            div_real_neg_from_neg_numer, div_real_nonneg_closure,
            div_real_nonneg_from_double_neg, div_real_nonpos_from_neg_denom,
            div_real_nonpos_from_nonpos_numer, div_complex_nonzero_closure,
            div_complex_closure)

        thm = None
        if number_set == Rational:
            thm = div_rational_closure
        elif number_set == RationalNonZero:
            thm = div_rational_nonzero_closure
        elif number_set == RationalPos:
            deduce_number_set(self.denominator)
            if Less(self.denominator, zero).proven():
                thm = div_rational_pos_from_double_neg
            else:
                thm = div_rational_pos_closure
        elif number_set == RationalNeg:
            deduce_number_set(self.denominator)
            if Less(self.denominator, zero).proven():
                thm = div_rational_neg_from_neg_denom
            else:
                thm = div_rational_neg_from_neg_numer
        elif number_set == RationalNonNeg:
            deduce_number_set(self.denominator)
            if Less(self.denominator, zero).proven():
                thm = div_rational_nonneg_from_double_neg
            else:
                thm = div_rational_nonneg_closure
        elif number_set == RationalNonPos:
            deduce_number_set(self.denominator)
            if Less(self.denominator, zero).proven():
                thm = div_rational_nonpos_from_neg_denom
            else:
                thm = div_rational_nonpos_from_neg_numer
        elif number_set == Real:
            thm = div_real_closure
        elif number_set == RealNonZero:
            thm = div_real_nonzero_closure
        elif number_set == RealPos:
            deduce_number_set(self.denominator)
            if Less(self.denominator, zero).proven():
                thm = div_real_pos_from_double_neg
            else:
                thm = div_real_pos_closure
        elif number_set == RealNeg:
            deduce_number_set(self.denominator)
            if Less(self.denominator, zero).proven():
                thm = div_real_neg_from_neg_denom
            else:
                thm = div_real_neg_from_neg_numer
        elif number_set == RealNonNeg:
            deduce_number_set(self.denominator)
            if Less(self.denominator, zero).proven():
                thm = div_real_nonneg_from_double_neg
            else:
                thm = div_real_nonneg_closure
        elif number_set == RealNonPos:
            deduce_number_set(self.denominator)
            if Less(self.denominator, zero).proven():
                thm = div_real_nonpos_from_neg_denom
            else:
                thm = div_real_nonpos_from_nonpos_numer
        elif number_set == ComplexNonZero:
            thm = div_complex_nonzero_closure
        elif number_set == Complex:
            thm = div_complex_closure
        if thm is not None:
            return thm.instantiate({a: self.numerator, b: self.denominator})
        raise NotImplementedError(
            "'Div.deduce_in_number_set()' not implemented for the %s set" %
            str(number_set))
Example #17
0
    def derive_element_in_restricted_number_set(self, **defaults_config):
        '''
        From (element in IntervalXX(x, y)), where x ≥ 0 or y ≤ 0,
        derive that the element is in RealPos, RealNeg, RealNonPos, or
        RealNonNeg as appropriate.
        '''
        from proveit.numbers import (zero, RealPos, RealNonNeg, 
                                     RealNeg, RealNonPos)
        from proveit.numbers import Less, LessEq, greater, greater_eq        
        _a = self.domain.lower_bound
        _b = self.domain.upper_bound
        _n = self.element
        
        # We wish to deduce a fact based upon the following
        # membership fact:
        self.expr.prove()

        if (not InSet(_a, RealNonNeg).proven() and 
                not InSet(_b, RealNonPos).proven()):
            try:
                _a.deduce_in_number_set(RealNonNeg, automation=False)
            except Exception:
                pass
            try:
                _b.deduce_in_number_set(RealNonPos, automation=False)
            except Exception:
                pass
            if (not InSet(_a, RealNonNeg).proven() and 
                    not InSet(_b, RealNonPos).proven()):
                # If we don't know that a ≥ 0 or b ≤ 0, we can't prove
                # the element is in either restricted number set
                # (NaturalPos or IntegerNeg).  So, try to sort a, b, 0
                # to work this out.
                LessEq.sort([_a, _b, zero])

        if InSet(_a, RealNonNeg).proven():
            try:
                _a.deduce_in_number_set(RealPos, automation=False)
            except Exception:
                pass
            lower_bound = self.derive_element_lower_bound()
            a_bound = greater_eq(_a, zero)
            if InSet(_a, RealPos).proven():
                a_bound = greater(_a, zero)
            lower_bound.apply_transitivity(a_bound)
            if (isinstance(self, IntervalOO) 
                    or isinstance(self, IntervalOC)
                    or InSet(_a, RealPos).proven()):
                # member in R^{>0}
                return InSet(_n, RealPos).prove()
            else:
                # member in R^{≥0}
                return InSet(_n, RealNonNeg).prove()
        if InSet(_b, RealNonPos).proven():
            try:
                _b.deduce_in_number_set(RealNeg, automation=False)
            except Exception:
                pass
            upper_bound = self.derive_element_upper_bound()
            b_bound = LessEq(_b, zero)
            if InSet(_b, RealNeg).proven():
                b_bound = Less(_b, zero)                
            upper_bound.apply_transitivity(b_bound)
            if (isinstance(self, IntervalOO)
                    or isinstance(self, IntervalCO)
                    or InSet(_b, RealNeg).proven()):
                # member in R^{<0}
                return InSet(_n, RealNeg).prove()
            else:
                # member in R^{≤0}
                return InSet(_n, RealNonPos).prove()
Example #18
0
    def bound_via_operand_bound(self, operand_relation, **defaults_config):
        '''
        For simple cases, deduce a bound on this Exp object given a
        bound on its operand. For example, suppose x = Exp(y, 2) and
        we know that y >= 2. Then x.bound_via_operand_bound(y >= 2)
        returns x >= 2^2 = 4.
        This method currently works MAINLY for expressions
        of the form Exp(x, a) for non-negative real x and real exponent
        'a', where we know something of the form x < y (or x ≤ y, x > y,
        x ≥ y) involving the base of the exponential expression.
        The result also depends on knowing the relationship between the
        exponent 'a' and zero, which might need to be pre-proven or
        provided as an assumption (e.g. in the form 'a > 0' or
        InSet(a, RealNeg), etc).
        A special case also deals with a negative base raised to the
        power of 2.
        This method also works for special cases of the form Exp(a, x),
        where a > 1 and the operand_relation involve the exponent x.

        Future development will address operand_relations
        involving the exponent x in expressions of the form a^x when
        the base 0 < a < 1, and expand the special negative
        base case to include all even and odd exponent cases.
        Also see NumberOperation.deduce_bound and compare to the
        bound_via_operand_bound() method found in the Div and Neg
        classes.
        '''
        from proveit import Judgment
        from proveit.numbers import (
                two, greater, greater_eq, Less, LessEq,
                NumberOrderingRelation, RealNonNeg)
        if isinstance(operand_relation, Judgment):
            operand_relation = operand_relation.expr
        if not isinstance(operand_relation, NumberOrderingRelation):
            raise TypeError(
                    "In Exp.bound_via_operand_bound(), the "
                    "'operand_relation' argument is expected to be a number "
                    "relation (<, >, ≤, or ≥), but instead was {}.".
                    format(operand_relation))

        lhs = operand_relation.lhs
        # should be able to generalize this later
        # no need to limit to just lhs, right?
        if lhs != self.base and lhs != self.exponent:
            raise ValueError(
                    "In Exp.bound_via_operand_bound(), the left side of "
                    "the 'operand_relation' argument {0} is expected to "
                    "match either the Exp base operand {1} or the "
                    "Exp exponent operand {2}.".
                    format(operand_relation, self.base, self.exponent))

        # assign x and y subs according to std Less or LessEq relations
        _x_sub = operand_relation.normal_lhs
        _y_sub = operand_relation.normal_rhs
        if lhs == self.base:
            _a_sub = self.exponent
        else:
            _a_sub = self.base

        # I. Default case: the user-supplied operand relation involves
        #    the BASE of the Exp expression x^a
        if lhs == self.base:

            # Several cases to consider:
            #  (1) a > 0, 0 ≤ x < y
            #  (2) a > 0, 0 ≤ x ≤ y
            #  (3) a ≥ 0, 0 < x < y
            #  (4) a ≥ 0, 0 < x ≤ y
            #  (5) a < 0, 0 < x < y
            #  (6) a < 0, 0 < x ≤ y
            #  (7) a ≤ 0, 0 < x < y
            #  (8) a ≤ 0, 0 < x ≤ y
            # =====================
            #  (9) a = 2, y < x < 0
            # (10) a = 2, y ≤ x < 0

            # Cases (1) and (2): exponent a > 0
            if (greater(_a_sub, zero).proven() and
                greater_eq(_x_sub, zero).proven()):
                if isinstance(operand_relation, Less):
                    from proveit.numbers.exponentiation import exp_pos_less
                    bound = exp_pos_less.instantiate(
                            {x: _x_sub, y: _y_sub, a: _a_sub})
                elif isinstance(operand_relation, LessEq):
                    from proveit.numbers.exponentiation import exp_pos_lesseq
                    bound = exp_pos_lesseq.instantiate(
                            {x: _x_sub, y: _y_sub, a: _a_sub})
                else:
                    raise TypeError(
                        "In Exp.bound_via_operand_bound(), the 'operand_relation' "
                        "argument is expected to be a 'Less', 'LessEq', 'greater', "
                        "or 'greater_eq' relation. Instead we have {}.".
                        format(operand_relation))

            # Cases (3) and (4): exponent a ≥ 0
            elif (greater_eq(_a_sub, zero).proven() and
                greater(_x_sub, zero).proven()):
                if isinstance(operand_relation, Less):
                    from proveit.numbers.exponentiation import exp_nonneg_less
                    bound = exp_nonneg_less.instantiate(
                            {x: _x_sub, y: _y_sub, a: _a_sub})
                elif isinstance(operand_relation, LessEq):
                    from proveit.numbers.exponentiation import exp_nonneg_lesseq
                    bound = exp_nonneg_lesseq.instantiate(
                            {x: _x_sub, y: _y_sub, a: _a_sub})
                else:
                    raise TypeError(
                        "In Exp.bound_via_operand_bound(), the 'operand_relation' "
                        "argument is expected to be a 'Less', 'LessEq', 'greater', "
                        "or 'greater_eq' relation. Instead we have {}.".
                        format(operand_relation))

            # Cases (5) and (6): exponent a < 0
            elif (Less(_a_sub, zero).proven() and
                greater(_x_sub, zero).proven()):
                if isinstance(operand_relation, Less):
                    from proveit.numbers.exponentiation import exp_neg_less
                    bound = exp_neg_less.instantiate(
                            {x: _x_sub, y: _y_sub, a: _a_sub})
                elif isinstance(operand_relation, LessEq):
                    from proveit.numbers.exponentiation import exp_neg_lesseq
                    bound = exp_neg_lesseq.instantiate(
                            {x: _x_sub, y: _y_sub, a: _a_sub})
                else:
                    raise TypeError(
                        "In Exp.bound_via_operand_bound(), the 'operand_relation' "
                        "argument is expected to be a 'Less', 'LessEq', 'greater', "
                        "or 'greater_eq' relation. Instead we have {}.".
                        format(operand_relation))

            # Cases (7) and (8): exponent a ≤ 0
            elif (LessEq(_a_sub, zero).proven() and
                greater(_x_sub, zero).proven()):
                if isinstance(operand_relation, Less):
                    from proveit.numbers.exponentiation import exp_nonpos_less
                    bound = exp_nonpos_less.instantiate(
                            {x: _x_sub, y: _y_sub, a: _a_sub})
                elif isinstance(operand_relation, LessEq):
                    from proveit.numbers.exponentiation import exp_nonpos_lesseq
                    bound = exp_nonpos_lesseq.instantiate(
                            {x: _x_sub, y: _y_sub, a: _a_sub})
                else:
                    raise TypeError(
                        "In Exp.bound_via_operand_bound(), the 'operand_relation' "
                        "argument is expected to be a 'Less', 'LessEq', 'greater', "
                        "or 'greater_eq' relation. Instead we have {}.".
                        format(operand_relation))

            # Cases (9) and (10): exponent a = 2
            # with x < y < 0 or x ≤ y < 0

            elif (_a_sub == two and
                Less(_y_sub, zero).proven()):
                if isinstance(operand_relation, Less):
                    from proveit.numbers.exponentiation import (
                            exp_even_neg_base_less)
                    bound = exp_even_neg_base_less.instantiate(
                            {x: _x_sub, y: _y_sub, a: _a_sub})
                elif isinstance(operand_relation, LessEq):
                    from proveit.numbers.exponentiation import (
                            exp_even_neg_base_lesseq)
                    bound = exp_even_neg_base_lesseq.instantiate(
                            {x: _x_sub, y: _y_sub, a: _a_sub})
                else:
                    raise TypeError(
                        "In Exp.bound_via_operand_bound(), the 'operand_relation' "
                        "argument is expected to be a 'Less', 'LessEq', 'greater', "
                        "or 'greater_eq' relation. Instead we have {}.".
                        format(operand_relation))

            else:
                raise ValueError(
                        "In calling Exp.bound_via_operand_bound(), a "
                        "specific matching case was not found for {}.".
                        format(self))

        # II. 2nd main case: the user-supplied operand relation involves
        #    the EXPONENT of the Exp expression a^x
        elif lhs == self.exponent:

            # Several cases to consider (others to be developed)
            # considering the Exp expression a^x with a, x in Real:
            #  (1) a > 1, x < y
            #  (2) a > 1, x ≤ y
            #  (3) a > 1, y < x
            #  (4) a > 1, y ≤ x
            # Other cases to be developed involving base a < 1,
            # which produces a monotonically-decreasing function.

            # Cases (1)-(4): base a > 1, a^x monotonically increasing
            if (greater(_a_sub, one).proven() and
                InSet(_x_sub, Real).proven()):
                if isinstance(operand_relation, Less):
                    from proveit.numbers.exponentiation import (
                            exp_monotonicity_large_base_less)
                    bound = exp_monotonicity_large_base_less.instantiate(
                            {x: _x_sub, y: _y_sub, a: _a_sub})
                elif isinstance(operand_relation, LessEq):
                    from proveit.numbers.exponentiation import (
                        exp_monotonicity_large_base_less_eq)
                    bound = exp_monotonicity_large_base_less_eq.instantiate(
                            {x: _x_sub, y: _y_sub, a: _a_sub})
                else:
                    raise TypeError(
                        "In Exp.bound_via_operand_bound(), the 'operand_relation' "
                        "argument is expected to be a 'Less', 'LessEq', 'greater', "
                        "or 'greater_eq' relation. Instead we have {}.".
                        format(operand_relation))
            else:
                raise ValueError(
                        "In Exp.bound_via_operand_bound(), either the "
                        "base {0} is not known to be greater than 1 and/or "
                        "the operand {1} is not known to be Real.".
                        format(_a_sub, _x_sub))

        else:
            raise ValueError("OOOPS!")

        if bound.rhs == self:
            return bound.with_direction_reversed()
        return bound
Example #19
0
 def conclude(self, **defaults_config):
     if (InSet(self.element, Integer).proven()
             and Less(self.element, zero).proven()):
         return self.conclude_as_last_resort()
     return NumberMembership.conclude(self)
Example #20
0
    def bound_via_denominator_bound(self, relation, **defaults_config):
        '''
        Given a relation applicable to the numerator,  bound this
        division accordingly.  For example,
        if self is "a / b" and the relation is b > y
        return (a / b) < (a / y), provided a, b, and y are positive.

        Also see NumberOperation.deduce_bound.
        '''
        from proveit.numbers import zero, Less, LessEq, greater, greater_eq
        from . import (strong_div_from_denom_bound__all_pos,
                       weak_div_from_denom_bound__all_pos,
                       strong_div_from_denom_bound__all_neg,
                       weak_div_from_denom_bound__all_neg,
                       strong_div_from_denom_bound__neg_over_pos,
                       weak_div_from_denom_bound__neg_over_pos,
                       strong_div_from_denom_bound__pos_over_neg,
                       weak_div_from_denom_bound__pos_over_neg)
        if isinstance(relation, Judgment):
            relation = relation.expr
        if not (isinstance(relation, Less) or isinstance(relation, LessEq)):
            raise TypeError("relation is expected to be Less "
                            "or LessEq number relations, not %s" % relation)
        if self.denominator not in relation.operands:
            raise ValueError("relation is expected to involve the "
                             "denominator of %s.  %s does not." %
                             (self, relation))
        _a = self.numerator
        _x = relation.normal_lhs
        _y = relation.normal_rhs
        try:
            # Ensure that we relate both _x and _y to zero by knowing
            # one of these.
            ordering = LessEq.sort((_x, _y, zero))
            ordering.operands[0].apply_transitivity(ordering.operands[1])
        except:
            pass  # We'll generate an appropriate error below.
        try:
            deduce_number_set(self.numerator)
            deduce_number_set(self.denominator)
        except UnsatisfiedPrerequisites:
            pass
        pos_numer = greater_eq(self.numerator, zero).proven()
        neg_numer = LessEq(self.numerator, zero).proven()
        pos_denom = greater(self.denominator, zero).proven()
        neg_denom = Less(self.denominator, zero).proven()
        if not (pos_numer or neg_numer) or not (pos_denom or neg_denom):
            raise UnsatisfiedPrerequisites(
                "We must know the sign of the numerator and "
                "denominator of %s before we can use "
                "'bound_via_denominator_bound'." % self)
        if pos_numer and pos_denom:
            if isinstance(relation, Less):
                bound = strong_div_from_denom_bound__all_pos.instantiate({
                    a: _a,
                    x: _x,
                    y: _y
                })
            elif isinstance(relation, LessEq):
                bound = weak_div_from_denom_bound__all_pos.instantiate({
                    a: _a,
                    x: _x,
                    y: _y
                })
        elif neg_numer and neg_denom:
            if isinstance(relation, Less):
                bound = strong_div_from_denom_bound__all_neg.instantiate({
                    a: _a,
                    x: _x,
                    y: _y
                })
            elif isinstance(relation, LessEq):
                bound = weak_div_from_denom_bound__all_neg.instantiate({
                    a: _a,
                    x: _x,
                    y: _y
                })
        elif pos_numer and neg_denom:
            if isinstance(relation, Less):
                bound = strong_div_from_denom_bound__pos_over_neg.instantiate({
                    a:
                    _a,
                    x:
                    _x,
                    y:
                    _y
                })
            elif isinstance(relation, LessEq):
                bound = weak_div_from_denom_bound__pos_over_neg.instantiate({
                    a:
                    _a,
                    x:
                    _x,
                    y:
                    _y
                })
        elif neg_numer and pos_denom:
            if isinstance(relation, Less):
                bound = strong_div_from_denom_bound__neg_over_pos.instantiate({
                    a:
                    _a,
                    x:
                    _x,
                    y:
                    _y
                })
            elif isinstance(relation, LessEq):
                bound = weak_div_from_denom_bound__neg_over_pos.instantiate({
                    a:
                    _a,
                    x:
                    _x,
                    y:
                    _y
                })
        else:
            raise UnsatisfiedPrerequisites(
                "We must know whether or not the denominator of %s "
                "is positive or negative before we can use "
                "'bound_via_denominator_bound'." % self)
        if bound.rhs == self:
            return bound.with_direction_reversed()
        return bound