示例#1
0
 def empty_range(_i, _j, _f, assumptions):
     # If the start and end are literal ints and form an
     # empty range, then it should be straightforward to
     # prove that the range is empty.
     from proveit.numbers import is_literal_int, Add
     from proveit.logic import Equals
     from proveit import m
     _m = entries[0].start_index
     _n = entries[0].end_index
     empty_req = Equals(Add(_n, one), _m)
     if is_literal_int(_m) and is_literal_int(_n):
         if _n.as_int() + 1 == _m.as_int():
             empty_req.prove()
     if empty_req.proven(assumptions):
         _f = Lambda(
             (entries[0].parameter, entries[0].body.parameter),
             entries[0].body.body)
         _i = entry_map(_i)
         _j = entry_map(_j)
         return len_of_empty_range_of_ranges.instantiate(
             {
                 m: _m,
                 n: _n,
                 f: _f,
                 i: _i,
                 j: _j
             },
             assumptions=assumptions)
示例#2
0
 def conclude(self, assumptions=USE_DEFAULTS):
     '''
     Attempt to conclude that the element is in the exponentiated set.
     '''
     from proveit.logic import InSet
     from proveit.logic.sets.membership import (exp_set_0, exp_set_1,
                                                exp_set_2, exp_set_3,
                                                exp_set_4, exp_set_5,
                                                exp_set_6, exp_set_7,
                                                exp_set_8, exp_set_9)
     from proveit.numbers import zero, is_literal_int, DIGITS
     element = self.element
     domain = self.domain
     elem_in_set = InSet(element, domain)
     if not isinstance(element, ExprTuple):
         raise ProofFailure(
             elem_in_set, assumptions,
             "Can only automatically deduce membership in exponentiated "
             "sets for an element that is a list")
     exponent_eval = domain.exponent.evaluation(assumptions=assumptions)
     exponent = exponent_eval.rhs
     base = domain.base
     #print(exponent, base, exponent.as_int(),element, domain, len(element))
     if is_literal_int(exponent):
         if exponent == zero:
             return exp_set_0.instantiate({S: base},
                                          assumptions=assumptions)
         if element.num_entries() != exponent.as_int():
             raise ProofFailure(
                 elem_in_set, assumptions,
                 "Element not a member of the exponentiated set; "
                 "incorrect list length")
         elif exponent in DIGITS:
             # thm = forall_S forall_{a, b... in S} (a, b, ...) in S^n
             thm = locals()['exp_set_%d' % exponent.as_int()]
             expr_map = {S: base}  # S is the base
             # map a, b, ... to the elements of element.
             expr_map.update({
                 proveit.__getattr__(chr(ord('a') + k)): elem_k
                 for k, elem_k in enumerate(element)
             })
             elem_in_set = thm.instantiate(expr_map,
                                           assumptions=assumptions)
         else:
             raise ProofFailure(
                 elem_in_set, assumptions,
                 "Automatic deduction of membership in exponentiated sets "
                 "is not supported beyond an exponent of 9")
     else:
         raise ProofFailure(
             elem_in_set, assumptions,
             "Automatic deduction of membership in exponentiated sets is "
             "only supported for an exponent that is a literal integer")
     if exponent_eval.lhs != exponent_eval.rhs:
         # after proving that the element is in the set taken to
         # the evaluation of the exponent, substitute back in the
         # original exponent.
         return exponent_eval.sub_left_side_into(elem_in_set,
                                                 assumptions=assumptions)
     return elem_in_set
示例#3
0
 def sorted_items(cls, items, reorder=True, assumptions=USE_DEFAULTS):
     '''
     Return the given items in sorted order with respect to this
     TransitivityRelation class (cls) under the given assumptions
     using known transitive relations.
     If reorder is False, raise a TransitivityException if the
     items are not in sorted order as provided.
     Weak relations (e.g., <=) are only considered when calling
     this method on a weak relation class (otherwise, only
     equality and strong relations are used in the sorting).
     '''
     from proveit.numbers import is_literal_int
     assumptions = defaults.checked_assumptions(assumptions)
     if all(is_literal_int(item) for item in items):
         # All the items are integers.  Use efficient n log(n) sorting to
         # get them in the proper order and then use fixed_transitivity_sort
         # to efficiently prove this order.
         items = sorted(items, key=lambda item: item.as_int())
         reorder = False
     if reorder:
         sorter = TransitivitySorter(cls, items, assumptions=assumptions)
         return list(sorter)
     else:
         return cls._fixed_transitivity_sort(
             items, assumptions=assumptions).operands
