Exemplo n.º 1
0
 def deduce_number_set(self, **defaults_config):
     '''
     Prove membership of this expression in the most
     restrictive standard number set we can readily know.
     '''
     base_ns = deduce_number_set(self.base).domain
     exp_ns = deduce_number_set(self.exponent).domain
     if Natural.includes(base_ns) and Natural.includes(exp_ns):
         return self.deduce_in_number_set(NaturalPos)
     if Integer.includes(base_ns) and Natural.includes(exp_ns):
         return self.deduce_in_number_set(Integer)
     if RationalPos.includes(base_ns) and Integer.includes(exp_ns):
         return self.deduce_in_number_set(RationalPos)
     if (RationalNonZero.includes(base_ns)
             and Integer.includes(exp_ns)):
         return self.deduce_in_number_set(RationalNonZero)
     if Rational.includes(base_ns) and Natural.includes(exp_ns):
         return self.deduce_in_number_set(Rational)
     if RealPos.includes(base_ns) and Real.includes(exp_ns):
         return self.deduce_in_number_set(RealPos)
     if RealNonNeg.includes(base_ns) and Real.includes(exp_ns):
         return self.deduce_in_number_set(RealNonNeg)
     if Real.includes(base_ns) and Natural.includes(exp_ns):
         return self.deduce_in_number_set(Real)
     if ComplexNonZero.includes(base_ns):
         return self.deduce_in_number_set(ComplexNonZero)
     return self.deduce_in_number_set(Complex)
Exemplo n.º 2
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
Exemplo n.º 3
0
 def shallow_simplification(self, *, must_evaluate=False,
                            **defaults_config):
     '''
     Returns a proven simplification equation for this Mod
     expression assuming the operands have been simplified.
     
     Specifically, performs reductions of the form
     (x mod L) = x where applicable and
     [(a mod L + b) mod L] = [(a + b) mod L].
     '''
     from . import (int_mod_elimination, real_mod_elimination,
                    redundant_mod_elimination, 
                    redundant_mod_elimination_in_sum)
     from proveit.numbers import (
         NaturalPos, RealPos, Interval, IntervalCO, subtract, zero, one)
     deduce_number_set(self.dividend)
     divisor_ns = deduce_number_set(self.divisor).domain
     if (NaturalPos.includes(divisor_ns) and 
             InSet(self.dividend, 
                   Interval(zero, 
                            subtract(self.divisor, one))).proven()):
         # (x mod L) = x if L in N+ and x in {0 .. L-1}
         return int_mod_elimination.instantiate(
             {x:self.dividend, L:self.divisor})
     if (RealPos.includes(divisor_ns) and 
             InSet(self.dividend, 
                   IntervalCO(zero, self.divisor)).proven()):
         # (x mod L) = x if L in R+ and x in [0, L)
         return real_mod_elimination.instantiate(
             {x:self.dividend, L:self.divisor})
     return Mod._redundant_mod_elimination(
             self, redundant_mod_elimination, 
             redundant_mod_elimination_in_sum)
Exemplo n.º 4
0
 def conclude(self, **defaults_config):
     '''
     Conclude something of the form 
     a < b.
     '''
     from proveit.logic import InSet
     from proveit.numbers import Add, zero, RealPos, deduce_number_set
     from . import positive_if_real_pos
     if self.upper == zero:
         # Special case with upper bound of zero.
         from . import negative_if_real_neg
         concluded = negative_if_real_neg.instantiate({a: self.lower})
         return concluded
     if self.lower == zero:
         # Special case with lower bound of zero.
         deduce_number_set(self.upper)
         if InSet(self.upper, RealPos).proven():
             positive_if_real_pos.instantiate({a: self.upper})
     if ((isinstance(self.lower, Add)
          and self.upper in self.lower.terms.entries)
             or (isinstance(self.upper, Add)
                 and self.lower in self.upper.terms.entries)):
         try:
             # Conclude an sum is bounded by one of its terms.
             return self.conclude_as_bounded_by_term()
         except UnsatisfiedPrerequisites:
             # If prerequisites weren't satisfied to do this,
             # we can still try something else.
             pass
     return NumberOrderingRelation.conclude(self)
