示例#1
0
    if expressions.num_entries() == 0:
        from proveit.logic.booleans.conjunction import \
            empty_conjunction
        return empty_conjunction
    if expressions.is_double():
        from . import and_if_both
        return and_if_both.instantiate({
            A: expressions[0],
            B: expressions[1]
        },
                                       assumptions=assumptions)
    else:
        from . import and_if_all
        _m = expressions.num_elements(assumptions)
        return and_if_all.instantiate({
            m: _m,
            A: expressions
        },
                                      assumptions=assumptions)


# Register these expression equivalence methods:
InnerExpr.register_equivalence_method(And, 'commutation', 'commuted',
                                      'commute')
InnerExpr.register_equivalence_method(And, 'group_commutation',
                                      'group_commuted', 'group_commute')
InnerExpr.register_equivalence_method(And, 'association', 'associated',
                                      'associate')
InnerExpr.register_equivalence_method(And, 'disassociation', 'disassociated',
                                      'disassociate')
示例#2
0
def reduce_operands(inner_expr,
                    in_place=True,
                    must_evaluate=False,
                    assumptions=USE_DEFAULTS):
    '''
    Attempt to return an InnerExpr object that is provably equivalent to
    the given inner_expr but with simplified operands at the
    inner-expression level.
    If in_place is True, the top-level expression must be a Judgment
    and the simplified Judgment is derived instead of an equivalence
    relation.
    If must_evaluate is True, the simplified
    operands must be irreducible values (see is_irreducible_value).
    '''
    # Any of the operands that can be simplified must be replaced with
    # their simplification.
    from proveit import InnerExpr, ExprRange
    assert isinstance(inner_expr, InnerExpr), \
        "Expecting 'inner_expr' to be of type 'InnerExpr'"
    inner = inner_expr.expr_hierarchy[-1]
    substitutions = []
    while True:
        all_reduced = True
        for operand in inner.operands:
            if (not is_irreducible_value(operand)
                    and not isinstance(operand, ExprRange)):
                # The operand isn't already irreducible, so try to
                # simplify it.
                if must_evaluate:
                    operand_eval = operand.evaluation(assumptions=assumptions)
                else:
                    operand_eval = operand.simplification(
                        assumptions=assumptions)
                if must_evaluate and not is_irreducible_value(
                        operand_eval.rhs):
                    msg = 'Evaluations expected to be irreducible values'
                    raise EvaluationError(msg, assumptions)
                if operand_eval.lhs != operand_eval.rhs:
                    # Compose map to replace all instances of the
                    # operand within the inner expression.
                    global_repl = Lambda.global_repl(inner, operand)
                    lambda_map = inner_expr.repl_lambda().compose(global_repl)
                    # substitute in the evaluated value
                    if in_place:
                        subbed = operand_eval.sub_right_side_into(lambda_map)
                        inner_expr = InnerExpr(subbed,
                                               inner_expr.inner_expr_path)
                    else:
                        sub = operand_eval.substitution(lambda_map)
                        inner_expr = InnerExpr(sub.rhs,
                                               inner_expr.inner_expr_path)
                        substitutions.append(sub)
                    all_reduced = False
                    # Start over since there may have been multiple
                    # substitutions:
                    break
        if all_reduced:
            break  # done!
        inner = inner_expr.expr_hierarchy[-1]

    if not in_place and len(substitutions) > 1:
        # When there have been multiple substitutions, apply
        # transtivity over the chain of substitutions to equate the
        # end-points.
        Equals.apply_transitivities(substitutions, assumptions)
    return inner_expr