示例#4
0
    def _computation(self, assumptions=USE_DEFAULTS, must_evaluate=False):
        # Currently not doing anything with must_evaluate
        # What it should do is make sure it evaluates to a number
        # and can circumvent any attempt that will not evaluate to
        # number.
        from proveit.numbers import one
        if not isinstance(self.operand, ExprTuple):
            # Don't know how to compute the length if the operand is
            # not a tuple. For example, it could be a variable that
            # represent a tuple.  So just return the self equality.
            from proveit.logic import Equals
            return Equals(self, self).prove()
        entries = self.operand.entries
        has_range = any(isinstance(entry, ExprRange) for entry in entries)
        if (len(entries) == 1 and has_range
                and not isinstance(entries[0].body, ExprRange)):
            # Compute the length of a single range.  Examples:
            # |(f(1), ..., f(n))| = n
            # |(f(i), ..., f(j))| = j-i+1
            range_entry = entries[0]
            start_index = range_entry.start_index
            end_index = range_entry.end_index
            lambda_map = range_entry.lambda_map
            if start_index == one:
                from proveit.core_expr_types.tuples import \
                    range_from1_len
                return range_from1_len.instantiate(
                    {
                        f: lambda_map,
                        i: end_index
                    }, assumptions=assumptions)
            else:
                from proveit.core_expr_types.tuples import range_len
                return range_len.instantiate(
                    {
                        f: lambda_map,
                        i: start_index,
                        j: end_index
                    },
                    assumptions=assumptions)
        elif not has_range:
            # Case of all non-range entries.
            if len(entries) == 0:
                # zero length.
                from proveit.core_expr_types.tuples import tuple_len_0
                return tuple_len_0
            elif len(entries) < 10:
                # Automatically get the count and equality with
                # the length of the proper iteration starting from
                # 1.  For example,
                # |(a, b, c)| = 3
                # |(a, b, c)| = |(1, .., 3)|
                import proveit.numbers.numerals.decimals
                _n = len(entries)
                len_thm = proveit.numbers.numerals.decimals\
                    .__getattr__('tuple_len_%d' % _n)
                repl_map = dict()
                for param, entry in zip(len_thm.explicit_instance_params(),
                                        entries):
                    repl_map[param] = entry
                return len_thm.instantiate(repl_map)
            else:
                # raise NotImplementedError("Can't handle length computation "
                #                        ">= 10 for %s"%self)
                from proveit.core_expr_types.tuples import tuple_len_incr
                from proveit.numbers import num
                from proveit.logic import Equals

                eq = tuple_len_incr.instantiate(
                    {
                        i: num(len(entries) - 1),
                        a: entries[:-1],
                        b: entries[-1]
                    },
                    assumptions=assumptions)

                rhs_simp = eq.rhs._integerBinaryEval(assumptions=assumptions)

                return rhs_simp.sub_right_side_into(eq,
                                                    assumptions=assumptions)
                # return Equals(eq.lhs, eq.rhs._integerBinaryEval(assumptions=assumptions).rhs).prove(assumptions=assumptions)
                # raise NotImplementedError("Can't handle length computation "
                #                         ">= 10 for %s"%self)
        elif (len(entries) == 2 and not isinstance(entries[1], ExprRange)
              and not isinstance(entries[0].body, ExprRange)):
            # Case of an extended range:
            # |(a_1, ..., a_n, b| = n+1
            from proveit.core_expr_types.tuples import \
                extended_range_len, extended_range_from1_len
            assert isinstance(entries[0], ExprRange)
            range_lambda = entries[0].lambda_map
            range_start = entries[0].start_index
            range_end = entries[0].end_index
            if range_start == one:
                return extended_range_from1_len.instantiate(
                    {
                        f: range_lambda,
                        b: entries[1],
                        i: range_end
                    },
                    assumptions=assumptions)
            else:
                return extended_range_len.instantiate(
                    {
                        f: range_lambda,
                        b: entries[1],
                        i: range_start,
                        j: range_end
                    },
                    assumptions=assumptions)
        else:
            # Handle the general cases via general_len_val,
            # len_of_ranges_with_repeated_indices,
            # len_of_ranges_with_repeated_indices_from_1,
            # or len_of_empty_range_of_range
            from proveit.core_expr_types.tuples import (
                general_len, len_of_ranges_with_repeated_indices,
                len_of_ranges_with_repeated_indices_from_1,
                len_of_empty_range_of_ranges)
            _x = safe_dummy_var(self)

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

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

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

            def empty_range(_i, _j, _f, assumptions):
                # If the start and end are literal ints and form an
                # empty range, then it should be straightforward to
                # prove that the range is empty.
                from proveit.numbers import is_literal_int, Add
                from proveit.logic import Equals
                from proveit import m
                _m = entries[0].start_index
                _n = entries[0].end_index
                empty_req = Equals(Add(_n, one), _m)
                if is_literal_int(_m) and is_literal_int(_n):
                    if _n.as_int() + 1 == _m.as_int():
                        empty_req.prove()
                if empty_req.proven(assumptions):
                    _f = Lambda(
                        (entries[0].parameter, entries[0].body.parameter),
                        entries[0].body.body)
                    _i = entry_map(_i)
                    _j = entry_map(_j)
                    return len_of_empty_range_of_ranges.instantiate(
                        {
                            m: _m,
                            n: _n,
                            f: _f,
                            i: _i,
                            j: _j
                        },
                        assumptions=assumptions)

            _f = [entry_map(entry) for entry in entries]
            _i = [entry_start(entry) for entry in entries]
            _j = [entry_end(entry) for entry in entries]
            _n = Len(_i).computed(assumptions=assumptions, simplify=False)

            from proveit.numbers import is_literal_int
            if len(entries) == 1 and isinstance(entries[0], ExprRange):
                if (is_literal_int(entries[0].start_index)
                        and is_literal_int(entries[0].end_index)):
                    if (entries[0].end_index.as_int() +
                            1 == entries[0].start_index.as_int()):
                        return empty_range(_i[0], _j[0], _f, assumptions)

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

            return general_len.instantiate({
                n: _n,
                f: _f,
                i: _i,
                j: _j
            },
                                           assumptions=assumptions)