Exemplo n.º 5
0
    def deduce_in_number_set(self, number_set, **defaults_config):
        '''
        Attempt to prove that the logarithmic expression 'self' is
        in the given number set 'number_set'. May require user to
        previously show or assume that the Log base is not 1.
        Currently implemented only for the general case, giving
        Log_a(b) in Real when 'a' and 'b' both in RealPos and 'a' != 1.
        This can be augmented in near future.
        '''
        from proveit import a, b
        from proveit.logic import InSet, NotEquals
        from proveit.numbers.logarithms import log_real_pos_real_closure

        from proveit.numbers import zero, Real

        deduce_number_set(self.base)
        deduce_number_set(self.antilog)
        if number_set == Real:
            return log_real_pos_real_closure.instantiate({
                a: self.base,
                b: self.antilog
            })

        # we can do more/better but that's enough for right now

        raise NotImplementedError(
            "'Log.deduce_in_number_set()' not implemented for the "
            " number set {0}. Try deducing in Real instead?".format(
                number_set))
Exemplo n.º 6
0
    def deduce_linear_bound(self, **defaults_config):
        '''
        Bound the Sin function evaluation by a line.
        '''
        from . import (sine_linear_bound, sine_linear_bound_pos,
                       sine_linear_bound_nonneg, sine_linear_bound_neg,
                       sine_linear_bound_nonpos)

        deduce_number_set(self.angle)

        if isinstance(self.angle, Abs):
            bound = sine_linear_bound.instantiate({theta: self.angle.operand})
        elif InSet(self.angle, RealPos).proven():
            bound = sine_linear_bound_pos.instantiate({theta: self.angle})
        elif InSet(self.angle, RealNeg).proven():
            bound = sine_linear_bound_neg.instantiate({theta: self.angle})
        elif InSet(self.angle, RealNonNeg).proven():
            bound = sine_linear_bound_nonneg.instantiate({theta: self.angle})
        elif InSet(self.angle, RealNonPos).proven():
            bound = sine_linear_bound_nonpos.instantiate({theta: self.angle})
        else:
            _theta = Abs(self.angle)
            bound = sine_linear_bound.instantiate({theta: _theta})
        if bound.rhs == self:
            return bound.with_direction_reversed()
        return bound
Exemplo n.º 7
0
 def deduce_number_set(self, **defaults_config):
     '''
     Prove membership of this expression in the most
     restrictive standard number set we can readily know.
     '''
     numer_ns = deduce_number_set(self.numerator).domain
     denom_ns = deduce_number_set(self.denominator).domain
     if RationalPos.includes(numer_ns) and RationalPos.includes(denom_ns):
         return self.deduce_in_number_set(RationalPos)
     if RationalNeg.includes(numer_ns) and RationalNeg.includes(denom_ns):
         return self.deduce_in_number_set(RationalPos)
     if RationalNeg.includes(numer_ns) and RationalPos.includes(denom_ns):
         return self.deduce_in_number_set(RationalNeg)
     if RationalPos.includes(numer_ns) and RationalNeg.includes(denom_ns):
         return self.deduce_in_number_set(RationalNeg)
     if (RationalNonNeg.includes(numer_ns)
             and RationalPos.includes(denom_ns)):
         return self.deduce_in_number_set(RationalNonNeg)
     if (RationalNonPos.includes(numer_ns)
             and RationalPos.includes(denom_ns)):
         return self.deduce_in_number_set(RationalNonPos)
     if (RationalNonNeg.includes(numer_ns)
             and RationalNeg.includes(denom_ns)):
         return self.deduce_in_number_set(RationalNonPos)
     if (RationalNonPos.includes(numer_ns)
             and RationalNeg.includes(denom_ns)):
         return self.deduce_in_number_set(RationalNonNeg)
     if (RationalNonZero.includes(numer_ns)
             and RationalNonZero.includes(denom_ns)):
         return self.deduce_in_number_set(RationalNonZero)
     if Rational.includes(numer_ns) and RationalNonZero.includes(denom_ns):
         return self.deduce_in_number_set(Rational)
     if RealPos.includes(numer_ns) and RealPos.includes(denom_ns):
         return self.deduce_in_number_set(RealPos)
     if RealNeg.includes(numer_ns) and RealNeg.includes(denom_ns):
         return self.deduce_in_number_set(RealPos)
     if RealPos.includes(numer_ns) and RealNeg.includes(denom_ns):
         return self.deduce_in_number_set(RealNeg)
     if RealNeg.includes(numer_ns) and RealPos.includes(denom_ns):
         return self.deduce_in_number_set(RealNeg)
     if RealNonNeg.includes(numer_ns) and RealPos.includes(denom_ns):
         return self.deduce_in_number_set(RealNonNeg)
     if RealNonPos.includes(numer_ns) and RealPos.includes(denom_ns):
         return self.deduce_in_number_set(RealNonPos)
     if RealNonNeg.includes(numer_ns) and RealNeg.includes(denom_ns):
         return self.deduce_in_number_set(RealNonPos)
     if RealNonPos.includes(numer_ns) and RealNeg.includes(denom_ns):
         return self.deduce_in_number_set(RealNonNeg)
     if Real.includes(numer_ns) and RealNonZero.includes(denom_ns):
         return self.deduce_in_number_set(Real)
     if RealNonZero.includes(numer_ns) and RealNonZero.includes(denom_ns):
         return self.deduce_in_number_set(RealNonZero)
     if Real.includes(numer_ns) and RealNonZero.includes(denom_ns):
         return self.deduce_in_number_set(Real)
     if (ComplexNonZero.includes(numer_ns)
             and ComplexNonZero.includes(denom_ns)):
         return self.deduce_in_number_set(ComplexNonZero)
     return self.deduce_in_number_set(Complex)