示例#3
0
        '''
        return groupCommutation(self, initIdx, finalIdx, length, disassociate, assumptions)
        
    def association(self, startIdx, length, assumptions=USE_DEFAULTS):
        '''
        Given numerical operands, deduce that this expression is equal to a form in which operands in the
        range [startIdx, startIdx+length) are grouped together.
        For example, (a + b + ... + y + z) = (a + b ... + (l + ... + m) + ... + y + z)
        '''
        from ._theorems_ import association
        return apply_association_thm(self, startIdx, length, association, assumptions)

    def disassociation(self, idx, assumptions=USE_DEFAULTS):
        '''
        Given numerical operands, deduce that this expression is equal to a form in which the operand
        at index idx is no longer grouped together.
        For example, (a + b ... + (l + ... + m) + ... + y+ z) = (a + b + ... + y + z)
        '''
        from ._theorems_ import disassociation
        return apply_disassociation_thm(self, idx, disassociation, assumptions)

# Register these expression equivalence methods:
InnerExpr.register_equivalence_method(Mult, 'commutation', 'commuted', 'commute')
InnerExpr.register_equivalence_method(Mult, 'groupCommutation', 'groupCommuted', 'groupCommute')
InnerExpr.register_equivalence_method(Mult, 'association', 'associated', 'associate')
InnerExpr.register_equivalence_method(Mult, 'disassociation', 'disassociated', 'disassociate')
InnerExpr.register_equivalence_method(Mult, 'distribution', 'distributed', 'distribute')
InnerExpr.register_equivalence_method(Mult, 'factorization', 'factorized', 'factor')
InnerExpr.register_equivalence_method(Mult, 'exponentCombination', 'combinedExponents', 'combineExponents')

示例#4
0
                else:
                    return range_len_is_nat.instantiate(
                        {
                            f: range_lambda,
                            i: range_start,
                            j: range_end
                        },
                        assumptions=assumptions)

    def do_reduced_simplification(self, assumptions=USE_DEFAULTS, **kwargs):
        '''
        A simplification of a Len operation computes the length as a sum
        of the lengths of each item of the ExprTuple operand, returning
        the equality between the Len expression and this computation,
        simplified to the extent possible.  An item may be a singular element
        (contribution 1 to the length) or an iteration contributing its length.
        '''
        return self._computation(must_evaluate=False, assumptions=assumptions)

    def do_reduced_evaluation(self, assumptions=USE_DEFAULTS, **kwargs):
        '''
        Return the evaluation of the length which equates that Len expression
        to an irreducible result.
        '''
        return self._computation(must_evaluate=True, assumptions=assumptions)


# Register these expression equivalence methods:
InnerExpr.register_equivalence_method(Len, 'computation', 'computed',
                                      'compute')
示例#5
0
        This works only if the operand x is an instance of the Add
        class at its outermost level, e.g. x = Add(a, b, …, n). The
        operands of that Add class can be other things, but the
        extraction is guaranteed to work only if the inner operands
        a, b, etc., are simple.
        '''
        from . import ceil_of_real_plus_int
        return apply_rounding_extraction(
            self, ceil_of_real_plus_int, idx_to_extract, assumptions)

    def deduce_in_number_set(self, number_set, assumptions=USE_DEFAULTS):
        '''
        Given a number set number_set, attempt to prove that the given
        Ceil expression is in that number set using the appropriate
        closure theorem.
        '''
        from proveit.numbers.rounding import ceil_is_an_int
        from proveit.numbers.rounding import ceil_real_pos_closure

        return rounding_deduce_in_number_set(
            self, number_set, ceil_is_an_int, ceil_real_pos_closure,
            assumptions)


# Register these generic expression equivalence methods:
InnerExpr.register_equivalence_method(
    Ceil, 'rounding_elimination', 'rounding_eliminated', 'rounding_eliminate')
InnerExpr.register_equivalence_method(
    Ceil, 'rounding_extraction', 'rounding_extracted', 'rounding_extract')
示例#6
0
                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

    def side_effects(self, judgment):
        return
        yield


# outside any specific class:
# special Exp case of square root


def sqrt(base):
    '''
    Special function for square root version of an exponential.
    '''
    return Exp(base, frac(one, two))


# Register these expression equivalence methods:
InnerExpr.register_equivalence_method(Exp, 'distribution', 'distributed',
                                      'distribute')