示例#5
0
    def computation(self, **defaults_config):
        '''
        Compute this Len expression, returning the equality
        between self and the expression for its computed value.
        Examples:
            |(a, b, c)| = 3
            |(x_1, ..., x_n, y)| = n+1
            |(f(i), ..., f(j), x_1, ..., x_n)| = (j-i+1) + (n-1+1)
            |x| = |x|
        In the last case, the 'x' represents an unknown tuple,
        so there is not anything we can do to compute it.
        '''
        # Currently not doing anything with must_evaluate
        # What it should do is make sure it evaluates to a number
        # and can circumvent any attempt that will not evaluate to
        # number.
        from proveit.numbers import one
        #print(self.operands.entries[0].__class__)
        if not isinstance(self.operands, ExprTuple):
            # Don't know how to compute the length if the operand is
            # not a tuple. For example, it could be a variable that
            # represent a tuple.  So just return the self equality.
            from proveit.logic import Equals
            return Equals(self, self).conclude_via_reflexivity()
        entries = self.operands.entries
        has_range = any(isinstance(entry, ExprRange) for entry in entries)
        if (len(entries) == 1 and has_range
                and not isinstance(entries[0].body, ExprRange)):
            # Compute the length of a single range.  Examples:
            # |(f(1), ..., f(n))| = n
            # |(f(i), ..., f(j))| = j-i+1
            range_entry = entries[0]
            start_index = range_entry.true_start_index
            end_index = range_entry.true_end_index
            lambda_map = range_entry.lambda_map
            if start_index == one:
                from proveit.core_expr_types.tuples import range_from1_len
                len_comp = range_from1_len.instantiate(
                    {
                        f: lambda_map,
                        i: end_index
                    }, auto_simplify=False)
            else:
                from proveit.core_expr_types.tuples import range_len
                len_comp = range_len.instantiate(
                    {
                        f: lambda_map,
                        i: start_index,
                        j: end_index
                    },
                    auto_simplify=False)
        elif not has_range:
            # Case of all non-range entries.
            if len(entries) == 0:
                # zero length.
                from proveit.core_expr_types.tuples import tuple_len_0
                return tuple_len_0
            elif len(entries) < 10:
                # Automatically get the count and equality with
                # the length of the proper iteration starting from
                # 1.  For example,
                # |(a, b, c)| = 3
                # |(a, b, c)| = |(1, .., 3)|
                import proveit.numbers.numerals.decimals
                _n = len(entries)
                len_thm = proveit.numbers.numerals.decimals\
                    .__getattr__('tuple_len_%d' % _n)
                repl_map = dict()
                for param, entry in zip(len_thm.explicit_instance_params(),
                                        entries):
                    repl_map[param] = entry
                return len_thm.instantiate(repl_map, auto_simplify=False)
            else:
                # raise NotImplementedError("Can't handle length computation "
                #                        ">= 10 for %s"%self)
                from proveit.core_expr_types.tuples import tuple_len_incr
                from proveit.numbers import num
                from proveit.logic import Equals
                # We turn on automation because this length equality should
                # be true (we know the number of elements is equal to the
                # number of entries since there are no ExprRange entries).
                # Since we know it's true, why not commit ourselves to
                # proving it?
                return tuple_len_incr.instantiate(
                    {
                        i: num(len(entries) - 1),
                        a: entries[:-1],
                        b: entries[-1]
                    },
                    automation=True)
                # return Equals(eq.lhs, eq.rhs._integerBinaryEval(assumptions=assumptions).rhs).prove(assumptions=assumptions)
                # raise NotImplementedError("Can't handle length computation "
                #                         ">= 10 for %s"%self)
        elif (len(entries) == 2 and not isinstance(entries[1], ExprRange)
              and not isinstance(entries[0].body, ExprRange)):
            # Case of an extended range:
            # |(a_1, ..., a_n, b| = n+1
            from proveit.core_expr_types.tuples import \
                extended_range_len, extended_range_from1_len
            assert isinstance(entries[0], ExprRange)
            range_lambda = entries[0].lambda_map
            range_start = entries[0].true_start_index
            range_end = entries[0].true_end_index
            if range_start == one:
                len_comp = extended_range_from1_len.instantiate({
                    f: range_lambda,
                    x: entries[1],
                    i: range_end
                })
            else:
                len_comp = extended_range_len.instantiate({
                    f: range_lambda,
                    x: entries[1],
                    i: range_start,
                    j: range_end
                })
        else:
            # Handle the general cases via general_len_val,
            # len_of_ranges_with_repeated_indices,
            # len_of_ranges_with_repeated_indices_from_1,
            # or len_of_empty_range_of_range
            from proveit.core_expr_types.tuples import (
                general_len, len_of_ranges_with_repeated_indices,
                len_of_ranges_with_repeated_indices_from_1,
                len_of_empty_range_of_ranges)
            _x = safe_dummy_var(self)
            preserved_exprs = defaults.preserved_exprs

            def entry_map(entry):
                # Don't auto-simplify the entry.
                preserved_exprs.add(entry)
                if isinstance(entry, ExprRange):
                    if isinstance(entry.body, ExprRange):
                        # Return an ExprRange of lambda maps.
                        return ExprRange(entry.parameter,
                                         entry.body.lambda_map,
                                         entry.true_start_index,
                                         entry.true_end_index)
                    else:
                        return entry.lambda_map
                # For individual elements, just map to the
                # elemental entry.
                return Lambda(_x, entry)

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

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

            def empty_range(_i, _j, _f):
                # If the start and end are literal ints and form an
                # empty range, then it should be straightforward to
                # prove that the range is empty.
                from proveit.numbers import is_literal_int, Add
                from proveit.logic import Equals
                from proveit import m
                _m = entries[0].true_start_index
                _n = entries[0].true_end_index
                empty_req = Equals(Add(_n, one), _m)
                if is_literal_int(_m) and is_literal_int(_n):
                    if _n.as_int() + 1 == _m.as_int():
                        empty_req.prove()
                if empty_req.proven():
                    _f = Lambda(
                        (entries[0].parameter, entries[0].body.parameter),
                        entries[0].body.body)
                    _i = entry_map(_i)
                    _j = entry_map(_j)
                    return len_of_empty_range_of_ranges.instantiate({
                        m: _m,
                        n: _n,
                        f: _f,
                        i: _i,
                        j: _j
                    }).with_wrapping_at()

            _f = [entry_map(entry) for entry in entries]
            _i = [entry_start(entry) for entry in entries]
            _j = [entry_end(entry) for entry in entries]
            _n = Len(_i).computed()

            from proveit.numbers import is_literal_int
            if len(entries) == 1 and isinstance(entries[0], ExprRange):
                if (is_literal_int(entries[0].true_start_index)
                        and is_literal_int(entries[0].true_end_index)):
                    if (entries[0].true_end_index.as_int() +
                            1 == entries[0].true_start_index.as_int()):
                        return empty_range(_i[0], _j[0], _f)

            len_comp = None
            if all(_ == _i[0] for _ in _i) and all(_ == _j[0] for _ in _j):
                if isinstance(_i[0], ExprRange):
                    if _i[0].is_parameter_independent:
                        # A parameter independent range means they
                        # are all the same.
                        _i = [_i[0].body]
                if isinstance(_j[0], ExprRange):
                    if _j[0].is_parameter_independent:
                        # A parameter independent range means they
                        # are all the same.
                        _j = [_j[0].body]
                if (not isinstance(_i[0], ExprRange)
                        and not isinstance(_j[0], ExprRange)):
                    # special cases where the indices are repeated
                    if _i[0] == one:
                        thm = len_of_ranges_with_repeated_indices_from_1
                        len_comp = thm.instantiate({
                            n: _n,
                            f: _f,
                            i: _j[0]
                        }).with_wrapping_at()
                    else:
                        thm = len_of_ranges_with_repeated_indices
                        len_comp = thm.instantiate({
                            n: _n,
                            f: _f,
                            i: _i[0],
                            j: _j[0]
                        }).with_wrapping_at()
            if len_comp is None:
                len_comp = general_len.instantiate(
                    {
                        n: _n,
                        f: _f,
                        i: _i,
                        j: _j
                    },
                    preserved_exprs=preserved_exprs).with_wrapping_at()
                if not defaults.auto_simplify and len_comp.lhs != self:
                    # Make sure the left side is reduced to the
                    # original expression (self) which is preserved.
                    return len_comp.inner_expr().lhs.shallow_simplify(
                        preserved_exprs=preserved_exprs)
        if defaults.auto_simplify:
            # Ensure the right side is simplified which may have
            # been prevented due to automatic preservation of
            # instatiation expressions.
            return len_comp.inner_expr().rhs.simplify()
        return len_comp