Exemplo n.º 8
0
 def deduce_number_set(self, **defaults_config):
     '''
     Prove membership of this expression in the most
     restrictive standard number set we can readily know.
     '''
     value_ns = deduce_number_set(self.value).domain
     divisor_ns = deduce_number_set(self.divisor).domain
     if (value_ns.includes(Integer) and divisor_ns.includes(Integer)):
         return self.deduce_in_number_set(Integer)
     else:
         return self.deduce_in_number_set(Real)
Exemplo n.º 9
0
 def deduce_number_set(self, **defaults_config):
     from proveit.numbers import deduce_number_set, greater
     _a = self.digits[0]
     _b = self.digits[1:]
     try:
         deduce_number_set(_a)
     except UnsatisfiedPrerequisites:
         pass
     if greater(_a, zero).proven():
         return self.deduce_in_natural_pos()
     else:
         return self.deduce_in_natural()
Exemplo n.º 10
0
 def deduce_number_set(self, **defaults_config):
     '''
     Prove membership of this Log expression in the most
     restrictive standard number set we can readily know.
     Currently just implemented for Reals, but should be able
     to augment this to allow more precise placement in
     RealPos vs. RealNeg for suitable base/antilog combinations.
     '''
     from proveit.numbers import Real, RealPos, Complex
     base_ns = deduce_number_set(self.base).domain
     antilog_ns = deduce_number_set(self.antilog).domain
     if RealPos.includes(base_ns) and RealPos.includes(antilog_ns):
         return self.deduce_in_number_set(Real)
     return self.deduce_in_number_set(Complex)
Exemplo n.º 11
0
 def deduce_number_set(self, **defaults_config):
     '''
     Prove membership of this expression in the most
     restrictive standard number set we can readily know.
     '''
     number_set_map = {
         NaturalPos: IntegerNeg,
         IntegerNeg: NaturalPos,
         Natural: IntegerNonPos,
         IntegerNonPos: Natural,
         IntegerNonZero: IntegerNonZero,
         Integer: Integer,
         RationalPos: RationalNeg,
         RationalNeg: RationalPos,
         RationalNonNeg: RationalNonPos,
         RationalNonPos: RationalNonNeg,
         RationalNonZero: RationalNonZero,
         Rational: Rational,
         RealPos: RealNeg,
         RealNeg: RealPos,
         RealNonNeg: RealNonPos,
         RealNonPos: RealNonNeg,
         RealNonZero: RealNonZero,
         Real: Real,
         ComplexNonZero: ComplexNonZero,
         Complex: Complex
     }
     operand_ns = deduce_number_set(self.operand).domain
     # check if operand_ns is not a standard number set
     if operand_ns not in number_set_map.keys():
         # try to replace term_ns with a std number set
         operand_ns = standard_number_set(operand_ns)
     return self.deduce_in_number_set(number_set_map[operand_ns])
Exemplo n.º 12
0
    def side_effects(self, judgment):
        '''
        In addition to the TransitiveRelation side-effects, also
        attempt (where applicable) eliminate_dividen_exponent,
        eliminate_common_exponent, and eliminate_common_factor.
        '''
        from proveit.numbers import two, Exp, Mult

        for side_effect in TransitiveRelation.side_effects(self, judgment):
            yield side_effect

        # For each of the following, use the default assumptions to
        # verify some conditions before yielding the side effect method
        # (i.e. check using .proven() without arguments)

        # for 2|(b^n), derive 2|b.
        # (can be generalized to any prime number).
        if self.lhs == two and isinstance(self.rhs, Exp):
            try:
                deduce_number_set(self.rhs.base)
                deduce_number_set(self.rhs.exponent)
            except UnsatisfiedPrerequisites:
                pass
            if (InSet(self.rhs.base, Integer).proven()
                    and InSet(self.rhs.exponent, Integer).proven()):
                yield self.eliminate_dividend_exponent

        # for (a^n)|(b^n)
        if (isinstance(self.rhs, Exp) and isinstance(self.lhs, Exp)
                and self.lhs.exponent == self.rhs.exponent):
            try:
                deduce_number_set(self.lhs.base)
                deduce_number_set(self.rhs.base)
                deduce_number_set(self.lhs.exponent)
            except UnsatisfiedPrerequisites:
                pass
            if (InSet(self.lhs.base, Integer).proven()
                    and InSet(self.rhs.base, Integer).proven()
                    and InSet(self.lhs.exponent, NaturalPos).proven()):
                yield self.eliminate_common_exponent

        # for (ka)|(kb)
        if (isinstance(self.lhs, Mult) and isinstance(self.rhs, Mult)):
            operands_intersection = (set(self.lhs.operands).intersection(
                set(self.lhs.operands)))
            if (len(operands_intersection) > 0):
                yield self.eliminate_common_factors
