Beispiel #1
0
 def _createOperand(instanceVars, instanceExpr, conditions):
     return Lambda(instanceVars, instanceExpr, conditions)
Beispiel #2
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 Naturals, k-(j+1) \in Naturals} 
        |- (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._theorems_ import (
            merge, merge_front, merge_back, merge_extension, merge_pair,
            merge_series)
        from proveit._common_ import f, i, j, k, l, x
        from proveit.number 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)
        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.extractArgument(front_singles[0])
            j_sub = lambda_map.extractArgument(front_singles[-1])
            if len(front_singles) == 2:
                # Merge a pair of singular items.
                front_merger = merge_pair.specialize(
                    {
                        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.specialize(
                    {
                        f: lambda_map,
                        x: front_singles,
                        i: i_sub,
                        j: j_sub
                    },
                    assumptions=assumptions)
            eq.update(
                front_merger.substitution(self.innerExpr()[:first_range_pos],
                                          assumptions=assumptions))

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

        if len(eq.expr) == 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.specialize({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.extractArgument(eq.expr[1])
                    if _k == Add(_j, one):
                        merger = merge_extension.specialize(
                            {
                                f: lambda_map,
                                i: _i,
                                j: _j
                            },
                            assumptions=assumptions)
                    else:
                        merger = merge_back.specialize(
                            {
                                f: lambda_map,
                                i: _i,
                                j: _j,
                                k: _k
                            },
                            assumptions=assumptions)
            else:
                # Merge a singular item and ExprRange.
                iSub = lambda_map.extractArgument(eq.expr[0])
                jSub, kSub = eq.expr[1].start_index, eq.expr[1].end_index
                merger = \
                    merge_front.specialize({f:lambda_map, i:iSub, j:jSub,
                                            k:kSub}, assumptions=assumptions)
            eq.update(merger)
            return eq.relation

        while len(eq.expr) > 1:
            front_merger = ExprTuple(*eq.expr[:2]).merger(assumptions)
            eq.update(
                front_merger.substitution(eq.expr.innerExpr(assumptions)[:2],
                                          assumptions=assumptions))
        return eq.relation
Beispiel #3
0
    def basic_replaced(self,
                       repl_map,
                       *,
                       allow_relabeling=False,
                       requirements=None):
        '''
        Returns this expression with sub-expressions substituted
        according to the replacement map (repl_map) dictionary.

        When an operater of an Operation is substituted by a Lambda map,
        the operation itself will be substituted with the Lambda map
        applied to the operands.  For example, substituting
        f : (x,y) -> x+y
        on f(a, b) will result in a+b.  When performing operation
        substitution with a range of parameters, the Lambda map
        application will require the number of these parameters
        to equal with the number of corresponding operand elements.
        For example,
        f : (a, b_1, ..., b_n) -> a*b_1 + ... + a*b_n
        n : 3
        applied to f(w, x, y, z) will result in w*x + w*y + w*z provided
        that |(b_1, ..., b_3)| = |(x, y, z)| is proven.
        Assumptions may be needed to prove such requirements.
        Requirements will be appended to the 'requirements' list if one
        is provided.

        There are limitations with respect the Lambda map application involving
        iterated parameters when perfoming operation substitution in order to
        keep derivation rules (i.e., instantiation) simple.  For details,
        see the ExprRange.substituted documentation.
        '''
        from proveit import Lambda, ExprRange

        if len(repl_map) > 0 and (self in repl_map):
            # The full expression is to be substituted.
            return repl_map[self]

        # Perform substitutions for the operator(s) and operand(s).
        subbed_operator = \
            self.operator.basic_replaced(
                    repl_map, allow_relabeling=allow_relabeling,
                    requirements=requirements)
        subbed_operands = \
            self.operands.basic_replaced(
                    repl_map, allow_relabeling=allow_relabeling,
                    requirements=requirements)

        # Check if the operator is being substituted by a Lambda map in
        # which case we should perform full operation substitution.
        if isinstance(subbed_operator, Lambda):
            # Substitute the entire operation via a Lambda map
            # application.  For example, f(x, y) -> x + y,
            # or g(a, b_1, ..., b_n) -> a * b_1 + ... + a * b_n.

            if isinstance(subbed_operator.body, ExprRange):
                raise ImproperReplacement(
                    self, repl_map,
                    "The function %s cannot be defined using this "
                    "lambda, %s, that has an ExprRange for its body; "
                    "that could lead to tuple length contradictions." %
                    (self.operator, subbed_operator))
            return Lambda._apply(subbed_operator.parameters,
                                 subbed_operator.body,
                                 *subbed_operands.entries,
                                 requirements=requirements)

        # If the operator is a literal operator of
        # an Operation class defined via an "_operator_" class
        # attribute, then create the Operation of that class.
        if subbed_operator in Operation.operation_class_of_operator:
            op_class = Operation.operation_class_of_operator[subbed_operator]
            if op_class != self.__class__:
                # Don't transfer the styles; they may not apply in
                # the same manner in the setting of the new
                # operation.
                subbed_sub_exprs = (subbed_operator, subbed_operands)
                return op_class._checked_make(
                    ['Operation'],
                    sub_expressions=subbed_sub_exprs,
                    style_preferences=self._style_data.styles)

        subbed_sub_exprs = (subbed_operator, subbed_operands)
        return self.__class__._checked_make(
            self._core_info,
            subbed_sub_exprs,
            style_preferences=self._style_data.styles)
Beispiel #4
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