def extractMyInitArgValue(self, argName):
     '''
     Return the most proper initialization value for the initialization argument
     of the given name in order to reconstruct this Expression in its
     current style.
     '''
     init_argname_mapping = self.__class__._init_argname_mapping_
     argName = init_argname_mapping.get(argName, argName)
     if argName=='operator':
         return self.operator # simply the operator
     elif argName=='instanceVarOrVars':
         # return the joined instance variables according to style.
         return singleOrCompositeExpression(OperationOverInstances.explicitInstanceVars(self))
     elif argName=='instanceExpr':
         # return the inner instance expression after joining the
         # instance variables according to the style
         return OperationOverInstances.explicitInstanceExpr(self)
     elif argName=='domain' or argName=='domains':
         # return the proper single domain or list of domains
         if self.domain is None: return None
         domains = OperationOverInstances.explicitDomains(self)
         if domains == [self.domain]*len(domains):
             return self.domain if argName=='domain' else None
         elif not None in domains:
             return ExprList(*domains) if argName=='domains' else None
         return None
     elif argName=='conditions':
         # return the joined conditions excluding domain conditions
         return singleOrCompositeExpression(OperationOverInstances.explicitConditions(self))
Example #2
0
    def __init__(self,
                 lambda_map,
                 start_index_or_indices,
                 end_index_or_indices,
                 styles=dict(),
                 requirements=tuple()):
        if not isinstance(lambda_map, Lambda):
            raise TypeError(
                'When creating an Iter Expression, the lambda_map argument must be a Lambda expression'
            )

        if isinstance(start_index_or_indices,
                      ExprList) and len(start_index_or_indices) == 1:
            start_index_or_indices = start_index_or_indices[0]
        self.start_index_or_indices = singleOrCompositeExpression(
            start_index_or_indices)
        if isinstance(self.start_index_or_indices, Composite):
            # a composite of multiple indices
            self.start_indices = self.start_index_or_indices
        else:
            # a single index
            self.start_index = self.start_index_or_indices
            # wrap a single index in a composite for convenience
            self.start_indices = compositeExpression(
                self.start_index_or_indices)

        if isinstance(end_index_or_indices,
                      ExprList) and len(end_index_or_indices) == 1:
            end_index_or_indices = end_index_or_indices[0]
        self.end_index_or_indices = singleOrCompositeExpression(
            end_index_or_indices)
        if isinstance(self.end_index_or_indices, Composite):
            # a composite of multiple indices
            self.end_indices = self.end_index_or_indices
        else:
            # a single index
            self.end_index = self.end_index_or_indices
            # wrap a single index in a composite for convenience
            self.end_indices = compositeExpression(self.end_index_or_indices)

        self.ndims = len(self.start_indices)
        if self.ndims != len(self.end_indices):
            raise ValueError(
                "Inconsistent number of 'start' and 'end' indices")

        if len(lambda_map.parameters) != len(self.start_indices):
            raise ValueError(
                "Inconsistent number of indices and lambda map parameters")

        Expression.__init__(self, ['Iter'], [
            lambda_map, self.start_index_or_indices, self.end_index_or_indices
        ],
                            styles=styles,
                            requirements=requirements)
        self.lambda_map = lambda_map