Exemplo n.º 13
0
 def deduce_number_set(self, **defaults_config):
     '''
     Prove membership of this expression in the most 
     restrictive standard number set we can readily know.
     '''
     summand_ns = deduce_number_set(self.summand,
                                    assumptions=self.conditions).domain
     return self.deduce_in_number_set(summand_ns)
Exemplo n.º 14
0
 def deduce_not_zero(self, **defaults_config):
     '''
     Prove that this exponential is not zero given that
     the base is not zero.
     '''
     from proveit.logic import InSet
     from proveit.numbers import RationalPos
     from . import exp_rational_non_zero__not_zero, exp_not_eq_zero
     deduce_number_set(self.base)
     deduce_number_set(self.exponent)
     if (not exp_not_eq_zero.is_usable() or (
             InSet(self.base, RationalPos).proven() and
             InSet(self.exponent, RationalPos).proven())):
         # Special case where the base and exponent are RationalPos.
         return exp_rational_non_zero__not_zero.instantiate(
             {a: self.base, b: self.exponent})
     return exp_not_eq_zero.instantiate(
         {a: self.base, b: self.exponent})
Exemplo n.º 15
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)
Exemplo n.º 16
0
def rounding_deduce_number_set(expr):
    '''
    Prove membership of this expression in the most 
    restrictive standard number set we can readily know.
    '''
    from proveit.numbers import RealPos, Natural, Integer
    operand_ns = deduce_number_set(expr.operand).domain
    if RealPos.includes(operand_ns):
        return expr.deduce_in_number_set(Natural)
    return expr.deduce_in_number_set(Integer)
Exemplo n.º 17
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)
Exemplo n.º 18
0
    def eliminate_common_exponent(self, **defaults_config):
        '''
        From self of the form (k^n)|(a^n), derive and return k|a.
        k, a, must be integers, with n a positive integer. This method
        is called from the DividesRelation side_effects() method.
        '''
        from proveit.numbers import Exp
        if (isinstance(self.lhs, Exp) and isinstance(self.rhs, Exp)
                and self.lhs.exponent == self.rhs.exponent):

            k = self.lhs.base
            a = self.rhs.base
            n = self.lhs.exponent
            try:
                for _expr in (k, a, n):
                    deduce_number_set(_expr)
            except UnsatisfiedPrerequisites:
                pass
            if (InSet(k, Integer).proven() and InSet(a, Integer).proven()
                    and InSet(n, NaturalPos).proven()):

                from . import common_exponent_elimination
                _k, _a, _n = common_exponent_elimination.instance_params
                return common_exponent_elimination.instantiate({
                    _k: k,
                    _a: a,
                    _n: n
                })
            else:
                err_msg = ("In using Divides.eliminate_common_exponent(), "
                           "the exponent ({0}) must already be known to be "
                           "a positive natural and each base ({1}, {2}) "
                           "must already been know to be an integer.".format(
                               n, k, a))
        else:
            err_msg = (
                "In using Divides.eliminate_common_exponent(), "
                "the lhs {0} and rhs {1} must both be exponential.".format(
                    self.lhs, self.rhs))

        raise ValueError(err_msg)
Exemplo n.º 19
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})
Exemplo n.º 20
0
 def deduce_in_interval(self, **defaults_config):
     '''
     Prove that the "x mod b" is in the interval [0, b).
     '''
     from . import (mod_in_interval, mod_natpos_in_interval,
                    mod_in_interval_c_o)
     from proveit.numbers import Integer, NaturalPos
     # from number_sets import deduce_in_integer, deduce_in_real
     dividend_ns = deduce_number_set(self.dividend).domain
     divisor_ns = deduce_number_set(self.divisor).domain
     int_dividend = Integer.includes(dividend_ns)
     if (int_dividend and NaturalPos.includes(divisor_ns)):
         return mod_natpos_in_interval.instantiate(
             {a: self.dividend, b: self.divisor})
     elif (int_dividend and Integer.includes(divisor_ns)):
         # if the operands are integers, then we can deduce that
         # a mod b is an integer in the set {0,1,...,(b-1)}
         return mod_in_interval.instantiate(
             {a: self.dividend, b: self.divisor})
     else:
         # if the operands are reals, then we can deduce that
         # a mod b is in half-open real interval [0, b)
         return mod_in_interval_c_o.instantiate(
             {a: self.dividend, b: self.divisor})