示例#6
0
    def shallow_simplification(self, *, must_evaluate=False,
                               **defaults_config):
        '''
        Returns a proven simplification equation for this Exp
        expression assuming the operands have been simplified.

        Handles the following evaluations:
            a^0 = 1 for any complex a
            0^x = 0 for any positive x
            1^x = 1 for any complex x
            a^(Log(a, x)) = x for RealPos a and x, a != 1.
            x^n = x*x*...*x = ? for a natural n and irreducible x.

        Handles a zero or one exponent or zero or one base as
        simplifications.
        '''
        from proveit.relation import TransRelUpdater
        from proveit.logic import EvaluationError, is_irreducible_value
        from proveit.logic import InSet
        from proveit.numbers import (zero, one, two, is_literal_int,
                                     is_literal_rational,
                                     Log, Rational, Abs)
        from . import (exp_zero_eq_one, exponentiated_zero,
                       exponentiated_one, exp_nat_pos_expansion)

        if self.is_irreducible_value():
            # already irreducible
            return Equals(self, self).conclude_via_reflexivity()

        if must_evaluate:
            if not all(is_irreducible_value(operand) for
                       operand in self.operands):
                for operand in self.operands:
                    if not is_irreducible_value(operand):
                        # The simplification of the operands may not have
                        # worked hard enough.  Let's work harder if we
                        # must evaluate.
                        operand.evaluation()
                return self.evaluation()

        if self.exponent == zero:
            return exp_zero_eq_one.instantiate({a: self.base})  # =1
        elif self.base == zero:
            # Will fail if the exponent is not positive, but this
            # is the only sensible thing to try.
            return exponentiated_zero.instantiate({x: self.exponent})  # =0
        elif self.exponent == one:
            return self.power_of_one_reduction()
        elif self.base == one:
            return exponentiated_one.instantiate({x: self.exponent})  # =1
        elif (isinstance(self.base, Exp) and
            isinstance(self.base.exponent, Div) and
            self.base.exponent.numerator == one and
                self.base.exponent.denominator == self.exponent):
            from . import nth_power_of_nth_root
            _n, _x = nth_power_of_nth_root.instance_params
            return nth_power_of_nth_root.instantiate(
                {_n: self.exponent, _x: self.base.base})
        elif (isinstance(self.base, Exp) and
            isinstance(self.exponent, Div) and
            self.exponent.numerator == one and
                self.exponent.denominator == self.base.exponent):
            from . import nth_root_of_nth_power, sqrt_of_square
            _n = self.base.exponent
            _x =  self.base.base
            if _n == two:
                return sqrt_of_square.instantiate({x: _x})
            return nth_root_of_nth_power.instantiate({n: _n, x: _x})
        elif (is_literal_rational(self.base) and
                  is_literal_int(self.exponent) and
                  self.exponent.as_int() > 1):
            expr = self
            eq = TransRelUpdater(expr)
            expr = eq.update(exp_nat_pos_expansion.instantiate(
                    {x:self.base, n:self.exponent}, preserve_all=True))
            # We should come up with a better way of reducing
            # ExprRanges representing repetitions:
            _n = self.exponent.as_int()
            if _n <= 0 or _n > 9:
                raise NotImplementedError("Currently only implemented for 1-9")
            repetition_thm = proveit.numbers.numerals.decimals \
                .__getattr__('reduce_%s_repeats' % _n)
            rep_reduction = repetition_thm.instantiate({x: self.base})
            expr = eq.update(expr.inner_expr().operands.substitution(
                    rep_reduction.rhs, preserve_all=True))
            expr = eq.update(expr.evaluation())
            return eq.relation
        elif (isinstance(self.exponent, Log)
            and self.base == self.exponent.base):
            # base_ns  = self.base.deduce_number_set()
            # antilog_ns = self.exponent.antilog.deduce_number_set()
            if (InSet(self.base, RealPos).proven()
                and InSet(self.exponent.antilog, RealPos).proven()
                and NotEquals(self.base, one).proven()):
                return self.power_of_log_reduction()
        expr = self
        # for convenience updating our equation:
        eq = TransRelUpdater(expr)
        if self.exponent == two and isinstance(self.base, Abs):
            from . import (square_abs_rational_simp,
                                     square_abs_real_simp)
            # |a|^2 = a if a is real
            try:
                deduce_number_set(self.base)
            except UnsatisfiedPrerequisites:
                pass
            rational_base = InSet(self.base, Rational).proven()
            real_base = InSet(self.base, Real).proven()
            thm = None
            if rational_base:
                thm = square_abs_rational_simp
            elif real_base:
                thm = square_abs_real_simp
            if thm is not None:
                simp = thm.instantiate({a: self.base.operand})
                expr = eq.update(simp)
                # A further simplification may be possible after
                # eliminating the absolute value.
                expr = eq.update(expr.simplification())

        return eq.relation