Example #3
0
 def __init__(self, operator_or_operators, operand_or_operands, styles=dict(), requirements=tuple()):
     '''
     Create an operation with the given operator(s) and operand(s).
     The operator(s) must be Label(s) (a Variable or a Literal).
     When there is a single operator, there will be an 'operator'
     attribute.  When there is a single operand, there will be
     an 'operand' attribute.  In any case, there will be
     'operators' and 'operands' attributes that bundle
     the one or more Expressions into a composite Expression.
     '''
     from proveit._core_.expression.composite import Composite, compositeExpression, singleOrCompositeExpression, Iter, Indexed
     from proveit._core_.expression.label.label import Label
     from proveit import Context
     if hasattr(self.__class__, '_operator_') and operator_or_operators==self.__class__._operator_:
         operator = operator_or_operators
         context = Context(inspect.getfile(self.__class__))
         if Expression.contexts[operator] != context:
             raise OperationError("Expecting '_operator_' Context to match the Context of the Operation sub-class.  Use 'context=__file__'.")
     self.operator_or_operators = singleOrCompositeExpression(operator_or_operators)
     self.operand_or_operands = singleOrCompositeExpression(operand_or_operands)
     if isinstance(self.operator_or_operators, Composite):
         # a composite of multiple operators:
         self.operators = self.operator_or_operators 
         for operator in self.operators:
             if isinstance(operator, Iter):
                 if not isinstance(operator.lambda_map.body, Indexed):
                     raise TypeError('operators must be Labels, Indexed variables, or iteration (Iter) over Indexed variables.')                
             elif not isinstance(operator, Label) and not isinstance(operator, Indexed):
                 raise TypeError('operator must be a Label, Indexed variable, or iteration (Iter) over Indexed variables.')
     else:
         # a single operator
         self.operator = self.operator_or_operators
         if not isinstance(self.operator, Label) and not isinstance(self.operator, Indexed):
             raise TypeError('operator must be a Label, Indexed variable, or iteration (Iter) over Indexed variables.')
         # wrap a single operator in a composite for convenience
         self.operators = compositeExpression(self.operator)
     if isinstance(self.operand_or_operands, Composite):
         # a composite of multiple operands
         self.operands = self.operand_or_operands
     else:
         # a single operand
         self.operand = self.operand_or_operands
         # wrap a single operand in a composite for convenience
         self.operands = compositeExpression(self.operand)
     if 'operation' not in styles:
         styles['operation'] = 'normal' # vs 'function
     if 'wrapPositions' not in styles:
         styles['wrapPositions'] = '()' # no wrapping by default
     if 'justification' not in styles:
         styles['justification'] = 'center'
     Expression.__init__(self, ['Operation'], [self.operator_or_operators, self.operand_or_operands], styles=styles, requirements=requirements)
Example #4
0
 def extractInitArgValue(argName, operator, operand):
     '''
     Given a name of one of the arguments of the __init__ method,
     return the corresponding value as determined by the
     given operator and operand for an OperationOverInstances
     Expression.
     
     Override this if the __init__ argument names are different than the
     default.
     '''
     assert isinstance(
         operand, Lambda
     ), "Expecting OperationOverInstances operand to be a Lambda expression"
     if argName == 'operator':
         return operator
     if argName == 'domain' or argName == 'domains':
         return None  # specify domains implicitly through conditions
     if argName == 'instanceVarOrVars':
         return singleOrCompositeExpression(operand.parameters)
     elif argName == 'instanceExpr':
         return operand.body
     elif argName == 'conditions':
         conditions = operand.conditions
         #if len(conditions)==0: return tuple()
         return conditions