Exemplo n.º 21
0
 def deduce_number_set(self, **defaults_config):
     '''
     Prove membership of this expression in the most
     restrictive standard number set we can readily know.
     After deriving a candidate super set that contains the
     number set deduced for each argument, the fxn then calls
     the self.deduce_in_number_set() fxn defined above.
     '''
     list_of_operand_sets = []
     # find a minimal std number set for operand
     for operand in self.operands:
         operand_ns = deduce_number_set(operand).domain
         list_of_operand_sets.append(operand_ns)
     # merge the resulting list of std number sets into a
     # single superset, if possible
     minimal_super_set = merge_list_of_sets(list_of_operand_sets)
     return self.deduce_in_number_set(minimal_super_set)
Exemplo n.º 22
0
 def deduce_number_set(self, **defaults_config):
     '''
     Prove membership of this expression in the most
     restrictive standard number set we can readily know.
     '''
     from proveit.numbers import (Integer, IntegerNonZero, NaturalPos,
                                  Natural, Rational, RationalNonZero,
                                  RationalPos, RationalNonNeg, Real,
                                  RealNonNeg, RealPos, ComplexNonZero,
                                  Complex)
     operand_ns = deduce_number_set(self.operand).domain
     if IntegerNonZero.includes(operand_ns):
         return self.deduce_in_number_set(NaturalPos)
     if Integer.includes(operand_ns):
         return self.deduce_in_number_set(Natural)
     if RationalNonZero.includes(operand_ns):
         return self.deduce_in_number_set(RationalPos)
     if Rational.includes(operand_ns):
         return self.deduce_in_number_set(RationalNonNeg)
     if ComplexNonZero.includes(operand_ns):
         return self.deduce_in_number_set(RealPos)
     return self.deduce_in_number_set(RealNonNeg)
Exemplo n.º 23
0
def rounding_deduce_in_number_set(expr, number_set, rounding_real_closure_thm,
                                  rounding_real_pos_closure_thm):
    '''
    Given a number set number_set, attempt to prove that the given
    Ceil, Floor, or Round expression is in that number set using
    the appropriate closure theorem.
    '''
    from proveit import x
    from proveit.numbers import Integer, Natural, Real

    if number_set == Natural:
        return rounding_real_pos_closure_thm.instantiate({x: expr.operand})

    operand_ns = deduce_number_set(expr.operand).domain
    if number_set.includes(Integer) and Real.includes(operand_ns):
        int_membership = rounding_real_closure_thm.instantiate(
            {x: expr.operand})
        if number_set == Integer:
            return int_membership
        return SubsetEq(Integer, number_set).derive_superset_membership(expr)

    raise NotImplementedError(
        "The rounding_methods.py function 'rounding_deduce_in_number_set()'"
        "is not implemented for the %s set" % str(number_set))
