示例#1
0
 def substituted(self, exprMap, relabelMap=None, reservedVars=None, assumptions=USE_DEFAULTS, requirements=None):
     '''
     Return this expression with its variables substituted 
     according to subMap and/or relabeled according to relabelMap.
     The Lambda parameters have their own scope within the Lambda 
     body and do not get substituted.  They may be relabeled, however. 
     Substitutions within the Lambda body are restricted to 
     exclude the Lambda parameters themselves (these Variables 
     are reserved), consistent with any relabeling.
     '''
     from proveit.logic import Forall
     
     self._checkRelabelMap(relabelMap)
     if len(exprMap)>0 and (self in exprMap):
         # the full expression is to be substituted
         return exprMap[self]._restrictionChecked(reservedVars)        
     if relabelMap is None: relabelMap = dict()
     assumptions = defaults.checkedAssumptions(assumptions)
     
     new_params, inner_expr_map, inner_assumptions, inner_reservations = self._innerScopeSub(exprMap, relabelMap, reservedVars, assumptions, requirements)
     
     # conditions with substitutions:
     condition_requirements = []
     condition_assumptions = inner_assumptions
     subbedConditions = self.conditions.substituted(inner_expr_map, relabelMap, inner_reservations, condition_assumptions, condition_requirements)
     # The lambda body with the substitutions.  Add the conditions, with substitutions, as assumptions
     # since they must be satisfied for the mapping to be well-defined.
     body_requirements = []
     body_assumptions = list(inner_assumptions)+list(subbedConditions)
     subbedBody = self.body.substituted(inner_expr_map, relabelMap, inner_reservations, body_assumptions, body_requirements)
     
     for requirements, requirements_assumptions in zip((condition_requirements, body_requirements), ([], subbedConditions)):
         for requirement in requirements:
             if requirement.freeVars().isdisjoint(new_params):
                 requirements.append(requirement)
             else:
                 # When the requirement involves any of the lambda parameters, we must universally quantify
                 # over those parameters, with appropriate conditions.  Appropriate conditions are the
                 # applicable assumptions that involve the lambda parameters.  This excludes the 'inner_assumptions'
                 # because they cannot involve lambda parameters (those were excluded).
                 requirement_params = requirement.freeVars().intersection(new_params)
                 requirement_conditions = [condition for condition in requirements_assumptions if not new_params.isdisjoint(condition.freeVars())]
                 requirement = Forall(requirement_params, requirement, conditions=requirement_conditions)
                 requirements.append(requirement)
                 raise ScopingViolation("Substitution requirements must not involve Lambda parameters")
     
     try:
         newLambda = Lambda(new_params, subbedBody, subbedConditions)
     except TypeError as e:
         raise ImproperSubstitution(e.args[0])
     except ValueError as e:
         raise ImproperSubstitution(e.args[0])            
     return newLambda
示例#2
0
 def _expandingIterRanges(self, iterParams, startArgs, endArgs, exprMap, relabelMap = None, reservedVars = None, assumptions=USE_DEFAULTS, requirements=None):
     from proveit import Variable, compositeExpression
     # Can't substitute the lambda parameter variables; they are in a new scope.
     innerExprMap = {key:value for (key, value) in exprMap.items() if key not in self.parameterVarSet}
     # Can't use assumptions involving lambda parameter variables
     innerAssumptions = [assumption for assumption in assumptions if self.parameterVarSet.isdisjoint(assumption.freeVars())]
     # Handle relabeling and variable reservations consistent with relabeling.
     innerReservations = dict() if reservedVars is None else dict(reservedVars)
     for parameterVar in self.parameterVars:
         # Note that lambda parameters introduce a new scope and don't need to,
         # themselves, be restriction checked.  But they generate new inner restrictions
         # that disallow any substitution from a variable that isn't in the new scope
         # to a variable that is in the new scope. 
         # For example, we can relabel y to z in (x, y) -> f(x, y), but not f to x. 
         if parameterVar in relabelMap:
             relabeledParams = compositeExpression(relabelMap[parameterVar])
             for relabeledParam in relabeledParams:
                 if not isinstance(relabeledParam, Variable):
                     raise ImproperSubstitution('May only relabel a Variable to another Variable or list of Variables')
                 innerReservations[relabeledParam] = parameterVar
         else:
             # Not relabeled
             innerReservations[parameterVar] = parameterVar
     
     # collect the iter ranges from the body and all conditions
     iter_ranges = set()
     for iter_range in self.body.expandingIterRanges(iterParams, startArgs, endArgs, innerExprMap, relabelMap, innerReservations, innerAssumptions, requirements):
         iter_ranges.add(iter_range)
     for iter_range in self.conditions.expandingIterRanges(iterParams, startArgs, endArgs, innerExprMap, relabelMap, innerReservations, innerAssumptions, requirements):
         iter_ranges.add(iter_range)
     for iter_range in iter_ranges:
         yield iter_range