Example #5
0
 def __init__(self, parameter_or_parameters, body, conditions=tuple(), styles=None, requirements=tuple()):
     '''
     Initialize a Lambda function expression given parameter(s) and a body.
     Each parameter must be a Variable.
     When there is a single parameter, there will be a 'parameter'
     attribute. Either way, there will be a 'parameters' attribute
     that bundles the one or more Variables into an ExprList.
     The 'body' attribute will be the lambda function body
     Expression (that may or may not be a Composite).  Zero or
     more expressions may be provided.
     '''
     from proveit._core_.expression.composite import compositeExpression, singleOrCompositeExpression, Iter
     if styles is None: styles = dict()
     self.parameters = compositeExpression(parameter_or_parameters)
     parameterVars = [getParamVar(parameter) for parameter in self.parameters]
     if len(self.parameters) == 1:
         # has a single parameter
         self.parameter = self.parameters[0]
         self.parameter_or_parameters = self.parameter
     else:
         self.parameter_or_parameters = self.parameters
     self.parameterVars = tuple(parameterVars)
     self.parameterVarSet = frozenset(parameterVars)
     if len(self.parameterVarSet) != len(self.parameters):
         raise ValueError('Lambda parameters Variables must be unique with respect to each other.')
     body = singleOrCompositeExpression(body)
     if not isinstance(body, Expression):
         raise TypeError('A Lambda body must be of type Expression')
     if isinstance(body, Iter):
         raise TypeError('An Iter must be within an ExprList or ExprTensor, not directly as a Lambda body')
     self.body = body
     self.conditions = compositeExpression(conditions)
     for requirement in self.body.getRequirements():
         if not self.parameterVarSet.isdisjoint(requirement.freeVars()):
             raise LambdaError("Cannot generate a Lambda expression with parameter variables involved in Lambda body requirements: " + str(requirement))
     sub_exprs = [self.parameter_or_parameters, self.body]
     if len(self.conditions)>0: sub_exprs.append(self.conditions)
     
     # Create a "generic" version (if not already) of the Lambda expression since the 
     # choice of parameter labeling is irrelevant.
     generic_body_vars = self.body._genericExpr.usedVars()
     generic_condition_vars = self.conditions._genericExpr.usedVars()
     used_generic_vars = generic_body_vars.union(generic_condition_vars)
     generic_params = tuple(safeDummyVars(len(self.parameterVars), *(used_generic_vars-self.parameterVarSet)))
     if generic_params != self.parameterVars:
         relabel_map = {param:generic_param for param, generic_param in zip(self.parameterVars, generic_params)}
         # temporarily disable automation during the relabeling process
         prev_automation = defaults.automation
         defaults.automation = False
         generic_parameters = self.parameters._genericExpr.relabeled(relabel_map)
         generic_body = self.body._genericExpr.relabeled(relabel_map)
         generic_conditions = self.conditions._genericExpr.relabeled(relabel_map)
         self._genericExpr = Lambda(generic_parameters, generic_body, generic_conditions, styles=dict(styles), requirements=requirements)
         defaults.automation = prev_automation # restore to previous value
     
     Expression.__init__(self, ['Lambda'], sub_exprs, styles=styles, requirements=requirements)