Exemplo n.º 24
0
    def shallow_simplification(self,
                               *,
                               must_evaluate=False,
                               **defaults_config):
        '''
        Returns a proven simplification equation for this Abs
        expression assuming the operand has been simplified.
        
        Handles a number of absolute value simplifications:
            1. ||x|| = |x| given x is complex
            2. |x| = x given x ≥ 0
            3. |x| = -x given x ≤ 0
                             (may try to prove this if easy to do)
            4. |-x| = |x|
            5. |x_1 * ... * x_n| = |x_1| * ... * |x_n|
            6. |a / b| = |a| / |b|
            7. |exp(i a)| = 1 given a in Real
            8. |r exp(i a) - r exp(i b)| = 2 r sin(|a - b|/2)
                given a and b in Real.
            9. |x_1 + ... + x_n| = +/-(x_1 + ... + x_n) if
               the terms are known to be all non-negative
               or all non-positive.
        '''
        from proveit.logic import Equals
        from proveit.numbers import e, Add, Neg, LessEq, Mult, Div, Exp
        from proveit.numbers import zero, RealNonNeg, RealNonPos
        from proveit.logic import EvaluationError, is_irreducible_value

        if is_irreducible_value(self.operand):
            if isinstance(self.operand, Neg):
                # |-x| where 'x' is a literal.
                return self.distribution()
            else:
                # If the operand is irreducible, we can just use
                # abs_elimination.
                return self.abs_elimination()
        elif must_evaluate:
            # The simplification of the operands may not have
            # worked hard enough.  Let's work harder if we
            # must evaluate.
            self.operand.evaluation()
            return self.evaluation()

        # among other things, convert any assumptions=None
        # to assumptions=() (thus averting len(None) errors)

        # Check if we have an established relationship between
        # self.operand and zero.
        try:
            deduce_number_set(self.operand)
        except UnsatisfiedPrerequisites:
            pass
        if (LessEq(zero, self.operand).proven()
                or LessEq(self.operand, zero).proven()):
            # Either |x| = x or |x| = -x depending upon the sign
            # of x (comparison with zero).
            return self.abs_elimination()

        if isinstance(self.operand, Abs):
            # Double absolute-value.  We can remove one of them.
            return self.double_abs_elimination()

        # Distribute over a product or division.
        if (isinstance(self.operand, Mult) or isinstance(self.operand, Div)
                or isinstance(self.operand, Neg)):
            # Let's distribute the absolute values over the product
            # or division (the absolute value of the factors/components
            # will be simplified seperately if auto_simplify is True).
            return self.distribution()

        # |exp(i a)| = 1
        if isinstance(self.operand, Exp) and self.operand.base == e:
            try:
                return self.unit_length_simplification()
            except ValueError:
                # Not in a complex polar form.
                pass

        # |r exp(i a) - r exp(i b)| = 2 r sin(|a - b|/2)
        if (isinstance(self.operand, Add)
                and self.operand.operands.is_double()):
            try:
                return self.chord_length_simplification()
            except (ProofFailure, ValueError):
                # Not in a complex polar form.
                pass

        # |x_1 + ... + x_n| = +/-(x_1 + ... + x_n)
        # if the terms are known to be all non-negative or all
        # non-positive.
        if isinstance(self.operand, Add):
            all_nonneg = True
            all_nonpos = True
            for term in self.operand.terms:
                # Note that "not proven" is not the same as "disproven".
                # Not proven means there is something we do not know.
                # Disproven means that we do know the converse.
                if all_nonneg and not LessEq(zero, term).proven():
                    all_nonneg = False
                if all_nonpos and not LessEq(term, zero).proven():
                    all_nonpos = False
            if all_nonpos:
                InSet(self.operand, RealNonPos).prove()
            elif all_nonneg:
                InSet(self.operand, RealNonNeg).prove()
            if all_nonpos or all_nonneg:
                # Do another pass now that we know the sign of
                # the operand.
                return self.shallow_simplification()

        # Default is no simplification.
        return Equals(self, self).prove()
