Example #1
0
    def get_format_cell_element_positions(self):
        '''
        Returns a list of element positions in correspondence with
        each format cell of this ExprTuple 
        (see ExprTuple.yield_format_cell_info).
        The element position starts as a 'one' (from proveit.numbers) 
        and adds one in correspondence with each format cell except the 
        'ellipsis' cell and the last cell of each ExprRange.  The 
        element position of the 'ellipsis' cells is 'None' (it isn't 
        defined).  The element position of the last cell of the 
        ExprRange will be ('end_index' - 'start_index') of the ExprRange
        added to the element position of the first cell.

        The assumptions dictate simplifications that may apply to
        the element positions.
        '''
        from .expr_range import ExprRange
        from proveit.numbers import Add, zero, one

        element_positions = []
        element_pos = zero # We will add 1 before using this.
        for item in self.entries:
            # Add one to the element_pos.
            element_pos = Add(element_pos, one).quick_simplified()
            # Append to element_positions.
            if isinstance(item, ExprRange):
                # An ExprRange covers multiple format cells.
                element_pos = item._append_format_cell_element_positions(
                        element_pos, element_positions)
            else:
                # One format cells for a regular entry.
                element_positions.append(element_pos)
        return element_positions
Example #2
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)
Example #3
0
 def num_elements(self, proven=True, **defaults_config):
     '''
     Return the number of elements of this ExprTuple as an 
     Expression.  This includes the extent of all contained ranges.
     If proven==True, a proof is constructed in the process.
     '''
     from .expr_range import ExprRange
     from proveit.core_expr_types import Len
     from proveit.numbers import Add, zero, one
     if proven:
         return Len(self).computed(**defaults_config)
     # Do the quick-and-dirty calculation with no proof.
     count = zero
     for entry in self:
         if isinstance(entry, ExprRange):
             count = Add(count, 
                         entry.num_elements(proven=False)).quick_simplified()
         else:
             count = Add(count, one).quick_simplified()
     return count
Example #4
0
def multi_elem_entries(element_from_part,
                       start_qubit_idx,
                       end_qubit_idx,
                       *part_start_and_ends,
                       check_part_index_span=True):
    '''
    Yield consecutive vertical entries for MultiQubitElem to 
    represent all parts of a multi-qubit operation in a quantum circuit
    involving all qubits from 'start_qubit_idx' to 'end_qubit_idx.
    There will be an entry for each "part" start/end pair of indices.
    In total, these must start from one, be consecutive, and cover the 
    range from the 'start_qubit_idx' to the 'end_qubit_idx.
    The element_from_part function must return an element corresponding
    to a given 'part'.
    '''
    targets = Interval(start_qubit_idx, end_qubit_idx)
    multi_qubit_gate_from_part = (
        lambda part: MultiQubitElem(element_from_part(part), targets))
    part = one
    if len(part_start_and_ends) == 0:
        raise ValueError("Must specify one or more 'part' start and end "
                         "indices, starting from one and covering the range "
                         "from %s to %s" % (start_qubit_idx, end_qubit_idx))
    for part_start, part_end in part_start_and_ends:
        #try:
        #    Equals(part, part_start).prove()
        #except ProofFailure:
        if part != part_start:
            raise ValueError("Part indices must be provably consecutive "
                             "starting from 1: %s ≠ %s" % (part_start, part))
        if part_start == part_end:  # just a single element
            yield multi_qubit_gate_from_part(part)
        else:
            param = safe_dummy_var()
            yield ExprRange(param, multi_qubit_gate_from_part(param),
                            part_start, part_end)
        part = Add(part_end, one).quick_simplified()
    if not check_part_index_span:
        lhs = Add(part_end, num(-1)).quick_simplified()
        rhs = Add(end_qubit_idx, Neg(start_qubit_idx)).quick_simplified()
        try:
            try:
                lhs = lhs.simplified()
            except:
                pass
            try:
                rhs = rhs.simplified()
            except:
                pass
            Equals(lhs, rhs).prove()
        except ProofFailure:
            raise ValueError("Part indices must span the range of the "
                             "multi qubit operation: %s ≠ %s" % (lhs, rhs))
Example #5
0
 def join(self, second_summation, assumptions=frozenset()):
     '''
     Join the "second summation" with "this" summation, deducing and returning
     the equivalence of these summations added with the joined summation.
     Both summation must be over Intervals.
     The relation between the first summation upper bound, UB1, and the second
     summation lower bound, LB2 must be explicitly either UB1 = LB2-1 or LB2=UB1+1.
     '''
     from theorems import sum_split_after, sum_split_before
     from proveit.numbers.common import one
     from proveit.numbers import Sub, Add
     if not isinstance(self.domain, Interval) or not isinstance(
             second_summation.domain, Interval):
         raise Exception(
             'Sum joining only implemented for Interval domains')
     if self.summand != second_summation.summand:
         raise Exception(
             'Sum joining only allowed when the summands are the same')
     if self.domain.upper_bound == Sub(second_summation.domain.lower_bound,
                                       one):
         sum_split = sum_split_before
         split_index = second_summation.domain.lower_bound
     elif second_summation.domain.lower_bound == Add(
             self.domain.upper_bound, one):
         sum_split = sum_split_after
         split_index = self.domain.upper_bound
     else:
         raise Exception(
             'Sum joining only implemented when there is an explicit increment of one from the upper bound and the second summations lower bound'
         )
     lower_bound, upper_bound = self.domain.lower_bound, second_summation.domain.upper_bound
     deduce_in_integer(lower_bound, assumptions)
     deduce_in_integer(upper_bound, assumptions)
     deduce_in_integer(split_index, assumptions)
     return sum_split.instantiate({
         Operation(f, self.instance_vars):
         self.summand
     }).instantiate({
         a: lower_bound,
         b: split_index,
         c: upper_bound,
         x: self.indices[0]
     }).derive_reversed()
Example #6
0
def quick_simplified_index(expr):
    '''
    Return a simplified version of this expression with a 
    quick-n-dirty approach suitable for additively shifted and/or
    negated integer indices and nested versions thereof.
    In particular, negations are distributed nested additionas are 
    ungrouped, literal integers are extracted, added, and placed at the
    end, and cancelations are made on ndividual terms as well as 
    expression ranges or portions of expression ranges.  We freely 
    assume terms represent numbers and expression ranges are 
    well-formed.
    Used for ExprRange formatting and for hints along the way when
    provably expanding ExprRanges through an instantiation (this
    provides hints, but there will be proven requirements to ensure it
    is right).
    '''
    from proveit.numbers import Add, Neg
    if isinstance(expr, Neg):
        return Add(expr).quick_simplified()
    elif isinstance(expr, Add):
        return expr.quick_simplified()
    return expr