Example #6
0
    def _replaced(self, repl_map, allow_relabeling, assumptions, requirements,
                  equality_repl_requirements):
        '''
        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, singleOrCompositeExpression,
                             compositeExpression, ExprTuple, 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_or_operators = \
            self.operator_or_operators.replaced(repl_map, allow_relabeling,
                                                assumptions, requirements,
                                                equality_repl_requirements)
        subbed_operand_or_operands = \
            self.operand_or_operands.replaced(repl_map, allow_relabeling,
                                              assumptions, requirements,
                                              equality_repl_requirements)
        subbed_operators = compositeExpression(subbed_operator_or_operators)

        # Check if the operator is being substituted by a Lambda map in
        # which case we should perform full operation substitution.
        if len(subbed_operators) == 1:
            subbed_operator = subbed_operators[0]
            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))
                if len(self.operands)==1 and \
                        not isinstance(self.operands[0], ExprRange):
                    # A single operand case (even if that operand
                    # happens to be a tuple).
                    subbed_operands = [subbed_operand_or_operands]
                else:
                    subbed_operands = subbed_operand_or_operands
                return Lambda._apply(
                    subbed_operator.parameters,
                    subbed_operator.body,
                    *subbed_operands,
                    assumptions=assumptions,
                    requirements=requirements,
                    equality_repl_requirements=equality_repl_requirements)

        had_singular_operand = hasattr(self, 'operand')
        if (had_singular_operand
                and isinstance(subbed_operand_or_operands, ExprTuple)
                and not isinstance(self.operand_or_operands, ExprTuple)):
            # If a singular operand is replaced with an ExprTuple,
            # we must wrap an extra ExprTuple around it to indicate
            # that it is still a singular operand with the operand
            # as the ExprTuple (rather than expanding to multiple
            # operands).
            subbed_operand_or_operands = ExprTuple(subbed_operand_or_operands)
        else:
            # Possibly collapse multiple operands to a single operand
            # via "do_singular_reduction=True".
            subbed_operand_or_operands = singleOrCompositeExpression(
                subbed_operand_or_operands, do_singular_reduction=True)

        # Remake the Expression with substituted operator and/or
        # operands
        if len(subbed_operators) == 1:
            # If it is a single operator that is a literal operator of
            # an Operation class defined via an "_operator_" class
            # attribute, then create the Operation of that class.
            operator = subbed_operators[0]
            if operator in Operation.operationClassOfOperator:
                op_class = Operation.operationClassOfOperator[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 = (operator, subbed_operand_or_operands)
                    substituted = op_class._checked_make(
                        ['Operation'],
                        styles=None,
                        subExpressions=subbed_sub_exprs)
                    return substituted._auto_reduced(
                        assumptions, requirements, equality_repl_requirements)

        subbed_sub_exprs = (subbed_operator_or_operators,
                            subbed_operand_or_operands)
        substituted = self.__class__._checked_make(self._coreInfo,
                                                   self.getStyles(),
                                                   subbed_sub_exprs)
        return substituted._auto_reduced(assumptions, requirements,
                                         equality_repl_requirements)
Example #7
0
    def __init__(self,
                 operator_or_operators,
                 operand_or_operands,
                 styles=None):
        '''
        Create an operation with the given operator(s) and operand(s).
        The operator(s) must be Label(s) (a Variable or a Literal).
        When there is a single operator, there will be an 'operator'
        attribute.  When there is a single operand, there will be
        an 'operand' attribute.  In any case, there will be
        'operators' and 'operands' attributes that bundle
        the one or more Expressions into a composite Expression.
        '''
        from proveit._core_.expression.composite import (
            Composite, compositeExpression, singleOrCompositeExpression,
            ExprTuple, ExprRange)
        from proveit._core_.expression.label.label import Label
        from .indexed_var import IndexedVar
        if styles is None: styles = dict()
        if hasattr(self.__class__, '_operator_'
                   ) and operator_or_operators == self.__class__._operator_:
            operator = operator_or_operators
            #if Expression.contexts[operator._style_id] != operator.context:
            #    raise OperationError("Expecting '_operator_' Context to match the Context of the Operation sub-class.  Use 'context=__file__'.")
        if isinstance(operator_or_operators, ExprRange):
            operator_or_operators = [operator_or_operators]
        if isinstance(operand_or_operands, ExprRange):
            operand_or_operands = [operand_or_operands]
        self.operator_or_operators = singleOrCompositeExpression(
            operator_or_operators)

        # Reduce to a single operand if it is just a tuple with
        # one non-ExprRange and non-ExprTuple element.
        self.operand_or_operands = singleOrCompositeExpression(
            operand_or_operands, do_singular_reduction=True)

        def raiseBadOperatorType(operator):
            raise TypeError('operator(s) must be a Label, an indexed variable '
                            '(IndexedVar), or iteration (Iter) over indexed'
                            'variables (IndexedVar). %s is none of those.' %
                            str(operator))

        if isinstance(self.operator_or_operators, Composite):
            # a composite of multiple operators:
            self.operators = self.operator_or_operators
            for operator in self.operators:
                if isinstance(operator, ExprRange):
                    if not isinstance(operator.body, IndexedVar):
                        raiseBadOperatorType(operator)
                elif not isinstance(operator, Label) and not isinstance(
                        operator, IndexedVar):
                    raiseBadOperatorType(operator)
        else:
            # a single operator
            self.operator = self.operator_or_operators
            if not isinstance(self.operator, Label) and not isinstance(
                    self.operator, IndexedVar):
                raiseBadOperatorType(self.operator)
            # wrap a single operator in a composite for convenience
            self.operators = compositeExpression(self.operator)
        if isinstance(self.operand_or_operands, Composite):
            # a composite of multiple operands
            self.operands = self.operand_or_operands
            if (isinstance(self.operands, ExprTuple)
                    and len(self.operands) == 1
                    and isinstance(self.operands[0], ExprTuple)):
                # This is a single operand that is an ExprTuple.
                self.operand = self.operands[0]
        else:
            # a single operand
            self.operand = self.operand_or_operands
            # wrap a single operand in a composite for convenience
            self.operands = compositeExpression(self.operand)
        if 'operation' not in styles:
            styles['operation'] = 'infix'  # vs 'function'
        if 'wrapPositions' not in styles:
            styles['wrapPositions'] = '()'  # no wrapping by default
        if 'justification' not in styles:
            styles['justification'] = 'center'
        sub_exprs = (self.operator_or_operators, self.operand_or_operands)
        if isinstance(self, IndexedVar):
            core_type = 'IndexedVar'
        else:
            core_type = 'Operation'
        Expression.__init__(self, [core_type], sub_exprs, styles=styles)
Example #8
0
    def __init__(self,
                 parameter_or_parameters,
                 body,
                 start_index_or_indices,
                 end_index_or_indices,
                 styles=None,
                 requirements=tuple(),
                 _lambda_map=None):
        '''
        Create an Iter that represents an iteration of the body for the
        parameter(s) ranging from the start index/indices to the end 
        index/indices.  A Lambda expression will be created as its 
        sub-expression that maps the parameter(s) to the body with
        conditions that restrict the parameter(s) to the appropriate interval.
        
        _lambda_map is used internally for efficiently rebuilding an Iter.
        '''
        from proveit.logic import InSet
        from proveit.number import Interval

        if _lambda_map is not None:
            # Use the provided 'lambda_map' instead of creating one.
            lambda_map = _lambda_map
            pos_args = (parameter_or_parameters, body, start_index_or_indices,
                        end_index_or_indices)
            if pos_args != (None, None, None, None):
                raise ValueError(
                    "Positional arguments of the Init constructor "
                    "should be None if lambda_map is provided.")
            parameters = lambda_map.parameters
            body = lambda_map.body
            conditions = lambda_map.conditions
            if len(conditions) != len(parameters):
                raise ValueError(
                    "Inconsistent number of conditions and lambda "
                    "map parameters")
            start_indices, end_indices = [], []
            for param, condition in zip(parameters, conditions):
                invalid_condition_msg = (
                    "Not the right kind of lambda_map condition "
                    "for an iteration")
                if not isinstance(condition,
                                  InSet) or condition.element != param:
                    raise ValueError(invalid_condition_msg)
                domain = condition.domain
                if not isinstance(domain, Interval):
                    raise ValueError(invalid_condition_msg)
                start_index, end_index = domain.lowerBound, domain.upperBound
                start_indices.append(start_index)
                end_indices.append(end_index)
            self.start_indices = ExprTuple(*start_indices)
            self.end_indices = ExprTuple(*end_indices)
            if len(parameters) == 1:
                self.start_index = self.start_indices[0]
                self.end_index = self.end_indices[0]
                self.start_index_or_indices = self.start_index
                self.end_index_or_indices = self.end_index
            else:
                self.start_index_or_indices = self.start_indices
                self.end_index_or_indices = self.end_indices
        else:
            parameters = compositeExpression(parameter_or_parameters)

            start_index_or_indices = singleOrCompositeExpression(
                start_index_or_indices)
            if isinstance(start_index_or_indices,
                          ExprTuple) and len(start_index_or_indices) == 1:
                start_index_or_indices = start_index_or_indices[0]
            self.start_index_or_indices = start_index_or_indices
            if isinstance(start_index_or_indices, Composite):
                # a composite of multiple indices
                self.start_indices = self.start_index_or_indices
            else:
                # a single index
                self.start_index = self.start_index_or_indices
                # wrap a single index in a composite for convenience
                self.start_indices = compositeExpression(
                    self.start_index_or_indices)

            end_index_or_indices = singleOrCompositeExpression(
                end_index_or_indices)
            if isinstance(end_index_or_indices,
                          ExprTuple) and len(end_index_or_indices) == 1:
                end_index_or_indices = end_index_or_indices[0]
            self.end_index_or_indices = end_index_or_indices
            if isinstance(self.end_index_or_indices, Composite):
                # a composite of multiple indices
                self.end_indices = self.end_index_or_indices
            else:
                # a single index
                self.end_index = self.end_index_or_indices
                # wrap a single index in a composite for convenience
                self.end_indices = compositeExpression(
                    self.end_index_or_indices)

            conditions = []
            for param, start_index, end_index in zip(parameters,
                                                     self.start_indices,
                                                     self.end_indices):
                conditions.append(
                    InSet(param, Interval(start_index, end_index)))

            lambda_map = Lambda(parameters, body, conditions=conditions)

        self.ndims = len(self.start_indices)
        if self.ndims != len(self.end_indices):
            raise ValueError(
                "Inconsistent number of 'start' and 'end' indices")

        if len(parameters) != len(self.start_indices):
            raise ValueError(
                "Inconsistent number of indices and lambda map parameters")

        Expression.__init__(self, ['Iter'], [lambda_map],
                            styles=styles,
                            requirements=requirements)
        self.lambda_map = lambda_map
        self._checkIndexedRestriction(body)
Example #9
0
 def __init__(self,
              parameter_or_parameters,
              body,
              conditions=tuple(),
              styles=dict(),
              requirements=tuple()):
     '''
     Initialize a Lambda function expression given parameter(s) and a body.
     Each parameter must be a Variable.
     When there is a single parameter, there will be a 'parameter'
     attribute. Either way, there will be a 'parameters' attribute
     that bundles the one or more Variables into an ExprList.
     The 'body' attribute will be the lambda function body
     Expression (that may or may not be a Composite).  Zero or
     more expressions may be provided.
     '''
     from proveit._core_.expression.composite import compositeExpression, singleOrCompositeExpression, Iter, Indexed
     from proveit._core_.expression.label import Variable
     self.parameters = compositeExpression(parameter_or_parameters)
     parameterVars = list()
     for parameter in self.parameters:
         if isinstance(parameter, Iter) and isinstance(
                 parameter.lambda_map.body, Indexed):
             parameterVars.append(parameter.lambda_map.body.var)
         elif isinstance(parameter, Indexed):
             parameterVars.append(parameter.var)
         elif isinstance(parameter, Variable):
             parameterVars.append(parameter)
         else:
             raise TypeError(
                 'parameters must be a Variables, Indexed variable, or iteration (Iter) over Indexed variables.'
             )
     if len(self.parameters) == 1:
         # has a single parameter
         self.parameter = self.parameters[0]
         self.parameter_or_parameters = self.parameter
     else:
         self.parameter_or_parameters = self.parameters
     self.parameterVars = tuple(parameterVars)
     self.parameterVarSet = frozenset(parameterVars)
     if len(self.parameterVarSet) != len(self.parameters):
         raise ValueError(
             'Lambda parameters Variables must be unique with respect to each other.'
         )
     body = singleOrCompositeExpression(body)
     if not isinstance(body, Expression):
         raise TypeError('A Lambda body must be of type Expression')
     if isinstance(body, Iter):
         raise TypeError(
             'An Iter must be within an ExprList or ExprTensor, not directly as a Lambda body'
         )
     self.body = body
     self.conditions = compositeExpression(conditions)
     for requirement in self.body.requirements:
         if not self.parameterVarSet.isdisjoint(requirement.freeVars()):
             raise LambdaError(
                 "Cannot generate a Lambda expression with parameter variables involved in Lambda body requirements: "
                 + str(requirement))
     Expression.__init__(
         self, ['Lambda'],
         [self.parameter_or_parameters, self.body, self.conditions],
         styles=styles,
         requirements=requirements)