def relabel(self, relabelMap): ''' Performs a relabeling derivation step, deriving another KnownTruth from this KnownTruth, under the same assumptions, with relabeled Variables. A Variable may only be relabeled to a Variable. Returns the proven relabeled KnownTruth, or throws an exception if the proof fails. ''' from proveit._core_.proof import Specialization return self._checkedTruth(Specialization(self, numForallEliminations=0, relabelMap=relabelMap, assumptions=self.assumptions))
def specialize(self, specializeMap=None, relabelMap=None, assumptions=USE_DEFAULTS): ''' Performs a specialize derivation step to be proven under the given assumptions, in addition to the assumptions of the KnownTruth. This will eliminate one or more nested Forall operations, specializing the instance variables according to specializeMap. Eliminates the number of Forall operations required to utilize all of the specializeMap keys. The default mapping of all instance variables is a mapping to itself (e.g., {x:x, y:y}). Simultaneously, variables may be relabeled via relabelMap (see the relabel method). Note, there is a difference between making substitutons simultaneously versus in-series. For example, the {x:y, y:x} mapping will swap x and y variables, but mapping {x:y} then {y:x} in series would set both variables to x. Returns the proven specialized KnownTruth, or throws an exception if the proof fails. ''' from proveit import Operation, Variable, Lambda, singleOrCompositeExpression from proveit.logic import Forall from .proof import Specialization, SpecializationFailure, ProofFailure if not self.isUsable(): # If this KnownTruth is not usable, see if there is an alternate under the # set of assumptions that is usable. try: alternate = self.expr.prove(assumptions, automation=False) except ProofFailure: self.raiseUnusableProof() return alternate.specialize(specializeMap, relabelMap, assumptions) # if no specializeMap is provided, specialize the "explicitInstanceVars" of the Forall with default mappings # (mapping instance variables to themselves) if specializeMap is None: specializeMap = { ivar: ivar for ivar in self.explicitInstanceVars() } if relabelMap is None: relabelMap = dict() # Include the KnownTruth assumptions along with any provided assumptions assumptions = defaults.checkedAssumptions(assumptions) assumptions += self.assumptions # For any entrys in the subMap with Operation keys, convert # them to corresponding operator keys with Lambda substitutions. # For example f(x,y):g(x,y) would become f:[(x,y) -> g(x,y)]. # Convert to composite expressions as needed (via singleOrCompositeExpression). processedSubMap = dict() for key, sub in specializeMap.items(): sub = singleOrCompositeExpression(sub) if isinstance(key, Operation): operation = key subVar = operation.operator sub = Lambda(operation.operands, sub) processedSubMap[subVar] = sub elif isinstance(key, Variable): processedSubMap[key] = sub else: raise SpecializationFailure( self, specializeMap, relabelMap, assumptions, 'Expecting specializeMap keys to be Variables, MultiVariables, or Operations with Variable/MultiVariable operators; not %s' % str(key.__class__)) remainingSubVars = set(processedSubMap.keys()) # Determine the number of Forall eliminations. There must be at least # one (if zero is desired, relabel should be called instead). # The number is determined by the instance variables that occur as keys # in the subMap. expr = self.expr numForallEliminations = 0 while numForallEliminations == 0 or len(remainingSubVars) > 0: numForallEliminations += 1 if not isinstance(expr, Forall): raise SpecializationFailure( self, specializeMap, relabelMap, assumptions, 'May only specialize instance variables of directly nested Forall operations' ) lambdaExpr = expr.operand assert isinstance( lambdaExpr, Lambda), "Forall Operation operand must be a Lambda function" instanceVars, expr, conditions = lambdaExpr.parameterVars, lambdaExpr.body, lambdaExpr.conditions for iVar in instanceVars: if iVar in remainingSubVars: # remove this instance variable from the remaining substitution variables remainingSubVars.remove(iVar) elif iVar not in processedSubMap: # default is to map instance variables to themselves processedSubMap[iVar] = iVar return self._checkedTruth( Specialization(self, numForallEliminations=numForallEliminations, specializeMap=processedSubMap, relabelMap=relabelMap, assumptions=assumptions))