def generalize(self, forallVars, domain=None, conditions=tuple()): r''' This makes a generalization of this expression, prepending Forall operations according to newForallVars and newConditions and/or newDomain that will bind 'arbitrary' free variables. This overrides the expr version to absorb antecedent into conditions if they match. For example, :math:`[A(x) \Rightarrow [B(x, y) \Rightarrow P(x, y)]]` generalized forall :math:`x, y` such that :math:`A(x), B(x, y)` becomes :math:`\forall_{x, y | A(x), B(x, y)} P(x, y)`, ''' from proveit.logic import InSet hypothesizedConditions = set() conditionsSet = set(compositeExpression(conditions)) if domain is not None: # add in the effective conditions from the domain for var in compositeExpression(forallVars): conditionsSet.add(InSet(var, domain)) expr = self while isinstance(expr, Implies) and expr.antecedent in conditionsSet: hypothesizedConditions.add(expr.antecedent) expr = expr.consequent if len(hypothesizedConditions) == 0: # Just use the expr version return expr.generalize(self, forallVars, domain, conditions) return expr.generalize(expr, forallVars, domain, conditions)
def generalize(self, forallVarLists, domainLists=None, domain=None, conditions=tuple()): ''' Performs a generalization derivation step. Returns the proven generalized KnownTruth. Can introduce any number of nested Forall operations to wrap the original statement, corresponding to the number of given forallVarLists and domains. A single variable list or single variable and a single domain may be provided to introduce a single Forall wrapper. ''' from proveit._core_.proof import Generalization from proveit import Variable, compositeExpression from proveit.logic import InSet if isinstance(forallVarLists, Variable): forallVarLists = [[ forallVarLists ]] # a single Variable to convert into a list of variable lists else: if not hasattr(forallVarLists, '__len__'): raise ValueError( "Must supply 'generalize' with a Variable, list of Variables, or list of Variable lists." ) if len(forallVarLists) == 0: raise ValueError( "Must provide at least one Variable to generalize over") if all(isinstance(x, Variable) for x in forallVarLists): # convert a list of Variable/MultiVariables to a list of lists forallVarLists = [forallVarLists] # Add domain conditions as appropriate if domain is not None and domainLists is not None: raise ValueError( "Either specify a 'domain' or a list of 'domainLists' but not both" ) if domain is not None: domainLists = [[domain] * len(forallVarList) for forallVarList in forallVarLists] if domainLists is not None: domainConditions = [] for domainList, forallVarList in zip(domainLists, forallVarLists): domainList = compositeExpression(domainList) if len(domainList) == 1: domainList = [domainList[0]] * len(forallVarList) domainConditions += [ InSet(instanceVar, domain) for instanceVar, domain in zip(forallVarList, domainList) ] conditions = domainConditions + list(conditions) return self._checkedTruth( Generalization(self, forallVarLists, conditions))
def has_matching_ranges(self, other_tuple): ''' Return True iff the `other_tuple` matches this ExprTuple with respect to which entries are ExprRanges and, where they are, the start and end indices of the ExprRanges match. ''' from proveit import ExprRange, compositeExpression if not isinstance(other_tuple, ExprTuple): other_tuple = compositeExpression(other_tuple) if len(self) != len(other_tuple): return False # don't have the same number of entries for entry, other_entry in zip(self, other_tuple): if (isinstance(entry, ExprRange) != isinstance( other_entry, ExprRange)): return False # range vs singular mismatch if isinstance(entry, ExprRange): if entry.start_index != other_entry.start_index: return False # start indices don't match if entry.end_index != other_entry.end_index: return False # end indices don't match return True # everything matches.