def __init__(self, names, rightSides, beginningProof=False): self.beginningProof = beginningProof from proveit import singleOrCompositeExpression processedRightSides = [] for rightSide in rightSides: if not isinstance(rightSide, KnownTruth): try: # try to combine a composite expression if the right side is a # list or dictionary that should convert to an expression. rightSide = singleOrCompositeExpression(rightSide) except: pass if proveItMagic.kind in ('axioms', 'theorems', 'common'): if not isinstance(rightSide, Expression) and (rightSide is not None): raise ValueError( "Right hand side of end-of-cell assignment(s) is expected to be Expression(s)" ) processedRightSides.append(rightSide) self.names = list(names) self.rightSides = processedRightSides for name, rightSide in zip(names, self.rightSides): if name in proveItMagic.definitions: prev_def = proveItMagic.definitions[name] if rightSide != prev_def and isinstance(prev_def, Expression): proveItMagic.expr_names[prev_def].remove(name) if len(proveItMagic.expr_names[prev_def]) == 0: proveItMagic.expr_names.pop(prev_def) if rightSide is None: # unsetting a defintion proveItMagic.lowerCaseNames.remove(name.lower()) prev_def = proveItMagic.definitions[name] proveItMagic.definitions.pop(name) proveItMagic.keys.remove(name) continue if proveItMagic.kind == 'axioms' or proveItMagic.kind == 'theorems': if len(rightSide.freeVars()) > 0: raise ValueError( '%s should not have free variables; variables must all be bound (e.g. universally quantified). Free variables: %s' % (proveItMagic.kind, rightSide.freeVars())) if name in proveItMagic.definitions: if proveItMagic.definitions[name] != rightSide: print('WARNING: Redefining', name) proveItMagic.keys.remove(name) elif name.lower() in proveItMagic.lowerCaseNames: if not ( proveItMagic.ranFinish and name in proveItMagic.definitions ): # allowed to come back around after it finished once raise ProveItMagicFailure( "%s names must be unique regardless of capitalization" % proveItMagic.kind[:-1]) proveItMagic.lowerCaseNames.add(name.lower()) proveItMagic.definitions[name] = rightSide if isinstance(rightSide, Expression): proveItMagic.expr_names.setdefault(rightSide, []).append(name) proveItMagic.keys.append(name)
def __init__(self, operand): ''' Len takes a single operand which should properly be an ExprTuple or an expression (such as a variable) that represents a tuple. ''' operand = singleOrCompositeExpression(operand) if isinstance(operand, ExprTuple): # Nest an ExprTuple operand in an extra ExprTuple as # a clear indication that Len has a single operand # that is an ExprTuple rather than multiple operands. operand = ExprTuple(operand) # In order to always recognize that Len only takes a single # operand, we must wrap it as an ExprTuple with one entry. Operation.__init__(self, Len._operator_, operand)
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))
def __init__(self, names, rightSides, beginningProof=False): self.beginningProof = beginningProof from proveit import singleOrCompositeExpression processedRightSides = [] for rightSide in rightSides: if not isinstance(rightSide, KnownTruth): try: # try to combine a composite expression if the right side is a # list or dictionary that should convert to an expression. rightSide = singleOrCompositeExpression( rightSide, wrap_expr_range_in_tuple=False) except: pass if proveItMagic.kind in ('axioms', 'theorems', 'common'): if not isinstance(rightSide, Expression) and (rightSide is not None): # raise ValueError("Right hand side of end-of-cell " # "assignment(s) is expected to be " # "Expression(s).") raise ValueError("Right hand side of end-of-cell " "assignment(s) is {}, but is expected to " "be Expression(s).".format(rightSide)) processedRightSides.append(rightSide) self.names = list(names) self.rightSides = processedRightSides for name, rightSide in zip(names, self.rightSides): if name in proveItMagic.definitions: prev_def = proveItMagic.definitions[name] if rightSide != prev_def and isinstance(prev_def, Expression): proveItMagic.expr_names[prev_def].remove(name) if len(proveItMagic.expr_names[prev_def]) == 0: proveItMagic.expr_names.pop(prev_def) if rightSide is None: # unsetting a defintion proveItMagic.lowerCaseNames.remove(name.lower()) prev_def = proveItMagic.definitions[name] proveItMagic.definitions.pop(name) proveItMagic.keys.remove(name) continue if proveItMagic.kind == 'axioms' or proveItMagic.kind == 'theorems': # Axiom and theorem variables should all be bound # though we will only check for variables that are # entirely unbound because it would be challenging # to consider partially bound instances and it isn't # so critical -- it's just a good convention. if len(free_vars(rightSide, err_inclusively=False)) > 0: raise ValueError( '%s should not have free variables; variables ' 'must all be bound (e.g. universally quantified). ' ' Free variables: %s' %(proveItMagic.kind, free_vars(rightSide, err_inclusively=False))) if name in proveItMagic.definitions: if proveItMagic.definitions[name] != rightSide: print('WARNING: Redefining', name) proveItMagic.keys.remove(name) elif name.lower() in proveItMagic.lowerCaseNames: if not(proveItMagic.ranFinish and name in proveItMagic.definitions): # allowed to come back around after it finished once raise ProveItMagicFailure("%s names must be unique regardless of capitalization"%proveItMagic.kind[:-1]) proveItMagic.lowerCaseNames.add(name.lower()) proveItMagic.definitions[name] = rightSide if isinstance(rightSide, Expression): proveItMagic.expr_names.setdefault(rightSide, []).append(name) proveItMagic.keys.append(name)