示例#3
0
 def substituted(self, exprMap, relabelMap=None, reservedVars=None, assumptions=USE_DEFAULTS, requirements=None):
     '''
     Return this expression with the variables substituted 
     according to subMap and/or relabeled according to relabelMap.
     '''
     from proveit._core_.expression.composite.composite import compositeExpression
     from proveit._core_.expression.lambda_expr.lambda_expr import Lambda
     self._checkRelabelMap(relabelMap)
     if len(exprMap)>0 and (self in exprMap):
         return exprMap[self]._restrictionChecked(reservedVars)        
     subbed_operand_or_operands = self.operand_or_operands.substituted(exprMap, relabelMap, reservedVars, assumptions, requirements)
     subbed_operands = compositeExpression(subbed_operand_or_operands)
     subbed_operator_or_operators = self.operator_or_operators.substituted(exprMap, relabelMap, reservedVars, assumptions, requirements)
     subbed_operators = compositeExpression(subbed_operator_or_operators)
     if len(subbed_operators)==1:
         subbedOperator = subbed_operators[0]
         if isinstance(subbedOperator, Lambda):
             # Substitute the entire operation via a Lambda body
             # For example, f(x, y) -> x + y.
             if len(subbed_operands) != len(subbedOperator.parameters):
                 raise ImproperSubstitution('Cannot substitute an Operation with the wrong number of parameters')
             if len(subbedOperator.conditions) != 0:
                 raise ImproperSubstitution('Operation substitution must be defined via an Unconditioned Lambda expression')
             operandSubMap = {param:operand for param, operand in zip(subbedOperator.parameters, subbed_operands)}
             if not reservedVars is None:
                 # the reserved variables of the lambda body excludes the lambda parameters
                 # (i.e., the parameters mask externally reserved variables).
                 lambdaExprReservedVars = {k:v for k, v in reservedVars.items() if k not in subbedOperator.parameterVarSet}
             else: lambdaExprReservedVars = None
             return subbedOperator.body._restrictionChecked(lambdaExprReservedVars).substituted(operandSubMap, assumptions=assumptions, requirements=requirements)
     # 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.
                 return op_class._make(['Operation'], styles=None, 
                                       subExpressions=[operator, 
                                                       subbed_operand_or_operands])
     return self.__class__._make(['Operation'], self.getStyles(), 
                                 [subbed_operator_or_operators, 
                                  subbed_operand_or_operands])
示例#4
0
    def _innerScopeSub(self, exprMap, relabelMap, reservedVars, assumptions, requirements):
        '''
        Helper method for substituted (and used by Iter.substituted) which handles the change in
        scope properly as well as parameter relabeling (or iterated parameter expansion).
        '''
        
        from proveit import compositeExpression, Iter, ExprList
        
        # Can't substitute the lambda parameter variables; they are in a new scope.
        inner_expr_map = {key:value for (key, value) in exprMap.items() if key not in self.parameterVarSet}
        # Handle relabeling and variable reservations consistent with relabeling.
        inner_reservations = dict() if reservedVars is None else dict(reservedVars)
        new_params = []
        
        for parameter, parameterVar in zip(self.parameters, self.parameterVars):
            # Note that lambda parameters introduce a new scope and don't need to,
            # themselves, be restriction checked.  But they generate new inner restrictions
            # that disallow any substitution from a variable that isn't in the new scope
            # to a variable that is in the new scope. 
            # For example, we can relabel y to z in (x, y) -> f(x, y), but not f to x. 
            if parameterVar in relabelMap:
                if isinstance(parameter, Iter):
                    relabeledParams = parameter.substituted(exprMap, relabelMap, reservedVars, assumptions, requirements)
                    if isinstance(relabeledParams, ExprList):
                        # expanding an iteration.  For example: x_1, ..., x_n -> a, b, c, d 
                        if len(relabeledParams) != len(relabelMap[parameterVar]):
                            raise ImproperSubstitution("Relabeling of iterated parameters incomplete: %d length expansion versus %d length substitution"%(len(relabeledParams), len(relabelMap[parameterVar])))
                    else:
                        # e.g., x_1, ..., x_n -> y_1, ..., y_n
                        relabeledParams = compositeExpression(relabeledParams)
                else:
                    relabeledParams = compositeExpression(relabelMap[parameterVar])
                for relabeledParam in relabeledParams:
                    new_params.append(relabeledParam)
                    inner_reservations[relabeledParam] = parameterVar
            else:
                # can perform a substition in indices of a parameter iteration: x_1, ..., x_n
                new_params.append(parameter.substituted(inner_expr_map, relabelMap, reservedVars, assumptions, requirements))
                inner_reservations[parameterVar] = parameterVar

        # Can't use assumptions involving lambda parameter variables
        inner_assumptions = [assumption for assumption in assumptions if assumption.freeVars().isdisjoint(new_params)]
                                      
        return new_params, inner_expr_map, inner_assumptions, inner_reservations