Exemplo n.º 25
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
Exemplo n.º 26
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
Exemplo n.º 27
0
    def conclude(self, **defaults_config):
        '''
        Attempt to conclude the divisibility claim in various ways:
        (1) simple reflexivity (x|x);
        (2) simple x|0 for x ≠ 0;
        (3) simple x|xy or x|yx scenario
        (4) x^n | y^n if x|y is known or assumed
        (5) x|y if (x^n)|(y^n) is known or assumed
        (6) via transitivity.
        '''
        from proveit.numbers import Exp

        #-- -------------------------------------------------------- --#
        #-- Case (1): x|x with x != 0 known or assumed               --#
        #-- -------------------------------------------------------- --#
        from proveit.logic import InSet, NotEquals
        from proveit.numbers import zero, Complex
        err_str = "In Divides.conclude() we tried:\n"
        try:
            deduce_number_set(self.lhs)
        except UnsatisfiedPrerequisites:
            pass
        if self.lhs == self.rhs:
            if (NotEquals(self.lhs, zero).proven()
                    and InSet(self.lhs, Complex).proven()):
                # Trivial x|x with complex x ≠ 0
                return self.conclude_via_reflexivity()
            else:
                err_str = err_str + (
                    "Case: lhs = rhs. "
                    "Although lhs = rhs = {0}, either {0} is not known to "
                    "be non-zero or {0} is not known to be in the complex "
                    "numbers (or both). Try proving one or both of those "
                    "claims first.\n".format(self.lhs))
                # raise ProofFailure(self, assumptions, err_str)

        #-- -------------------------------------------------------- --#
        #-- Case (2): x|0 with x != 0 known or assumed               --#
        #-- -------------------------------------------------------- --#
        if self.rhs == zero:
            if (NotEquals(self.lhs, zero).proven()
                    and InSet(self.lhs, Complex).proven()):
                # We have 0/x with complex x ≠ 0
                return self.conclude_via_zero_factor()
            else:
                err_str = err_str + (
                    "Case: rhs = 0. "
                    "Although rhs = 0, either the lhs {0} is not known to "
                    "be non-zero or {0} is not known to be in the complex "
                    "numbers (or both). Try proving one or both of those "
                    "claims first.\n".format(self.lhs))

        #-- -------------------------------------------------------- --#
        #-- Case (3): very simple version of x|xy or x|yx            --#
        #-- -------------------------------------------------------- --#
        # return self.conclude_via_factor(assumptions)
        try:
            return self.conclude_via_factor()
        except Exception as e:
            err_str = err_str + (
                "Case: x|xy. This possible case returned the following "
                "error message: {0} \n".format(e))
            pass

        #-- -------------------------------------------------------- --#
        #-- Case (4): x^n|y^n if x|y                                 --#
        #-- -------------------------------------------------------- --#
        if (isinstance(self.lhs, Exp) and isinstance(self.rhs, Exp)
                and Equals(self.lhs.exponent, self.rhs.exponent)
                and Divides(self.lhs.base, self.rhs.base).proven()):
            try:
                deduce_number_set(self.lhs.base)
                deduce_number_set(self.rhs.base)
                deduce_number_set(self.lhs.exponent)
            except UnsatisfiedPrerequisites:
                pass

            if (InSet(self.lhs.base, Integer).proven()
                    and InSet(self.rhs.base, Integer).proven()
                    and InSet(self.lhs.exponent, NaturalPos).proven()):
                return (Divides(self.lhs.base,
                                self.rhs.base).introduce_common_exponent(
                                    self.lhs.exponent))

            else:
                err_str = err_str + (
                    "Case: (x^n) | (y^n). One or more of the conditions "
                    "(such as domain requirements or x|y) were not "
                    "already proven. Check the conditions for the "
                    "common_exponent_introduction theorem in the "
                    "number/divisibility package.\n")

        else:
            err_str = err_str + (
                "Case: (x^n) | (y^n). Does not appear applicable.\n")
        """
        # This case should be handled on the "side-effect" end.

        #-- -------------------------------------------------------- --#
        #-- Case (5): x|y if x^n|y^n (for some small pos nat n)      --#
        #-- -------------------------------------------------------- --#
        possible_exps = range(2,10)
        for e in possible_exps:
            # print("exp = {}".format(e))
            if (Divides(Exp(self.lhs, num(e)), Exp(self.rhs, num(e))).
                proven(assumptions)):
                # print("    Divides found for exp = {}".format(test_exp))
                return (Divides(Exp(self.lhs, test_exp),
                                Exp(self.rhs, test_exp)).
                        eliminate_common_exponent(assumptions=assumptions))

        err_str = err_str + (
                "Case: x|y where we already have (x^n)|(y^n). "
                "Does not appear applicable.\n")
        """

        #-- -------------------------------------------------------- --#
        #-- Case (6): x|z with x|y and y|z known or assumed          --#
        #-- -------------------------------------------------------- --#
        # Seek out the appropriate x|y and y|z and use transitivity
        # to get x|z, utilizing the conclude_via_transitivity() method
        # available for instances of TransitiveRelation
        try:
            return self.conclude_via_transitivity()
        except Exception as e:
            err_str = err_str + (
                "Case: transitivity search. In attempting to use "
                "conclude_via_transitivity(), obtained the following "
                "error message: {0}.".format(e))
            pass

        raise ProofFailure(self, defaults.assumptions, err_str)