Example #7
0
#        This \varphi is the phase that is the objective of phase estimation.
phase_ = Literal(pkg, 'phase', {LATEX: r'\varphi'})

# t: Number of qubit registers for the quantum phase estimation.
#    We prove that this is the bits of precision of phase estimation.
t_ = Literal(pkg, 't')

# Psi: Outcome of register qubits following the quantum phase estimation
# circuit.
Psi_ = Literal(pkg, 'PSI', {STRING: 'Psi', LATEX: r'\Psi'})
# psi: indexed intermediate output registers inside the quantum phase
# estimation circuit.
psi_ = Literal(pkg, 'psi', {STRING: 'psi', LATEX: r'\psi'})
psi_k = SubIndexed(psi_, k)
psi_t = SubIndexed(psi_, t_)
psi_next = SubIndexed(psi_, Add(k, one))
psi_1 = SubIndexed(psi_, one)

U_pow_two_pow_k = Exp(U_, Exp(two, k))

# m: Random variable for the measurement of Psi as an integer from the
# register's binary representation.
m_ = Literal(pkg, 'm')

# phase_m: Random variable for the phase result of the quantum phase estimation.
#          phase_m = m / 2^t
phase_m_ = Literal(pkg, 'phase_m', {LATEX: r'\varphi_m'})

# b: The "best" outcome of m such that phase_m is as close as possible to
# phase.
b_ = Literal(pkg, 'b')
Example #8
0
from proveit.logic import Forall, Equals
from proveit.numbers import Sum, Integer, Interval, LessThan, Add, Sub
from proveit.common import a, b, f, x, fa, fb, fx
from proveit.numbers.common import one
from proveit import begin_axioms, end_axioms

begin_axioms(locals())

sum_single = Forall(f, Forall(a,
                              Equals(Sum(x, fx, Interval(a, a)),
                                     fa),
                              domain=Integer))
sum_single

sum_split_last = Forall(f,
                        Forall([a, b],
                               Equals(Sum(x, fx, Interval(a, b)),
                                      Add(Sum(x, fx, Interval(a, Sub(b, one))),
                                          fb)),
                               domain=Integer, conditions=[LessThan(a, b)]))
sum_split_last


end_axioms(locals(), __package__)
Example #9
0
subtract_real_closure = Forall([a, b], InSet(Sub(a, b), Real), domain=Real)
subtract_real_closure

subtract_one_in_nats = Forall(a,
                              InSet(Sub(a, one), Natural),
                              domain=NaturalPos)
subtract_one_in_nats

diff_not_eq_zero = Forall((a, b),
                          NotEquals(Sub(a, b), zero),
                          domain=Complex,
                          conditions=[NotEquals(a, b)])
diff_not_eq_zero

subtract_as_add_neg = Forall([x, y],
                             Equals(Sub(x, y), Add(x, Neg(y))),
                             domain=Complex)
subtract_as_add_neg

add_neg_as_subtract = Forall([x, y],
                             Equals(Add(x, Neg(y)), Sub(x, y)),
                             domain=Complex)
add_neg_as_subtract

absorb_terms_into_subtraction = Forall([w_etc, x, y, z_etc],
                                       Equals(Add(w_etc, Sub(x, y), z_etc),
                                              Sub(Add(w_etc, x, z_etc), y)),
                                       domain=Complex)
absorb_terms_into_subtraction

subtract_cancel_elim_sums = Forall([x, y, z],
Example #10
0
                         Equals(Exp(a, zero), one),
                         domain=Complex,
                         conditions=[NotEquals(a, zero)])
exp_zero_eq_one

exponentiated_zero = Forall([x],
                            Equals(Exp(zero, x), zero),
                            domain=Complex,
                            conditions=[NotEquals(x, zero)])
exponentiated_zero

exponentiated_one = Forall([x], Equals(Exp(one, x), one), domain=Complex)
exponentiated_one

sum_in_exp = Forall([a, b, c],
                    Equals(Exp(a, Add(b, c)), Mult(Exp(a, b), Exp(a, c))),
                    domain=Complex,
                    conditions=[NotEquals(a, zero)])
sum_in_exp

sum_in_exp_rev = Forall([a, b, c],
                        Equals(Mult(Exp(a, b), Exp(a, c)), Exp(a, Add(b, c))),
                        domain=Complex,
                        conditions=[NotEquals(a, zero)])
sum_in_exp_rev

add_one_right_in_exp = Forall([a, b],
                              Equals(Exp(a, Add(b, one)), Mult(Exp(a, b), a)),
                              domain=Complex,
                              conditions=[NotEquals(a, zero)])
add_one_right_in_exp
Example #11
0
                            domain=ComplexSansZero)
divide_not_eq_zero

fraction_not_eq_zero = Forall([a, b],
                              NotEquals(frac(a, b), zero),
                              domain=ComplexSansZero)
fraction_not_eq_zero

frac_zero_numer = Forall(x, Equals(frac(zero, x), zero), domain=Complex)
frac_zero_numer

frac_one_denom = Forall(x, Equals(frac(x, one), x), domain=Complex)
frac_one_denom

distributefrac_through_sum = Forall([x_etc, y],
                                    Equals(frac(Add(x_etc), y),
                                           Add(Etcetera(frac(x_multi, y)))),
                                    domain=Complex,
                                    conditions=[NotEquals(y, zero)])
distributefrac_through_sum

distributefrac_through_sum_rev = Forall([x_etc, y],
                                        Equals(Add(Etcetera(frac(x_multi, y))),
                                               frac(Add(x_etc), y)),
                                        domain=Complex,
                                        conditions=[NotEquals(y, zero)])
distributefrac_through_sum_rev