示例#7
0
            if pull == 'left':
                w_etc_sub = factored_numer.operands[:-1]
                x_sub = factored_numer.operands[-1]
                z_etc_sub = []
            elif pull == 'right':
                w_etc_sub = []
                x_sub = factored_numer.operands[0]
                z_etc_sub = factored_numer.operands[1:]
            eqns.append(frac_in_prod_rev.instantiate({w_etc:w_etc_sub, x:x_sub, y:self.denominator, z_etc:z_etc_sub}))
            num = len(the_factor.operands) if isinstance(the_factor, Mult) else 1
            if group_factor and num > 1:
                if pull=='left':
                    eqns.append(eqns[-1].rhs.group(end_idx=num, assumptions=assumptions))
                elif pull=='right':
                    eqns.append(eqns[-1].rhs.group(start_idx=-num, assumptions=assumptions))
        return Equals(eqns[0].lhs, eqns[-1].rhs).prove(assumptions)
    """


def frac(numer, denom):
    return Div(numer, denom)


# Register these expression equivalence methods:
InnerExpr.register_equivalence_method(Div, 'deep_one_eliminations',
                                      'deep_eliminated_ones',
                                      'deep_eliminate_ones')
InnerExpr.register_equivalence_method(Div, 'exponent_combination',
                                      'combined_exponents',
                                      'combine_exponents')
示例#8
0
            else:
                return multNegRightDouble.specialize(
                    {a: mult_expr.operands[0]}, assumptions=assumptions)
        aVal = mult_expr.operands[:idx]
        bVal = mult_expr.operands[idx]
        cVal = mult_expr.operands[idx + 1:]
        mVal = num(len(aVal))
        nVal = num(len(cVal))
        return multNegAnyDouble.specialize(
            {
                m: mVal,
                n: nVal,
                AA: aVal,
                B: bVal,
                CC: cVal
            },
            assumptions=assumptions)


# Register these expression equivalence methods:
InnerExpr.register_equivalence_method(Neg, 'doubleNegSimplification',
                                      'doubleNegSimplified',
                                      'doubleNegSimplify')
InnerExpr.register_equivalence_method(Neg, 'distribution', 'distributed',
                                      'distribute')
InnerExpr.register_equivalence_method(Neg, 'factorization', 'factorized',
                                      'factor')
InnerExpr.register_equivalence_method(Neg, 'innerNegMultSimplification',
                                      'innerNegMultSimplified',
                                      'innerNegMultSimplify')
示例#9
0
            if idx == 0:
                return mult_neg_left_double.instantiate(
                    {a: mult_expr.operands[1]}, assumptions=assumptions)
            else:
                return mult_neg_right_double.instantiate(
                    {a: mult_expr.operands[0]}, assumptions=assumptions)
        _a = mult_expr.operands[:idx]
        _b = mult_expr.operands[idx]
        _c = mult_expr.operands[idx + 1:]
        _m = _a.num_elements(assumptions)
        _n = _c.num_elements(assumptions)
        return mult_neg_any_double.instantiate(
            {m: _m, n: _n, a: _a, b: _b, c: _c}, assumptions=assumptions)


# Register these expression equivalence methods:
InnerExpr.register_equivalence_method(
    Neg,
    'double_neg_simplification',
    'double_neg_simplified',
    'double_neg_simplify')
InnerExpr.register_equivalence_method(
    Neg, 'distribution', 'distributed', 'distribute')
InnerExpr.register_equivalence_method(
    Neg, 'factorization', 'factorized', 'factor')
InnerExpr.register_equivalence_method(
    Neg,
    'inner_neg_mult_simplification',
    'inner_neg_mult_simplified',
    'inner_neg_mult_simplify')
示例#10
0
    def _sub_one_side_into(self, prob_relation_or_inner_expr, *, which_side,
                           **defaults_config):
        '''
        Helper method for sub_[left/right]_side_into.
        '''
        from . import lhs_prob_via_equiv, rhs_prob_via_equiv
        equiv = self
        if which_side == 'left':
            thm = lhs_prob_via_equiv
            orig_circuit = equiv.rhs
        elif which_side == 'right':
            thm = rhs_prob_via_equiv
            orig_circuit = equiv.lhs
        else:
            raise ValueError("'which_side' must either be 'left' or 'right'")
        if isinstance(prob_relation_or_inner_expr, Judgment):
            prob_relation_or_inner_expr = prob_relation_or_inner_expr.expr
        if isinstance(prob_relation_or_inner_expr, InnerExpr):
            # This should be an inner expresion of a probability
            # over a quantum circuit.
            inner_expr = prob_relation_or_inner_expr
            expr_hierarchy = inner_expr.expr_hierarchy
            for _k, _expr in enumerate(reversed(expr_hierarchy)):
                circuit_or_lambda_map = None
                if isinstance(_expr, Prob) and isinstance(
                        _expr.operand, Qcircuit):
                    if _k == 2:
                        # Just a quantum circuit in a probability
                        circuit_or_lambda_map = _expr.operand
                    else:
                        # A portion of a quantum circuit.
                        circuit_or_lambda_map = InnerExpr(
                            _expr, inner_expr.inner_expr_path[-_k + 2:])
                    prob_relation_lambda = InnerExpr(
                        expr_hierarchy[0],
                        inner_expr.inner_expr_path[:-_k]).repl_lambda()
                    break
            if circuit_or_lambda_map is None:
                raise NotImplementedError(
                    "Qcircuit.sub_[left/right]_side_into only "
                    "implemented to apply to an inner expr within "
                    "a Prob on a Qcircuit")
            if circuit_or_lambda_map != orig_circuit:
                # Not a direct probability substitution.
                if which_side == 'left':
                    equiv = equiv.derive_reversed()
                    thm = rhs_prob_via_equiv
                equiv = equiv.substitution(circuit_or_lambda_map)
        else:
            # prob_relation_or_inner_expr should be a probability
            # relation (it isn't an InnerExpr).
            prob_relation = prob_relation_or_inner_expr
            qcircuit = Qcircuit._extract_circuit_from_prob_relation(
                prob_relation)
            if qcircuit != orig_circuit:
                # Let's see if orig_circuit is a portion of qcircuit:
                if which_side == 'left':
                    equiv = self.derive_reversed().substitution(qcircuit)
                    thm = rhs_prob_via_equiv
                else:
                    equiv = self.substitution(qcircuit)
            prob_relation_lambda = Lambda.global_repl(prob_relation,
                                                      Prob(qcircuit))

        # Prove the probability relation.
        return thm.instantiate({
            Q: prob_relation_lambda,
            A: equiv.lhs,
            B: equiv.rhs
        })
示例#11
0
        if summand_lambda not in (lesser_lambda, greater_lambda):
            raise ValueError("Expecting summand_relation to be a universally "
                             "quantified number relation (< or <=) "
                             "involving the summand, %d, not %s" %
                             (self.summand, summand_relation))
        _a = lesser_lambda
        _b = greater_lambda
        _S = self.domain
        if isinstance(summand_relation.instance_expr, LessEq):
            # Use weak form
            sum_rel_impl = weak_summation_from_summands_bound.instantiate(
                {
                    a: _a,
                    b: _b,
                    S: _S
                }, assumptions=assumptions)
        else:
            # Use strong form
            sum_rel_impl = strong_summation_from_summands_bound.instantiate(
                {
                    a: _a,
                    b: _b,
                    S: _S
                }, assumptions=assumptions)
        sum_relation = sum_rel_impl.derive_consequent(assumptions)
        if summand_lambda == greater_lambda:
            return sum_relation.with_direction_reversed()
        return sum_relation

InnerExpr.register_equivalence_method(Sum, 'factorization', 'factorized',
                                      'factor')
示例#12
0
        This works only if the operand x is an instance of the Add
        class at its outermost level, e.g. x = Add(a, b, …, n). The
        operands of that Add class can be other things, but the
        extraction is guaranteed to work only if the inner operands
        a, b, etc., are simple.
        '''
        from ._theorems_ import roundOfRealPlusInt
        return apply_roundingExtraction(self, roundOfRealPlusInt,
                                        idx_to_extract, assumptions)

    def deduceInNumberSet(self, number_set, assumptions=USE_DEFAULTS):
        '''
        Given a number set number_set, attempt to prove that the given
        Round expression is in that number set using the appropriate
        closure theorem.
        '''
        from proveit.number.rounding._axioms_ import roundIsAnInt
        from proveit.number.rounding._theorems_ import roundRealPosClosure

        return rounding_deduceInNumberSet(self, number_set, roundIsAnInt,
                                          roundRealPosClosure, assumptions)


# Register these generic expression equivalence methods:
InnerExpr.register_equivalence_method(Round, 'roundingElimination',
                                      'roundingEliminated',
                                      'roundingEliminate')
InnerExpr.register_equivalence_method(Round, 'roundingExtraction',
                                      'roundingExtracted', 'roundingExtract')
示例#13
0
            raise IndexError("Index or indices out of bounds: {0}. "
                             "subset indices i should satisfy "
                             "0 ≤ i ≤ {1}.".format(unexpected_indices_set,
                                                   len(valid_indices_set) - 1))
        if len(subset_indices_list) > len(subset_indices_set):
            # we have repeated indices, so let's find them to use in
            # feedback/error message
            repeated_indices_set = set()
            for elem in subset_indices_set:
                if subset_indices_list.count(elem) > 1:
                    repeated_indices_set.add(elem)
            raise ValueError("The subset_indices specification contains "
                             "repeated indices, with repeated index or "
                             "indices: {}. Each index value should appear at "
                             "most 1 time.".format(repeated_indices_set))
        # if we made it this far and proper_subset = True,
        # confirm that the subset indices are compatible with a proper
        # subset instead of an improper subset
        if proper_subset and len(subset_indices_set) == len(valid_indices_set):
            raise ValueError("The subset indices are not compatible with a "
                             "proper subset (too many elements).")


# Register these expression equivalence methods:
InnerExpr.register_equivalence_method(Set, 'permutation', 'permuted',
                                      'permute')
InnerExpr.register_equivalence_method(Set, 'permutation_move', 'moved', 'move')
InnerExpr.register_equivalence_method(Set, 'permutation_swap', 'swapped',
                                      'swap')
InnerExpr.register_equivalence_method(Set, 'reduction', 'reduced', 'reduce')