Exemplo n.º 28
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))
Exemplo n.º 29
0
    def eliminate_common_factors(self, **defaults_config):
        '''
        Eliminate all factors in common between the divisor and the
        dividend.  For example, from (k a)|(k b), derive and return a|b.
        k must be a non-zero complex number.
        '''
        from . import common_factor_elimination
        from proveit.numbers import Mult, one
        if self.lhs == self.rhs:
            # From x | x return 1 | 1.  It's vacuous, but whatever.
            return Divides(one, one).prove()
        elif (isinstance(self.lhs, Mult) and isinstance(self.rhs, Mult)):

            # Handle the basic case in which the divisor and
            # the dividend are each the product of two factors and
            # the first of these is in common between them.
            if (self.lhs.operands.is_double()
                    and self.rhs.operands.is_double()):
                lhs1 = self.lhs.operands[0]
                lhs2 = self.lhs.operands[1]
                rhs1 = self.rhs.operands[0]
                rhs2 = self.rhs.operands[1]
                deduce_number_set(lhs1)

                if (lhs1 == rhs1 and InSet(lhs1, Complex).proven()
                        and NotEquals(lhs1, zero).proven()):
                    return common_factor_elimination.instantiate({
                        a: lhs2,
                        b: rhs2,
                        k: lhs1
                    })

            # Try to convert it to the basic case via factorization
            # and try again.
            rhs_factors = set(self.rhs.operands.entries)
            common_factors = [
                factor for factor in self.lhs.factors if factor in rhs_factors
            ]
            # Pull the common factors out to the front.
            if len(common_factors) == 0:
                return self.prove()  # No common factors to eliminate.
            lhs_factorization = self.lhs.factorization(common_factors,
                                                       pull='left',
                                                       group_factors=True,
                                                       group_remainder=True,
                                                       preserve_all=True)
            rhs_factorization = self.rhs.factorization(common_factors,
                                                       pull='left',
                                                       group_factors=True,
                                                       group_remainder=True,
                                                       preserve_all=True)
            # Prove this "divides" but the substitute factorized forms.
            divides_proof = self.prove()
            if lhs_factorization.lhs != lhs_factorization.rhs:
                divides_proof = lhs_factorization.sub_right_side_into(
                    divides_proof)
            if rhs_factorization.lhs != rhs_factorization.rhs:
                divides_proof = rhs_factorization.sub_right_side_into(
                    divides_proof)
            lhs1, lhs2 = lhs_factorization.rhs.operands
            rhs1, rhs2 = rhs_factorization.rhs.operands
            return common_factor_elimination.instantiate({
                a: lhs2,
                b: rhs2,
                k: lhs1
            })
        elif isinstance(self.lhs, Mult) and self.rhs in self.lhs.factors:
            # From (k z) | k return z | 1.  Why not?
            dividend = Mult(self.rhs, one)
            divides = Divides(self.lhs, dividend)
            divides_proof = divides.eliminate_common_factors()
            return divides_proof.inner_expr().lhs.dividend.one_elimination(1)
        elif isinstance(self.rhs, Mult) and self.lhs in self.rhs.factors:
            # From (k z) | k return z | 1.  Why not?
            divisor = Mult(self.lhs, one)
            divides = Divides(divisor, self.rhs)
            divides_proof = divides.eliminate_common_factors()
            return divides_proof.inner_expr().lhs.divisor.one_elimination(1)

        # There are no common factors.
        return self.prove()
Exemplo n.º 30
0
    def exponent_combination(self,
                             start_idx=None,
                             end_idx=None,
                             **defaults_config):
        '''
        Equates $a^m/a^n$ to $a^{m-n} or
        $a^c/b^c$ to $(a/b)^c$.
        '''
        from proveit.logic import InSet
        from proveit.numbers import Exp
        from proveit.numbers.exponentiation import (quotient_of_posnat_powers,
                                                    quotient_of_pos_powers,
                                                    quotient_of_real_powers,
                                                    quotient_of_complex_powers)
        if (isinstance(self.numerator, Exp)
                and isinstance(self.denominator, Exp)):
            if self.numerator.base == self.denominator.base:
                # Same base: (a^b/a^c) = a^{b-c}
                same_base = self.numerator.bas
                exponents = (self.numerator.exponent,
                             self.denominator.exponent)
                # Find out the known type of the exponents.
                possible_exponent_types = [NaturalPos, RealPos, Real, Complex]
                for exponent in exponents:
                    deduce_number_set(exponent)
                    while len(possible_exponent_types) > 1:
                        exponent_type = possible_exponent_types[0]
                        if InSet(exponent, exponent_type).proven():
                            # This type is known for this exponent.
                            break
                        # We've eliminated a type from being known.
                        possible_exponent_types.pop(0)
                known_exponent_type = possible_exponent_types[0]

                if known_exponent_type == NaturalPos:
                    _m, _n = exponents
                    return quotient_of_posnat_powers.instantiate({
                        a: same_base,
                        m: _m,
                        n: _n
                    })
                else:
                    _b, _c = exponents
                    if known_exponent_type == RealPos:
                        thm = quotient_of_pos_powers
                    elif known_exponent_type == Real:
                        thm = quotient_of_real_powers
                    else:  # Complex is the default
                        thm = quotient_of_complex_powers
                    thm.instantiate({a: same_base, b: _b, c: _c})

            elif self.numerator.exponent == self.denominator.exponent:
                # Same exponent: (a^c/b^c) = (a/b)^c
                same_exponent = self.numerator.exponent
                bases = (self.numerator.base, self.denominator.base)
                # Combining the exponents in this case is the reverse
                # of disibuting an exponent.
                quotient = Div(*bases).with_matching_style(self)
                exp = Exp(quotient, same_exponent)
                return exp.distribution().derive_reversed()
        else:
            raise NotImplementedError("Need to implement degenerate cases "
                                      "of a^b/a and a/a^b.")