distributefrac_through_subtract = Forall([x, y, z],
                                         Equals(frac(Sub(x, y), z),
                                                Sub(frac(x, z), frac(y, z))),
Example #12
0
    def merger(self, **defaults_config):
        '''
        If this is an tuple of expressions that can be directly merged
        together into a single ExprRange, return this proven
        equivalence.  For example,
        {j \in Natural, k-(j+1) \in Natural}
        |- (x_1, .., x_j, x_{j+1}, x_{j+2}, ..., x_k) = (x_1, ..., x_k)
        '''
        from proveit._core_.expression.lambda_expr import (
                Lambda, ArgumentExtractionError)
        from .expr_range import ExprRange, simplified_index
        from proveit.relation import TransRelUpdater
        from proveit.core_expr_types.tuples import (
            merge, merge_front, merge_back, merge_extension,
            merge_pair, merge_series)
        from proveit import f, i, j, k, l, x
        from proveit.numbers import one, Add, subtract

        # A convenience to allow successive update to the equation via
        # transitivities (starting with self=self).
        eq = TransRelUpdater(self)

        # Determine the position of the first ExprRange item and get the
        # lambda map.
        first_range_pos = len(self.entries)
        lambda_map = None
        for _k, item in enumerate(self):
            if isinstance(item, ExprRange):
                lambda_map = Lambda(item.lambda_map.parameter,
                                    item.lambda_map.body)
                first_range_pos = _k
                break

        if 1 < first_range_pos:
            if lambda_map is None:
                raise NotImplementedError("Means of extracting a lambda "
                                          "map has not been implemented")
                pass  # need the lambda map
            # Collapse singular items at the beginning.
            front_singles = ExprTuple(eq.expr[:first_range_pos])
            i_sub = lambda_map.extract_argument(front_singles[0])
            j_sub = lambda_map.extract_argument(front_singles[-1])
            if len(front_singles.entries) == 2:
                # Merge a pair of singular items.
                front_merger = merge_pair.instantiate(
                    {f: lambda_map, i: i_sub, j: j_sub})
            else:
                # Merge a series of singular items in one shot.
                front_merger = merge_series.instantiate(
                    {f: lambda_map, x: front_singles, i: i_sub, j: j_sub})
            eq.update(
                front_merger.substitution(
                    self.inner_expr()[:first_range_pos]))

        if eq.expr.num_entries() == 1:
            # We have accomplished a merger down to one item.
            return eq.relation

        if eq.expr.num_entries() == 2:
            # Merge a pair.
            if isinstance(eq.expr[0], ExprRange):
                if isinstance(eq.expr[1], ExprRange):
                    # Merge a pair of ExprRanges.
                    item = eq.expr[1]
                    other_lambda_map = Lambda(item.lambda_map.parameter,
                                              item.lambda_map.body)
                    if other_lambda_map != lambda_map:
                        raise ExprTupleError(
                            "Cannot merge together ExprRanges "
                            "with different lambda maps: %s vs %s" %
                            (lambda_map, other_lambda_map))
                    _i, _j = eq.expr[0].true_start_index, eq.expr[0].true_end_index
                    _k, _l = eq.expr[1].true_start_index, eq.expr[1].true_end_index
                    merger = \
                        merge.instantiate(
                                {f: lambda_map, i: _i, j: _j, k: _k, l: _l})
                else:
                    # Merge an ExprRange and a singular item.
                    _i, _j = eq.expr[0].true_start_index, eq.expr[0].true_end_index
                    try:
                        _k = lambda_map.extract_argument(eq.expr[1])
                    except ArgumentExtractionError:
                        _k = simplified_index(Add(_j, one))
                    if _k == Add(_j, one):
                        merger = merge_extension.instantiate(
                            {f: lambda_map, i: _i, j: _j})
                    else:
                        merger = merge_back.instantiate(
                            {f: lambda_map, i: _i, j: _j, k: _k})
            else:
                # Merge a singular item and ExprRange.
                _i = simplified_index(
                    subtract(eq.expr[1].true_start_index, one))
                _j, _k = eq.expr[1].true_start_index, eq.expr[1].true_end_index
                merger = \
                    merge_front.instantiate({f: lambda_map, i: _i, 
                                             j: _j, k: _k})
            all_decreasing = all(expr.is_decreasing() for expr in eq.expr
                                 if isinstance(expr, ExprRange))
            if all_decreasing:
                # Apply the 'decreasing' order style to match what we
                # had originally.
                for _i in (0, 1):
                    if isinstance(eq.expr[_i], ExprRange):
                        merger = (merger.inner_expr().lhs[_i]
                                  .with_decreasing_order())
                merger = merger.inner_expr().rhs[0].with_decreasing_order()
            eq.update(merger)
            return eq.relation

        while eq.expr.num_entries() > 1:
            front_merger = ExprTuple(*eq.expr[:2].entries).merger()
            eq.update(front_merger.substitution(
                eq.expr.inner_expr()[:2]))
        return eq.relation
Example #13
0
    def joining(self, second_summation, **defaults_config):
        '''
        Join the "second summation" with "this" (self) summation,
        deducing and returning the equivalence of the sum of the self
        and second_summation with the joined summation.
        Both summations must be over integer Intervals.
        The relation between the first summation upper bound, UB1,
        and the second summation lower bound, LB2, must be *explicitly*
        either UB1 = LB2-1 or LB2=UB1+1 *or* easily-derivable
        mathematical equivalents of those equalities.
        Example usage: let S1 = Sum(i, i^2, Interval(1,10)) and
        S2 = Sum(i, i^2, Interval(1,10)). Then S1.join(S2) returns
        |- S1 + S2 = Sum(i, i^2, Interval(1,20))
        '''

        if (not isinstance(self.domain, Interval)
                or not isinstance(second_summation.domain, Interval)):
            raise NotImplementedError(
                "Sum.join() is only implemented for summations with a "
                "single index over an integer Interval. The sum {0} has "
                "indices {1} and domain {2}; the sum {3} has indices "
                "{4} and domain {5}.".format(self, self.indices, self.domain,
                                             second_summation,
                                             second_summation.indices,
                                             second_summation.domain))

        if self.summand != second_summation.summand:
            raise ValueError(
                "Sum joining using Sum.join() is only allowed when the "
                "summands are identical. The sum {0} has summand {1} "
                "while the sum {2} has summand {3}. If the summands are "
                "equal but do not appear identical, you will have to "
                "establish an appropriate substituion before calling the "
                "Sum.join() method.".format(self, self.summand,
                                            second_summation,
                                            second_summation.summand))

        from . import sum_split_after, sum_split_before
        from proveit import a

        _i = self.index
        _a1 = self.domain.lower_bound
        _b1 = self.domain.upper_bound
        _a2 = second_summation.domain.lower_bound
        _b2 = second_summation.domain.upper_bound
        f_op, f_op_sub = Function(f, self.index), self.summand

        # Create low-effort, simplified versions of transition index
        # values, if possible
        _b1_plus_1_simplified = Add(_b1, one).shallow_simplified()
        _a2_minus_1_simplified = subtract(_a2, one).shallow_simplified()

        # This breaks into four cases (despite the temptation to
        # combine some of the cases):
        if (_b1 == subtract(_a2, one)):
            # UB1 == LB2 - 1 (literally)
            sum_split = sum_split_before
            split_index = _a2
        elif (_a2 == Add(_b1, one)):
            # LB2 == UB1 + 1 (literally)
            sum_split = sum_split_after
            split_index = _b1
        elif (_b1 == _a2_minus_1_simplified):
            # UB1 == LB2 - 1 (after simplification)
            sum_split = sum_split_before
            split_index = _a2
        elif (_a2 == _b1_plus_1_simplified):
            # LB2 == UB1 + 1 (after simplification)
            sum_split = sum_split_after
            split_index = _b1
        else:
            raise UnsatisfiedPrerequisites(
                "Sum joining using Sum.join() only implemented for when "
                "there is an explicit (or easily verified) increment "
                "of one unit from the first summation's upper bound "
                "to the second summation's lower bound (or decrement "
                "of one unit from second summation's lower bound to "
                "first summation's upper bound). We have first "
                "summation upper bound of {0} with the second summation "
                "lower bound of {1}. If these appear to have the "
                "necessary relationship, you might need to prove this "
                "before calling the Sum.join() method.".format(_b1, _a2))

        # Preserve the original summations that will be on the
        # left side of the equation.
        preserved_exprs = set(defaults.preserved_exprs)
        preserved_exprs.add(self)
        preserved_exprs.add(second_summation)

        return sum_split.instantiate(
            {
                f_op: f_op_sub,
                a: _a1,
                b: split_index,
                c: _b2,
                x: _i
            },
            preserved_exprs=preserved_exprs).derive_reversed()
Example #14
0
negated_positive_is_negative

negated_negative_is_positive = Forall(a,
                                      GreaterThan(Neg(a), zero),
                                      domain=Real,
                                      conditions=[LessThan(a, zero)])
negated_negative_is_positive

neg_not_eq_zero = Forall(a,
                         NotEquals(Neg(a), zero),
                         domain=Complex,
                         conditions=[NotEquals(a, zero)])
neg_not_eq_zero

distribute_neg_through_sum = Forall([x_etc],
                                    Equals(Neg(Add(x_etc)),
                                           Add(Etcetera(Neg(x_multi)))),
                                    domain=Complex)
distribute_neg_through_sum

distribute_neg_through_sum_rev = Forall([x_etc],
                                        Equals(Add(Etcetera(Neg(x_multi))),
                                               Neg(Add(x_etc))),
                                        domain=Complex)
distribute_neg_through_sum_rev

distribute_neg_through_subtract = Forall([x, y],
                                         Equals(Neg(Sub(x, y)), Add(Neg(x),
                                                                    y)),
                                         domain=Complex)
distribute_neg_through_subtract
Example #15
0
mult_zero

mult_comm = Forall([v_etc, w_etc, x_etc, y_etc, z_etc],
                   Equals(Mult(v_etc, w_etc, x_etc, y_etc, z_etc),
                          Mult(v_etc, y_etc, x_etc, w_etc, z_etc)),
                   domain=Complex)
mult_comm

mult_assoc_rev = Forall([x_etc, y_etc, z_etc],
                        Equals(Mult(x_etc, Mult(y_etc), z_etc),
                               Mult(x_etc, y_etc, z_etc)))
mult_assoc_rev

distribute_through_sum = Forall([x_etc, y_etc, z_etc],
                                Equals(
                                    Mult(x_etc, Add(y_etc), z_etc),
                                    Add(Etcetera(Mult(x_etc, y_multi,
                                                      z_etc)))),
                                domain=Complex)
distribute_through_sum

distribute_through_sum_rev = Forall(
    [x_etc, y_etc, z_etc],
    Equals(Add(Etcetera(Mult(x_etc, y_multi, z_etc))),
           Mult(x_etc, Add(y_etc), z_etc)),
    domain=Complex)
distribute_through_sum_rev

distribute_through_subtract = Forall([w_etc, x, y, z_etc],
                                     Equals(
                                         Mult(w_etc, Sub(x, y), z_etc),
Example #16
0
    def merger(self, assumptions=USE_DEFAULTS):
        '''
        If this is an tuple of expressions that can be directly merged
        together into a single ExprRange, return this proven
        equivalence.  For example,
        {j \in Natural, k-(j+1) \in Natural}
        |- (x_1, .., x_j, x_{j+1}, x_{j+2}, ..., x_k) = (x_1, ..., x_k)
        '''
        from proveit._core_.expression.lambda_expr import Lambda
        from .expr_range import ExprRange
        from proveit.relation import TransRelUpdater
        from proveit.core_expr_types.tuples import (merge, merge_front,
                                                    merge_back,
                                                    merge_extension,
                                                    merge_pair, merge_series)
        from proveit import f, i, j, k, l, x
        from proveit.numbers import Add, one

        # A convenience to allow successive update to the equation via
        # transitivities (starting with self=self).
        eq = TransRelUpdater(self, assumptions)

        # Determine the position of the first ExprRange item and get the
        # lambda map.
        first_range_pos = len(self.entries)
        lambda_map = None
        for _k, item in enumerate(self):
            if isinstance(item, ExprRange):
                lambda_map = Lambda(item.lambda_map.parameter,
                                    item.lambda_map.body)
                first_range_pos = _k
                break

        if 1 < first_range_pos:
            if lambda_map is None:
                raise NotImplementedError("Means of extracting a lambda "
                                          "map has not been implemented")
                pass  # need the lambda map
            # Collapse singular items at the beginning.
            front_singles = ExprTuple(eq.expr[:first_range_pos])
            i_sub = lambda_map.extract_argument(front_singles[0])
            j_sub = lambda_map.extract_argument(front_singles[-1])
            if len(front_singles.entries) == 2:
                # Merge a pair of singular items.
                front_merger = merge_pair.instantiate(
                    {
                        f: lambda_map,
                        i: i_sub,
                        j: j_sub
                    },
                    assumptions=assumptions)
            else:
                # Merge a series of singular items in one shot.
                front_merger = merge_series.instantiate(
                    {
                        f: lambda_map,
                        x: front_singles,
                        i: i_sub,
                        j: j_sub
                    },
                    assumptions=assumptions)
            eq.update(
                front_merger.substitution(self.inner_expr()[:first_range_pos],
                                          assumptions=assumptions))

        if eq.expr.num_entries() == 1:
            # We have accomplished a merger down to one item.
            return eq.relation

        if eq.expr.num_entries() == 2:
            # Merge a pair.
            if isinstance(eq.expr[0], ExprRange):
                if isinstance(eq.expr[1], ExprRange):
                    # Merge a pair of ExprRanges.
                    item = eq.expr[1]
                    other_lambda_map = Lambda(item.lambda_map.parameter,
                                              item.lambda_map.body)
                    if other_lambda_map != lambda_map:
                        raise ExprTupleError(
                            "Cannot merge together ExprRanges "
                            "with different lambda maps: %s vs %s" %
                            (lambda_map, other_lambda_map))
                    _i, _j = eq.expr[0].start_index, eq.expr[0].end_index
                    _k, _l = eq.expr[1].start_index, eq.expr[1].end_index
                    merger = \
                        merge.instantiate({f: lambda_map, i: _i, j: _j, k: _k, l: _l},
                                          assumptions=assumptions)
                else:
                    # Merge an ExprRange and a singular item.
                    _i, _j = eq.expr[0].start_index, eq.expr[0].end_index
                    _k = lambda_map.extract_argument(eq.expr[1])
                    if _k == Add(_j, one):
                        merger = merge_extension.instantiate(
                            {
                                f: lambda_map,
                                i: _i,
                                j: _j
                            },
                            assumptions=assumptions)
                    else:
                        merger = merge_back.instantiate(
                            {
                                f: lambda_map,
                                i: _i,
                                j: _j,
                                k: _k
                            },
                            assumptions=assumptions)
            else:
                # Merge a singular item and ExprRange.
                i_sub = lambda_map.extract_argument(eq.expr[0])
                j_sub, k_sub = eq.expr[1].start_index, eq.expr[1].end_index
                merger = \
                    merge_front.instantiate({f: lambda_map, i: i_sub, j: j_sub,
                                             k: k_sub}, assumptions=assumptions)
            eq.update(merger)
            return eq.relation

        while eq.expr.num_entries() > 1:
            front_merger = ExprTuple(*eq.expr[:2].entries).merger(assumptions)
            eq.update(
                front_merger.substitution(eq.expr.inner_expr(assumptions)[:2],
                                          assumptions=assumptions))
        return eq.relation
Example #17
0
def unit_length_complex_polar_angle(expr, *, reductions=None):
    '''
    Given an expression, expr, of the complex number polar form,
        exp(i * theta),
    or something obviously equivalent to this, where r is RealNonNeg 
    and theta is Real under the given assumptions, return theta.
    If defaults.automation=False, theta must already be known to be 
    Real. If defaults.automation=True, we may attempt to prove these 
    through automation.
    
    If expr is not exactly in this complex number polar form and
    'reductions' is provided as a set, add to the 'reductions' set
    an equation that equates the exact form on the left with the
    original form on the right.  This may be useful to use as
    'replacements' in instantiations of theorems that employ the
    complex number polar form so it may perform proper reductions
    to the desired form.  For example, if expr=1 is provided,
    the added reduction will be
        exp(i * 0) = 1
    
    Raise ValueError if the expr is not obviously equivalent to a
    complex number polar form.
    
    Also see complex_polar_coordinates.
    '''
    from proveit import ExprRange
    from proveit.logic import Equals, InSet
    from proveit.numbers import deduce_in_number_set, deduce_number_set
    from proveit.numbers import zero, one, e, i, pi
    from proveit.numbers import Add, Neg, Mult, Exp, Real, Complex
    from . import unit_length_complex_polar_negation
    if reductions is None: reductions = set()

    orig_expr = expr

    def raise_not_valid_form(extra_msg=None):
        if extra_msg is None: extra_msg = ""
        raise ValueError("%s not in a form that is obviously "
                         "reducible from an exp(i*theta) form. %s" %
                         (orig_expr, extra_msg))

    automation = defaults.automation
    simplify = defaults.auto_simplify

    def add_reduction(reduction, _theta):
        '''
        Add the given reduction.  First check that its left and
        rights sides are as expected: the left should be the polar
        form and the right should be the original expression.
        '''
        polar_form = Exp(e, Mult(i, _theta))
        assert (isinstance(reduction, Judgment)
                and isinstance(reduction.expr, Equals)
                and reduction.lhs == polar_form and reduction.rhs == orig_expr)
        if reduction.lhs != reduction.rhs:
            reductions.add(reduction)

    if expr == one:
        # expr = 1 = exp(i * 0)
        _theta = zero
        expr = Exp(e, Mult(i, _theta))
        # reduction: exp(i * 0) = 1
        reduction = expr.simplification()
        # Add the reduction and return theta.
        add_reduction(reduction, _theta)
        return _theta
    if isinstance(expr, Exp) and expr.base == e:
        if expr.exponent == i:
            # expr = exp(i) = exp(i * 1)
            _theta = one
            expr = Exp(e, Mult(i, one))
            # reduction: exp(i * 1) = exp(i)
            reduction = expr.inner_expr().exponent.one_elimination(1)
            # Add the reduction and return theta.
            add_reduction(reduction, _theta)
            return _theta
        if hasattr(expr.exponent, 'factorization'):
            if (isinstance(expr.exponent, Mult)
                    and expr.exponent.operands.is_double()
                    and expr.exponent.operands[0] == i):
                # Already in the proper form.  No reduction needed,
                # but we do need to check that theta is real.
                _theta = expr.exponent.factors[1]
                _theta_ns = deduce_number_set(_theta).domain
                if not Real.includes(_theta_ns):
                    raise_not_valid_form("%s known to be %s but not Real." %
                                         (_theta, _theta_ns))
                deduce_in_number_set(_theta, Real)
                return _theta
            try:
                # Factor i in the exponent, pulling to the left to
                # get into exp(i * theta) form.
                for operand in expr.exponent.operands:
                    # Deduce the operands are complex numbers ahead of
                    # time in case automation is disabled.
                    deduce_in_number_set(operand, Complex)
                factorization = expr.inner_expr().exponent.factorization(
                    i, pull='left', group_remainder=True, preserve_all=True)
                expr = factorization.rhs
                assert isinstance(expr.exponent, Mult)
                assert expr.exponent.factors.is_double()
                assert expr.exponent.factors[0] == i
                _theta = expr.exponent.factors[1]
                _theta_ns = deduce_number_set(_theta).domain
                if not Real.includes(_theta_ns):
                    raise_not_valid_form("%s known to be %s but not Real." %
                                         (_theta, _theta_ns))
                # reduction: exp(i * theta) = orig_expr
                reduction = factorization.derive_reversed()
                # Add the reduction and return theta.
                add_reduction(reduction, _theta)
                return _theta
            except ValueError:
                raise_not_valid_form()
    if isinstance(expr, Neg):
        # expr = -exp(i*theta0) = exp(i*(theta0 + pi)) = exp(i*theta)
        inner_reductions = set()
        # obtain the theta of the negated expression.
        _theta0 = unit_length_complex_polar_angle(expr.operand,
                                                  reductions=inner_reductions)
        # theta = theta0 + pi
        _theta = Add(_theta0, pi)
        if simplify:
            # simplify theta
            theta_simplification = _theta.simplification()
            inner_reductions.add(theta_simplification)
            _theta = theta_simplification.rhs
        # reduction: exp(i*theta) = orig_expr [via -exp(i*theta0)]
        reduction = unit_length_complex_polar_negation.instantiate(
            {theta: _theta0},
            replacements=inner_reductions,
            auto_simplify=False)
        # Add the reduction and return theta.
        add_reduction(reduction, _theta)
        return _theta

    raise_not_valid_form()
Example #18
0
# transferred by wdc 3/11/2020
abs_ineq = Forall(
    (x, y), Iff(
        LessThanEquals(
            Abs(x), y), And(
                LessThanEquals(
                    Neg(y), x), LessThanEquals(
                        x, y))), domain=Real, conditions=[
                            GreaterThanEquals(
                                y, zero)])
abs_ineq

# transferred by wdc 3/11/2020
triangle_inequality = Forall([a, b], LessThanEquals(
    Abs(Add(a, b)), Add(Abs(a), Abs(b))), domain=Complex)
triangle_inequality

# transferred by wdc 3/11/2020
abs_prod = Forall(x_etc,
                  Equals(Abs(Mult(x_etc)),
                         Mult(Etcetera(Abs(x_multi)))),
                  domain=Complex)
abs_prod

# transferred by wdc 3/11/2020
abs_frac = Forall([a, b],
                  Equals(Abs(frac(a, b)), frac(Abs(a), Abs(b))),
                  domain=Complex)
abs_frac
Example #19
0
def complex_polar_coordinates(expr,
                              *,
                              radius_must_be_nonneg=True,
                              nonneg_radius_preferred=True,
                              do_include_unit_length_reduction=True,
                              reductions=None):
    '''
    Given an expression, expr, of the complex number polar form,
        r * exp(i * theta),
    or something obviously equivalent to this, where r and theta are 
    Real (and r is preferably RealNonNeg) under the given assumptions, 
    return
        (r, theta)
    as a tuple pair. If defaults.automation=False, the r and theta must
    already be known to be RealNonNeg and Real respectively. If
    defaults.automation=True, we may attempt to prove these through 
    automation.
    
    If radius_must_be_nonneg and nonneg_radius_preferred are False, 
    we won't worry about ensuring that r is non-negative (so the result
    can be ambiguous).  If radius_must_be_nonneg is True, a ValueError
    will be raised if we can't convert to a form where r is known to be
    non-negative.
    
    If expr is not exactly in this complex number polar form and
    'reductions' is provided as a set, add to the 'reductions' set
    an equation that equates the exact form on the left with the
    original form on the right.  This may be useful to use as
    'reductions' in instantiations of theorems that employ the
    complex number polar form so it may perform proper reductions
    to the desired form.  For example, if expr=5 is provided,
    the added reduction will be
        5 * exp(i * 0) = 5.
    
    If do_include_unit_length_reduction is True,  we will included
    reductions so that it will reduce from the unit length
    form as well.  For example, if expr=1 is provided, the added
    reductions will be
        exp(i * 0) = 1
        1 * 1 = 1.
    This also works in a way that cascades when reducing from the
    general polar form:
        1 * exp(i * 0) = 1 * 1 = 1
    
    Raise ValueError if the expr is not obviously equivalent to a
    complex number polar form.

    Also see unit_length_complex_polar_angle.
    '''
    from . import complex_polar_negation, complex_polar_radius_negation
    from proveit.logic import InSet, Equals
    from proveit.numbers import deduce_in_number_set, deduce_number_set
    from proveit.numbers import zero, one, e, i, pi
    from proveit.numbers import Real, RealNonPos, RealNonNeg, Complex
    from proveit.numbers import Add, LessEq, Neg, Mult, Exp
    orig_expr = expr
    automation = defaults.automation
    simplify = defaults.auto_simplify
    if reductions is None: reductions = set()

    def add_reduction(reduction, _radius, _theta):
        '''
        Add the given reduction.  First check that its left and
        rights sides are as expected: the left should be the polar
        form and the right should be the original expression.
        '''
        polar_form = Mult(_radius, Exp(e, Mult(i, _theta)))
        assert (isinstance(reduction, Judgment)
                and isinstance(reduction.expr, Equals)
                and reduction.lhs == polar_form and reduction.rhs
                == orig_expr), ("Reduction, %s, not a judgement "
                                "for %s = %s" %
                                (reduction, polar_form, orig_expr))
        if do_include_unit_length_reduction and _radius == one:
            # As a unit length complex number, let's include the
            # reduction from the unit length form in case a unit length
            # formula is applied (cover the bases).
            # The 'automation' allowed here is negligible (assuming
            # we have already proven appropriate set membership by this
            # point).
            reductions.add(reduction.inner_expr().lhs.eliminate_one(
                0, automation=True))
            # But prepare for a multi-stage reduction:
            # 1 * exp[i * theta] = 1 * orig_expr = orig_expr
            reductions.add(
                Mult(one, orig_expr).one_elimination(0, automation=True))
        elif reduction.lhs != reduction.rhs:
            reductions.add(reduction)

    def raise_not_valid_form(extra_msg=None):
        if extra_msg is None: extra_msg = ""
        raise ValueError("%s not in a form that is obviously "
                         "reducible from an r * exp(i*theta) form. %s" %
                         (orig_expr, extra_msg))

    if (isinstance(expr, Exp)
            or (isinstance(expr, Neg) and isinstance(expr.operand, Exp))):
        # exp(i * theta) reduced from 1 * exp(i * theta).
        # or exp(i * (theta + pi)) reduced from -exp(i * theta).
        inner_reductions = set()
        _theta = unit_length_complex_polar_angle(expr,
                                                 reductions=inner_reductions)
        deduce_in_number_set(_theta, Complex)
        deduce_in_number_set(Mult(i, _theta), Complex)
        deduce_in_number_set(Exp(e, Mult(i, _theta)), Complex)
        _r = one
        expr = Mult(_r, Exp(e, Mult(i, _theta)))
        # reduction: 1*exp(i * theta) = exp(i * theta)
        reduction = expr.one_elimination(0, preserve_all=True)
        # reduction: 1*exp(i * theta) = orig_expr
        if len(inner_reductions) > 0:
            reduction = reduction.inner_expr().rhs.substitute(
                inner_reductions.pop().rhs, preserve_all=True)
        # Add the reduction and return the coordinates.
        add_reduction(reduction, _r, _theta)
        return (_r, _theta)
    elif isinstance(expr, Neg):
        # expr = -(r*exp(i*theta0)) = r*exp(i*(theta0 + pi))
        inner_reductions = set()
        # obtain the theta of the negated expression.
        _r, _theta0 = complex_polar_coordinates(
            expr.operand,
            radius_must_be_nonneg=radius_must_be_nonneg,
            nonneg_radius_preferred=nonneg_radius_preferred,
            reductions=inner_reductions)
        # theta = theta0 + pi
        _theta = Add(_theta0, pi)
        if defaults.auto_simplify:
            # simplify theta
            theta_simplification = _theta.simplification()
            inner_reductions.add(theta_simplification)
            _theta = theta_simplification.rhs
        deduce_in_number_set(_theta, Complex)
        deduce_in_number_set(Mult(i, _theta), Complex)
        deduce_in_number_set(Exp(e, Mult(i, _theta)), Complex)
        # reduction: r*exp(i*theta) = orig_expr [via -(r*exp(i*theta0))]
        reduction = complex_polar_negation.instantiate(
            {
                r: _r,
                theta: _theta0
            },
            replacements=inner_reductions,
            auto_simplify=False)
        # Add the reduction and return the coordinates.
        add_reduction(reduction, _r, _theta)
        return (_r, _theta)

    # Search for an exponentiation factor with base of 'e' and an
    # imaginary number in the exponent.
    complex_exp_factor_idx = None
    if isinstance(expr, Mult):
        i_factor_idx = None
        for idx, factor in enumerate(expr.factors):
            if isinstance(factor, Exp) and factor.base == e:
                # exp(x) type factor; check for imaginary number in
                # exponent.
                contains_imaginary_factor = False
                sub_expr = factor.exponent
                if isinstance(sub_expr, Neg):
                    sub_expr = sub_expr.operand
                if isinstance(sub_expr, Mult):
                    if i in sub_expr.operands.entries:
                        contains_imaginary_factor = True
                else:
                    contains_imaginary_factor = (sub_expr == i)
                if contains_imaginary_factor:
                    # Found imaginary number in an exponent.
                    if ((complex_exp_factor_idx is not None)
                            or (i_factor_idx is not None)):
                        # We already have an imaginary number in
                        # an exponent.  We can only have one.
                        raise_not_valid_form()
                    complex_exp_factor_idx = idx
                    deduce_in_number_set(sub_expr, Complex)
    if complex_exp_factor_idx is None:
        # No exp(i theta) factor.  Let's multiply by exp(i * 0).
        exp_i0 = Exp(e, Mult(i, zero))
        expr = Mult(expr, exp_i0)
        inner_reductions = set()
        _r, _theta = complex_polar_coordinates(
            expr,
            radius_must_be_nonneg=radius_must_be_nonneg,
            nonneg_radius_preferred=nonneg_radius_preferred,
            do_include_unit_length_reduction=False,
            reductions=inner_reductions)
        assert _theta == zero
        deduce_in_number_set(exp_i0, Complex)
        # reduction: r * exp(i * theta) = orig_expr * exp(i * 0)
        if len(inner_reductions) > 0:
            reduction = inner_reductions.pop()
        else:
            reduction = Equals(expr, expr).conclude_via_reflexivity()
        # reduction: r * exp(i * theta) = orig_expr
        reduction = reduction.inner_expr().rhs.simplify(
            preserve_expr=orig_expr)
        add_reduction(reduction, _r, _theta)
        return (_r, _theta)

    # expr in ... * exp(... * i * ...) * ... form
    # Obtain the theta from exp(... * i * ...) = exp[i * theta0].
    inner_reductions = set()
    _theta0 = unit_length_complex_polar_angle(
        expr.factors[complex_exp_factor_idx], reductions=inner_reductions)
    expr = Mult(*expr.factors.entries[:complex_exp_factor_idx],
                Exp(e, Mult(i, _theta0)),
                *expr.factors.entries[complex_exp_factor_idx + 1:])
    # reduction: ... * expr[i * theta0] * ... = orig_expr
    if len(inner_reductions) > 0:
        reduction = expr.inner_expr().operands[1].substitution(
            inner_reductions.pop().rhs, preserve_all=True)
    else:
        reduction = Equals(expr, expr).conclude_via_reflexivity()
    if not expr.operands.is_double() or complex_exp_factor_idx != 1:
        # Pull the exp(i*theta) type factor to the right.
        # reduction: r0 * exp(i * theta0) = orig_expr
        for factor in expr.factors:
            # Deduce the factors are complex numbers ahead of time
            # in case automation is disabled.
            deduce_in_number_set(factor, Complex)
        reduction = reduction.inner_expr().lhs.factor(complex_exp_factor_idx,
                                                      pull='right',
                                                      group_remainder=True,
                                                      preserve_all=True)
        expr = reduction.lhs
    # expr: r0 * exp(i * theta0)
    assert expr.operands.is_double() and isinstance(expr.operands[1], Exp)
    # Check that r0 is real and that we know it's relation with zero.
    _r0 = expr.operands[0]
    _r0_ns = deduce_number_set(_r0).domain
    if Real.includes(_r0_ns):
        InSet(_r0, Real).prove()
    else:
        raise_not_valid_form("%s not known to be real." % _r0)
    is_known_nonneg = RealNonNeg.includes(_r0_ns)
    is_known_nonpos = RealNonPos.includes(_r0_ns)
    if radius_must_be_nonneg:
        # We must know the relationship between r0 and 0 so we
        # can ensure r is non-negative.
        if not nonneg_radius_preferred:
            ValueError("nonneg_radius_preferred must be True if "
                       "radius_must_be_nonneg is True.")
        if not (is_known_nonneg or is_known_nonpos):
            raise_not_valid_form("Relation of %s to 0 is unknown and "
                                 "radius_must_be_nonneg is True." % _r0)
    if nonneg_radius_preferred and is_known_nonpos:
        # r0 <= 0, so we must negate it and add pi to the angle.
        inner_reductions = {reduction}
        # theta: theta + pi
        _theta = Add(_theta0, pi)
        if simplify:
            # simplify theta
            theta_simplification = _theta.simplification()
            inner_reductions.add(theta_simplification)
            _theta = theta_simplification.rhs
        # r: -r0
        _r = Neg(_r0)
        if simplify:
            # simplify radius
            radius_simplification = _r.simplification()
            inner_reductions.add(radius_simplification)
            _r = radius_simplification.rhs
        # reduction: r*exp(i*theta) = orig_expr [via r0*exp(i*theta0))]
        reduction = complex_polar_radius_negation.instantiate(
            {
                r: _r0,
                theta: _theta0
            },
            replacements=inner_reductions,
            auto_simplify=False)
    else:
        _r, _theta = _r0, _theta0
    # Add the reduction and return the coordinates.
    add_reduction(reduction, _r, _theta)
    return (_r, _theta)
Example #20
0
from proveit.logic import Forall, InSet, Equals
from proveit.numbers import Integer, Natural, NaturalPos, Real, RealPos, RealNeg, Complex
from proveit.numbers import Add, GreaterThan, LessThan
from proveit.common import a, b, x, a_etc, c_etc, x_etc, y_etc, z_etc, v_etc, w_etc
from proveit.numbers.common import zero
from proveit import begin_theorems, end_theorems

begin_theorems(locals())

add_int_closure = Forall([x_etc], InSet(Add(x_etc), Integer), domain=Integer)
add_int_closure

add_nat_closure = Forall((a, b), InSet(Add(a, b), Natural), domain=Natural)
add_nat_closure

add_real_closure = Forall([x_etc], InSet(Add(x_etc), Real), domain=Real)
add_real_closure

add_complex_closure = Forall([x_etc],
                             InSet(Add(x_etc), Complex),
                             domain=Complex)
add_complex_closure

add_nat_pos_closure = Forall((a_etc, b, c_etc),
                             InSet(Add(a_etc, b, c_etc), NaturalPos),
                             domain=Natural,
                             conditions=[GreaterThan(b, zero)])
add_nat_pos_closure

add_zero = Forall(x, Equals(Add(zero, x), x), domain=Complex)
add_zero
Example #21
0
from .common import zero, one, two
from proveit import begin_axioms, end_axioms

begin_axioms(locals())

# Define the set of Natural as, essentially, the minimum set that contains zero and all of its successors;
# that is, n is in Natural iff n is in all sets that contain zero and all
# successors.
naturals_def = Forall(
    n,
    Equals(
        InSet(n, Natural),
        Forall(
            S,
            Implies(
                And(InSet(zero, S), Forall(x, InSet(Add(x, one), S),
                                           domain=S)), InSet(n, S)))))

# Define the length of an ExpressionList inductively.
expr_list_length_def = And(
    Equals(Len(), zero),
    Forall((x_multi, y), Equals(Len(x_etc, y), Add(Len(x_etc), one))))

naturals_pos_def = Forall(n,
                          Iff(InSet(n, NaturalPos), GreaterThanEquals(n, one)),
                          domain=Natural)
naturals_pos_def

integers_def = Equals(Integer,
                      Union(Natural, SetOfAll(n, Neg(n), domain=Natural)))
Example #22
0
from proveit import Operation
from proveit.logic import Forall, InSet, NotInSet, NotEquals, And, Implies, Equals, Boolean
from proveit.numbers import Integer, Natural, NaturalPos, Interval, Real, RealPos, Complex
from proveit.numbers import Add, GreaterThan, GreaterThanEquals, LessThan, LessThanEquals
from proveit.numbers import Len
from proveit.common import a, b, n, m, x, y, P, S, x_multi, x_etc, Px_etc
from proveit.numbers import zero, one, two, three, four, five, six, seven, eight, nine
from proveit.numbers.common import Pzero, Pm, P_mAddOne, Pn
from proveit import begin_theorems, end_theorems

begin_theorems(locals())

zero_in_nats = InSet(zero, Natural)

successive_nats = Forall(n, InSet(Add(n, one), Natural), domain=Natural)

induction_lemma = Forall(n,
                         Forall(
                             S,
                             Implies(
                                 And(
                                     InSet(zero, S),
                                     Forall(x, InSet(Add(x, one), S),
                                            domain=S)), InSet(n, S))),
                         domain=Natural)

induction = Forall(
    P,
    Implies(And(Pzero, Forall(m, P_mAddOne, domain=Natural, conditions=[Pm])),
            Forall(n, Pn, Natural)))
Example #23
0
not_equals_is_less_than_or_greater_than = Forall((a, x),
                                                 Or(LessThan(x, a),
                                                    GreaterThan(x, a)),
                                                 domain=Real,
                                                 conditions=[NotEquals(x, a)])
not_equals_is_less_than_or_greater_than

shift_less_than_to_less_than_equals = Forall(
    (a, b),
    LessThanEquals(a, b),
    domain=Integer,
    conditions=[LessThan(Sub(a, one), b)])
shift_less_than_to_less_than_equals

less_than_equals_add_right = Forall([a, b, c],
                                    LessThanEquals(Add(a, c), Add(b, c)),
                                    domain=Real,
                                    conditions=[LessThanEquals(a, b)])
less_than_equals_add_right

less_than_equals_add_left = Forall([a, b, c],
                                   LessThanEquals(Add(c, a), Add(c, b)),
                                   domain=Real,
                                   conditions=[LessThanEquals(a, b)])
less_than_equals_add_left

less_than_equals_subtract = Forall([a, b, c],
                                   LessThanEquals(Sub(a, c), Sub(b, c)),
                                   domain=Real,
                                   conditions=[LessThanEquals(a, b)])
less_than_equals_subtract