示例#5
0
    def substituted(self,
                    exprMap,
                    relabelMap=None,
                    reservedVars=None,
                    assumptions=USE_DEFAULTS,
                    requirements=None):
        '''
        Return this expression with its variables substituted 
        according to subMap and/or relabeled according to relabelMap.
        The Lambda parameters have their own scope within the Lambda 
        body and do not get substituted.  They may be relabeled, however. 
        Substitutions within the Lambda body are restricted to 
        exclude the Lambda parameters themselves (these Variables 
        are reserved), consistent with any relabeling.
        '''
        from proveit import compositeExpression, Iter
        if (exprMap is not None) and (self in exprMap):
            # the full expression is to be substituted
            return exprMap[self]._restrictionChecked(reservedVars)
        if relabelMap is None: relabelMap = dict()
        assumptions = defaults.checkedAssumptions(assumptions)
        # Can't substitute the lambda parameter variables; they are in a new scope.
        innerExprMap = {
            key: value
            for (key, value) in exprMap.iteritems()
            if key not in self.parameterVarSet
        }
        # Can't use assumptions involving lambda parameter variables
        innerAssumptions = [
            assumption for assumption in assumptions
            if self.parameterVarSet.isdisjoint(assumption.freeVars())
        ]
        # Handle relabeling and variable reservations consistent with relabeling.
        innerReservations = dict() if reservedVars is None else dict(
            reservedVars)
        newParams = []

        for parameter, parameterVar in zip(self.parameters,
                                           self.parameterVars):
            # Note that lambda parameters introduce a new scope and don't need to,
            # themselves, be restriction checked.  But they generate new inner restrictions
            # that disallow any substitution from a variable that isn't in the new scope
            # to a variable that is in the new scope.
            # For example, we can relabel y to z in (x, y) -> f(x, y), but not f to x.
            if parameterVar in relabelMap:
                if isinstance(parameter, Iter):
                    # expanding an iteration.  For example: x_1, ..., x_n -> a, b, c, d
                    relabeledParams = parameter.substituted(
                        exprMap, relabelMap, reservedVars, assumptions,
                        requirements)
                    if len(relabeledParams) != len(relabelMap[parameterVar]):
                        raise ImproperSubstitution(
                            "Relabeling of iterated parameters incomplete: %d length expansion versus %d length substitution"
                            % (len(relabeledParams),
                               len(relabelMap[parameterVar])))
                else:
                    relabeledParams = compositeExpression(
                        relabelMap[parameterVar])
                for relabeledParam in relabeledParams:
                    newParams.append(relabeledParam)
                    innerReservations[relabeledParam] = parameterVar
            else:
                # can perform a substition in indices of a parameter iteration: x_1, ..., x_n
                newParams.append(
                    parameter.substituted(innerExprMap, relabelMap,
                                          reservedVars, assumptions,
                                          requirements))
                innerReservations[parameterVar] = parameterVar
        # the lambda body with the substitution:
        subbedBody = self.body.substituted(innerExprMap, relabelMap,
                                           innerReservations, innerAssumptions,
                                           requirements)
        # conditions with substitutions:
        subbedConditions = self.conditions.substituted(innerExprMap,
                                                       relabelMap,
                                                       innerReservations,
                                                       innerAssumptions,
                                                       requirements)
        try:
            newLambda = Lambda(newParams, subbedBody, subbedConditions)
        except TypeError as e:
            raise ImproperSubstitution(e.message)
        except ValueError as e:
            raise ImproperSubstitution(e.message)
        return newLambda