def _deduceRequirement(condition, assumptions): from proveit.number import num, LessThan, GreaterThan, GreaterThanEquals, Abs from proveit.number.complex.theorems import absIsNonNeg if isinstance(condition, In): domain = condition.domain elem = condition.element deduceInNumberSet(elem, numberSet=domain, assumptions=assumptions) elif isinstance(condition, NotEquals) and condition.rhs == num(0): deduceNotZero(condition.lhs, assumptions=assumptions) elif isinstance(condition, GreaterThan) and condition.rhs == num(0): deducePositive(condition.lhs, assumptions=assumptions) elif isinstance(condition, GreaterThanEquals) and condition.rhs == num(0): if isinstance(condition.lhs, Abs): condition.lhs.deduceGreaterThanEqualsZero(assumptions=assumptions) else: try: # if it is in Naturals, this comes naturally deduceInNaturals(condition.lhs, assumptions) Naturals.deduceMemberLowerBound( condition.lhs).checked(assumptions) except: # May also extend with deduceNonNegative, but that isn't implemented yet. pass elif isinstance(condition, GreaterThanEquals) and condition.rhs == num(1): try: # if it is in NaturalsPos, this comes naturally deduceInNaturalsPos(condition.lhs, assumptions) NaturalsPos.deduceMemberLowerBound( condition.lhs).checked(assumptions) except: pass elif isinstance(condition, LessThan) and condition.rhs == num(0): deduceNegative(condition.lhs, assumptions=assumptions)
def apply_association_thm(expr, startIdx, length, thm, assumptions=USE_DEFAULTS): from proveit.logic import Equals from proveit.number import num beg, end = startIdx, startIdx + length if beg < 0: beg = len(expr.operands) + beg # use wrap-around indexing if not length >= 2: raise IndexError( "The 'length' must be 2 or more when applying association.") if end > len(expr.operands): raise IndexError("'startIdx+length' out of bounds: %d > %d." % (end, len(expr.operands))) if beg == 0 and end == len(expr.operands): # association over the entire range is trivial: return Equals(expr, expr).prove() # simply the self equality l, m, n, AA, BB, CC = thm.allInstanceVars() return thm.specialize( { l: num(beg), m: num(end - beg), n: num(len(expr.operands) - end), AA: expr.operands[:beg], BB: expr.operands[beg:end], CC: expr.operands[end:] }, assumptions=assumptions)
def deduceEquality(self, equality, assumptions=USE_DEFAULTS, minimal_automation=False): from proveit import ExprRange from proveit.logic import Equals if not isinstance(equality, Equals): raise ValueError("The 'equality' should be an Equals expression") if equality.lhs != self: raise ValueError("The left side of 'equality' should be 'self'") from proveit.number import num, one # Handle the special counting cases. For example, # (1, 2, 3, 4) = (1, ..., 4) _n = len(self) if all(self[_k] == num(_k + 1) for _k in range(_n)): if (isinstance(equality.rhs, ExprTuple) and len(equality.rhs) == 1 and isinstance(equality.rhs[0], ExprRange)): expr_range = equality.rhs[0] if (expr_range.start_index == one and expr_range.end_index == num(_n)): if len(self) >= 10: raise NotImplementedError("counting range equality " "not implemented for more " "then 10 elements") import proveit.number.numeral.deci equiv_thm = proveit.number.numeral.deci._theorems_\ .__getattr__('count_to_%d_range'%_n) return equiv_thm raise NotImplementedError("ExprTuple.deduceEquality not implemented " "for this case: %s." % self)
def deriveSwap(self, i, j, assumptions=USE_DEFAULTS): ''' From (A and ... and H and I and J or ... or L and M or N and ... and Q), assuming in Booleans and given the beginning and end of the groups to be switched, derive and return (A and ... and H and M and J and ... and L and I and N and ... and Q). Created by JML on 6/10/19 ''' from ._theorems_ import swap from proveit.number import num if 0 < i < j < len(self.operands) - 1: return swap.specialize( { l: num(i), m: num(j - i - 1), n: num(len(self.operands) - j - 1), AA: self.operands[:i], B: self.operands[i], CC: self.operands[i + 1:j], D: self.operands[j], EE: self.operands[j + 1:] }, assumptions=assumptions) else: raise IndexError( "Beginnings and ends must be of the type: 0<i<j<length.")
def deducePartInBool(self, indexOrExpr, assumptions=USE_DEFAULTS): ''' Deduce X in Booleans from (A and B and .. and X and .. and Z) in Booleans provided X by expression or index number. ''' from ._theorems_ import eachInBool idx = indexOrExpr if isinstance(indexOrExpr, int) else list( self.operands).index(indexOrExpr) if idx < 0 or idx >= len(self.operands): raise IndexError("Operand out of range: " + str(idx)) if len(self.operands) == 2: if idx == 0: return self.deduceLeftInBool(assumptions) elif idx == 1: return self.deduceRightInBool(assumptions) else: from proveit.number import num mVal, nVal = num(idx), num(len(self.operands) - idx - 1) return eachInBool.specialize( { m: mVal, n: nVal, AA: self.operands[:idx], B: self.operands[idx], CC: self.operands[idx + 1:] }, assumptions=assumptions)
def deriveViaMultiDilemma(self, conclusion, assumptions=USE_DEFAULTS): ''' From (A or B) as self, and assuming A => C, B => D, and A, B, C, and D are Booleans, derive and return the conclusion, C or D. ''' from ._theorems_ import constructiveDilemma, destructiveDilemma, constructiveMultiDilemma, destructiveMultiDilemma from proveit.logic import Not, Or from proveit.number import num assert isinstance(conclusion, Or) and len(conclusion.operands) == len( self.operands ), "deriveViaMultiDilemma requires conclusion to be a disjunction, the same number of operands as self." # Check for destructive versus constructive dilemma cases. if all(isinstance(operand, Not) for operand in self.operands) and all( isinstance(operand, Not) for operand in conclusion.operands): # destructive case. if len(self.operands) == 2: # From Not(C) or Not(D), A => C, B => D, conclude Not(A) or Not(B) return destructiveDilemma.specialize( { C: self.operands[0].operand, D: self.operands[1].operand, A: conclusion.operands[0].operand, B: conclusion.operands[1].operand }, assumptions=assumptions) # raise NotImplementedError("Generalized destructive multi-dilemma not implemented yet.") # Iterated destructive case. From (Not(A) or Not(B) or Not(C) or Not(D)) as self negatedOperandsSelf = [ operand.operand for operand in self.operands ] negatedOperandsConc = [ operand.operand for operand in conclusion.operands ] return destructiveMultiDilemma.specialize( { m: num(len(self.operands)), A: negatedOperandsSelf, B: negatedOperandsConc }, assumptions=assumptions) else: # constructive case. if len(self.operands) == 2: # From (A or B), A => C, B => D, conclude C or D. return constructiveDilemma.specialize( { A: self.operands[0], B: self.operands[1], C: conclusion.operands[0], D: conclusion.operands[1] }, assumptions=assumptions) #raise NotImplementedError("Generalized constructive multi-dilemma not implemented yet.") return constructiveMultiDilemma.specialize( { m: num(len(self.operands)), A: self.operands, B: conclusion.operands }, assumptions=assumptions)
def concludeViaExample(self, trueOperand, assumptions=USE_DEFAULTS): ''' From one true operand, conclude that this 'or' expression is true. Requires all of the operands to be in the set of BOOLEANS. ''' from proveit.number import num from ._theorems_ import nandIfNotOne, nandIfNotLeft, nandIfNotRight index = self.operands.index(trueOperand) if len(self.operands) == 2: if index == 0: return nandIfNotLeft.specialize( { A: self.operands[0], B: self.operands[1] }, assumptions=assumptions) elif index == 1: return nandIfNotRight.specialize( { A: self.operands[0], B: self.operands[1] }, assumptions=assumptions) return nandIfNotOne.specialize( { m: num(index), n: num(len(self.operands) - index - 1), AA: self.operands[:index], B: self.operands[index], CC: self.operands[index + 1:] }, assumptions=assumptions)
def conversionToAddition(self, assumptions=USE_DEFAULTS): ''' From multiplication by an integer as the first factor, derive and return the equivalence of this multiplication to a repeated addition; for example, 3*c = c + c + c. ''' from ._axioms_ import multDef if hasattr(self.operands[0], 'asInt'): reps = self.operands[0].asInt() else: raise ValueError( "Cannot 'expandAsAddition' unless the first operand is a literal integer: %s" % str(self)) expr = self eq = TransRelUpdater( self, assumptions) # for convenience updating our equation # Group together the remaining factors if necessary: if len(self.operands) > 2: expr = eq.update( expr.association(1, len(self.operands) - 1, assumptions)) _x = self.operands[1] _n = num(reps) eq.update( multDef.specialize({ n: _n, a: [_x] * reps, x: _x }, assumptions=assumptions)) return eq.relation
def distribute(self, assumptions=USE_DEFAULTS): ''' Distribute the absolute value over a product or fraction. Assumptions may be needed to deduce that the sub-operands are complex numbers. This works fine for the Abs(Div()) case, but still eliciting an extractInitArgValue error related to a multi- variable domain condition for the Mult case. See _demos_ pg for an example; WW thinks this is a prob with iterations and we'll fix/update this later. ''' from ._theorems_ import absFrac, absProd from proveit._common_ import n, xx from proveit.number import num, Complexes, Div, Mult if isinstance(self.operand, Div): return absFrac.specialize( { a: self.operand.numerator, b: self.operand.denominator }, assumptions=assumptions) elif isinstance(self.operand, Mult): from proveit._common_ import xx theOperands = self.operand.operands return absProd.specialize( { n: num(len(theOperands)), xx: theOperands }, assumptions=assumptions) else: raise ValueError( 'Unsupported operand type for Abs.distribute() ' 'method: ', str(self.operand.__class__))
def equivalence(self, assumptions=USE_DEFAULTS): ''' From the EnumMembership object [element in {a, ..., n}], deduce and return: |– [element in {x, y, ..}] = [(element=a) or ... or (element=a)] ''' from ._axioms_ import enumSetDef from ._theorems_ import singletonDef enum_elements = self.domain.elements if len(enum_elements) == 1: return singletonDef.instantiate( { x: self.element, y: enum_elements[0] }, assumptions=assumptions) else: return enumSetDef.instantiate( { n: num(len(enum_elements)), x: self.element, y: enum_elements }, assumptions=assumptions)
def distribution(self, assumptions=USE_DEFAULTS): ''' Distribute negation through a sum, deducing and returning the equality between the original and distributed forms. ''' from ._theorems_ import distributeNegThroughBinarySum from ._theorems_ import distributeNegThroughSubtract, distributeNegThroughSum from proveit.number import Add, num from proveit.relation import TransRelUpdater expr = self eq = TransRelUpdater( expr, assumptions) # for convenience updating our equation if isinstance(self.operand, Add): # Distribute negation through a sum. add_expr = self.operand if len(add_expr.operands) == 2: # special case of 2 operands if isinstance(add_expr.operands[1], Neg): expr = eq.update( distributeNegThroughSubtract.specialize( { a: add_expr.operands[0], b: add_expr.operands[1].operand }, assumptions=assumptions)) else: expr = eq.update( distributeNegThroughBinarySum.specialize( { a: add_expr.operands[0], b: add_expr.operands[1] }, assumptions=assumptions)) else: # distribute the negation over the sum expr = eq.update(distributeNegThroughSum.specialize({ n: num(len(add_expr.operands)), xx: add_expr.operands }), assumptions=assumptions) assert isinstance( expr, Add ), "distributeNeg theorems are expected to yield an Add expression" # check for double negation for k, operand in enumerate(expr.operands): assert isinstance( operand, Neg ), "Each term from distributeNegThroughSum is expected to be negated" if isinstance(operand.operand, Neg): expr = eq.update( expr.innerExpr().operands[k].doubleNegSimplification()) return eq.relation else: raise Exception( 'Only negation distribution through a sum or subtract is implemented' )
def equivalence(self, element, assumptions=USE_DEFAULTS): ''' Deduce and return and [element in (A union B ...)] = [(element in A) or (element in B) ...] where self = (A union B ...). ''' from ._axioms_ import unionDef element = self.element operands = self.domain.operands return unionDef.specialize({l:num(len(operands)), x:element, AA:operands}, assumptions=assumptions)
def QubitRegisterSpace(num_Qbits): ''' Transplanted here beginning 2/13/2020 by wdc, from the old physics/quantum/common.py ''' # need some extra curly brackets around the Exp() expression # to allow the latex superscript to work on something # already superscripted return TensorExp({Exp(Complexes, num(2))}, num_Qbits)
def unfold(self, assumptions=USE_DEFAULTS): ''' From [element in (A union B ...)], derive and return [(element in A) or (element in B) ...], where self represents (A union B ...). ''' from ._theorems_ import membershipUnfolding from proveit.number import num element = self.element operands = self.domain.operands return membershipUnfolding.specialize({m:num(len(operands)), x:element, AA:operands}, assumptions=assumptions)
def unfold(self, assumptions=USE_DEFAULTS): ''' From [element in {x, y, ..}], derive and return [(element=x) or (element=y) or ..]. ''' from ._theorems_ import unfoldSingleton, unfold enum_elements = self.domain.elements if len(enum_elements) == 1: return unfoldSingleton.specialize({x:self.element, y:enum_elements[0]},assumptions=assumptions) else: return unfold.specialize({l:num(len(enum_elements)), x:self.element, yy:enum_elements}, assumptions=assumptions)
def equivalence(self, assumptions=USE_DEFAULTS): ''' Deduce and return and [element not in (A union B ...)] = [(element not in A) and (element not in B) ...] where self = (A union B ...). ''' from ._theorems_ import nonmembershipEquiv from proveit.number import num element = self.element operands = self.domain.operands return nonmembershipEquiv.specialize({m:num(len(operands)), x:element, AA:operands}, assumptions=assumptions)
def conclude(self, assumptions=USE_DEFAULTS): ''' From [element not in A] and [element not in B] ..., derive and return [element not in (A union B ...)], where self represents (A union B ...). ''' from ._theorems_ import nonmembershipFolding from proveit.number import num element = self.element operands = self.domain.operands return nonmembershipFolding.specialize({m:num(len(operands)), x:element, AA:operands}, assumptions=assumptions)
def locAsExprs(loc): from proveit.number import num loc_exprs = [] for coord in loc: if isinstance(coord, int): coord = num(coord) # convert int to an Expression if not isinstance(coord, Expression): raise TypeError("location coordinates must be Expression objects (or 'int's to convert to Expressions)") loc_exprs.append(coord) return loc_exprs
def getElem(self, indices, base=0, assumptions=USE_DEFAULTS, requirements=None): ''' Return the tensor element at the indices location, given as an Expression, using the given assumptions as needed to interpret the location expression. Required truths, proven under the given assumptions, that were used to make this interpretation will be appended to the given 'requirements' (if provided). ''' from proveit.number import num, Less, Add, subtract from .iteration import Iter from .composite import _simplifiedCoord if len(indices) != self.ndims: raise ExprArrayError("The 'indices' has the wrong number of dimensions: %d instead of %d"%(len(indices), self.ndims)) if requirements is None: requirements = [] # requirements won't be passed back in this case if base != 0: # subtract off the base if it is not zero indices = [subtract(index, num(self.base)) for index in indices] tensor_loc = [_simplifiedCoord(index, assumptions, requirements) for index in indices] lower_indices = [] upper_indices = [] for coord, sorted_coords in zip(tensor_loc, self.sortedCoordLists): lower, upper = None, None try: lower, upper = Less.insert(sorted_coords, coord, assumptions=assumptions) except: raise ExprArrayError("Could not determine the 'indices' range within the tensor coordinates under the given assumptions") # The relationship to the lower and upper coordinate bounds are requirements for determining # the element being assessed. requirements.append(Less.sort((sorted_coords[lower], coord), reorder=False, assumptions=assumptions)) requirements.append(Less.sort((coord, sorted_coords[upper]), reorder=False, assumptions=assumptions)) lower_indices.append(lower) upper_indices.append(upper) if tuple(lower_indices) not in self.entryOrigins or tuple(upper_indices) not in self.entryOrigins: raise ExprArrayError("Tensor element could not be found at %s"%str(tensor_loc)) rel_entry_origin = self.relEntryOrigins[lower_indices] if self.relEntryOrigins[upper_indices] != rel_entry_origin: raise ExprArrayError("Tensor element is ambiguous for %s under the given assumptions"%str(tensor_loc)) entry = self[rel_entry_origin] if isinstance(entry, Iter): # indexing into an iteration entry_origin = self.tensorLoc(rel_entry_origin) iter_start_indices = entry.start_indices iter_loc = [Add(iter_start, subtract(coord, origin)) for iter_start, coord, origin in zip(iter_start_indices, tensor_loc, entry_origin)] simplified_iter_loc = [_simplifiedCoord(coord, assumptions, requirements) for coord in iter_loc] return entry.getInstance(simplified_iter_loc, assumptions=assumptions, requirements=requirements) else: # just a single-element entry assert lower_indices==upper_indices, "A single-element entry should not have been determined if there was an ambiguous range for 'tensor_loc'" return entry
def concludeViaDemorgans(self, assumptions=USE_DEFAULTS): ''' # created by JML 6/28/19 From A and B and C conclude Not(Not(A) or Not(B) or Not(C)) ''' from ._theorems_ import demorgansLawOrToAnd, demorgansLawOrToAndBin from proveit.number import num if len(self.operands) == 2: return demorgansLawOrToAndBin.specialize({A:self.operands[0], B:self.operands[1]}, assumptions=assumptions) else: return demorgansLawOrToAnd.specialize({m:num(len(self.operands)), A:self.operands}, assumptions=assumptions)
def deduceInBool(self, assumptions=USE_DEFAULTS): ''' Attempt to deduce, then return, that this 'and' expression is in the set of BOOLEANS. ''' from ._theorems_ import binaryClosure, closure if len(self.operands)==2: return binaryClosure.specialize({A:self.operands[0], B:self.operands[1]}, assumptions=assumptions) else: from proveit.number import num return closure.specialize({m:num(len(self.operands)), A:self.operands}, assumptions=assumptions)
def equivalence(self): ''' Deduce and return and [element not in {x, y, ..}] = [(element != x) and (element != y) and ...] where self = {y}. ''' from ._theorems_ import notInSingletonEquiv, nonmembershipEquiv enum_elements = self.domain.elements if len(enum_elements) == 1: return notInSingletonEquiv.specialize({x:self.element, y:enum_elements}) else: return nonmembershipEquiv.specialize({l:num(len(enum_elements)), x:self.element, yy:enum_elements})
def __init__(self, operandA, operandB): r''' Sub one number from another ''' from proveit.number import Add, isLiteralInt, num Operation.__init__(self, Subtract._operator_, (operandA, operandB)) if all(isLiteralInt(operand) for operand in self.operands): # With literal integer operands, we can import useful theorems for evaluation. # From c - b, make the a+b which equals c. This will import the theorems we need. Add(num(self.operands[0].asInt() - self.operands[1].asInt()), self.operands[1])
def evaluation(self, assumptions=USE_DEFAULTS): ''' Given operands that evaluate to TRUE or FALSE, derive and return the equality of this expression with TRUE or FALSE. ''' from ._axioms_ import orTT, orTF, orFT, orFF # load in truth-table evaluations from ._theorems_ import trueEval, falseEval from proveit.logic.boolean._common_ import TRUE, FALSE trueIndex = -1 for i, operand in enumerate(self.operands): if operand != TRUE and operand != FALSE: # The operands are not always true/false, so try the default evaluation method # which will attempt to evaluate each of the operands. return Operation.evaluation(self, assumptions) if operand == TRUE: trueIndex = i if len(self.operands) == 2: # This will automatically return orTT, orTF, orFT, or orFF return Operation.evaluation(self, assumptions) if trueIndex >= 0: # one operand is TRUE so the whole disjunction evaluates to TRUE. from proveit.number import num mVal, nVal = num(trueIndex), num( len(self.operands) - trueIndex - 1) return trueEval.specialize( { m: mVal, n: nVal, AA: self.operands[:trueIndex], CC: self.operands[trueIndex + 1:] }, assumptions=assumptions) else: # no operand is TRUE so the whole disjunction evaluates to FALSE. from proveit.number import num return falseEval.specialize( { m: num(len(self.operands)), AA: self.operands }, assumptions=assumptions)
def innerNegMultSimplification(self, idx, assumptions=USE_DEFAULTS): ''' Equivalence method to derive a simplification when negating a multiplication with a negated factor. For example, -(a*b*(-c)*d) = a*b*c*d. See Mult.negSimplification where this may be used indirectly. ''' from proveit.number import Mult, num from ._theorems_ import multNegLeftDouble, multNegRightDouble, multNegAnyDouble mult_expr = self.operand if not isinstance(mult_expr, Mult): raise ValueError( "Operand expected to be a Mult expression for %s" % (idx, str(self))) if not isinstance(mult_expr.operands[idx], Neg): raise ValueError( "Operand at the index %d expected to be a negation for %s" % (idx, str(mult_expr))) if len(mult_expr.operands) == 2: if idx == 0: return multNegLeftDouble.specialize({a: mult_expr.operands[1]}, assumptions=assumptions) else: return multNegRightDouble.specialize( {a: mult_expr.operands[0]}, assumptions=assumptions) aVal = mult_expr.operands[:idx] bVal = mult_expr.operands[idx] cVal = mult_expr.operands[idx + 1:] mVal = num(len(aVal)) nVal = num(len(cVal)) return multNegAnyDouble.specialize( { m: mVal, n: nVal, AA: aVal, B: bVal, CC: cVal }, assumptions=assumptions)
def distinctSubsetExistence(self, elems=None, assumptions=USE_DEFAULTS): ''' Assuming the cardinality of the domain can be proven to be >= 2, proves and returns that there exists distinct elements in that domain. ''' from proveit.number import num from ._theorems_ import distinctSubsetExistence, distinctPairExistence if len(elems)==2: aVar, bVar = elems return distinctPairExistence.specialize({S:self.domain}, relabelMap={a:aVar, b:bVar}, assumptions=assumptions) else: return distinctSubsetExistence.specialize({S:self.domain, N:num(len(elems))}, relabelMap={xMulti:elems}, assumptions=assumptions)
def deduceInNumberSet(self, numberSet, assumptions=USE_DEFAULTS): # edited by JML 7/20/19 from ._theorems_ import multIntClosure, multIntClosureBin, multNatClosure, multNatClosureBin, multNatPosClosure, multNatClosureBin, multRealClosure, multRealClosureBin, multRealPosClosure, multRealPosClosureBin, multComplexClosure, multComplexClosureBin from proveit.number import num if hasattr(self, 'number_set'): numberSet = numberSet.number_set bin = False if numberSet == Integers: if len(self.operands) == 2: thm = multIntClosureBin bin = True else: thm = multIntClosure elif numberSet == Naturals: if len(self.operands) == 2: thm = multNatsClosureBin bin = True else: thm = multNatsClosure elif numberSet == NaturalsPos: if len(self.operands) == 2: thm = multNatsPosClosureBin bin = True else: thm = multNatsPosClosure elif numberSet == Reals: if len(self.operands) == 2: thm = multRealClosureBin bin = True else: thm = multRealClosure elif numberSet == RealsPos: if len(self.operands) == 2: thm = multRealsPosClosureBin bin = True else: thm = multRealPosClosure elif numberSet == Complexes: if len(self.operands) == 2: thm = multComplexClosureBin bin = True else: thm = multComplexClosure else: msg = "'deduceInNumberSet' not implemented for the %s set"%str(numberSet) raise ProofFailure(InSet(self, numberSet), assumptions, msg) from proveit._common_ import AA # print("thm", thm) # print("self in deduce in number set", self) # print("self.operands", self.operands) if bin: return thm.specialize({a:self.operands[0], b:self.operands[1]}, assumptions=assumptions) return thm.specialize({m:num(len(self.operands)),AA:self.operands}, assumptions=assumptions)
def apply_disassociation_thm(expr, idx, thm=None, assumptions=USE_DEFAULTS): from proveit.number import num if idx < 0: idx = len(expr.operands) + idx # use wrap-around indexing if idx >= len(expr.operands): raise IndexError("'idx' out of range for disassociation") if not isinstance(expr.operands[idx], expr.__class__): raise ValueError( "Expecting %d index of %s to be grouped (i.e., a nested expression of the same type)" % (idx, str(expr))) l, m, n, AA, BB, CC = thm.allInstanceVars() length = len(expr.operands[idx].operands) return thm.specialize( { l: num(idx), m: num(length), n: num(len(expr.operands) - idx - 1), AA: expr.operands[:idx], BB: expr.operands[idx].operands, CC: expr.operands[idx + 1:] }, assumptions=assumptions)
def equivalence(self, assumptions=USE_DEFAULTS): ''' Deduce and return and [element in {x, y, ..}] = [(element=x) or (element=y) or ...] where self = {y}. ''' from ._axioms_ import enumSetDef from ._theorems_ import singletonDef enum_elements = self.domain.elements if len(enum_elements) == 1: return singletonDef.specialize({x:self.element, y:enum_elements[0]}, assumptions=assumptions) else: return enumSetDef.specialize({l:num(len(enum_elements)), x:self.element, yy:enum_elements}, assumptions=assumptions)
def oneElimination(self, idx, assumptions=USE_DEFAULTS): ''' Equivalence method that derives a simplification in which a single factor of one, at the given index, is eliminated. For example: x*y*1*z = x*y*z ''' from proveit.number import one, num from ._theorems_ import elimOneLeft, elimOneRight, elimOneAny if self.operands[idx] != one: raise ValueError("Operand at the index %d expected to be zero for %s"%(idx, str(self))) if len(self.operands)==2: if idx==0: return elimOneLeft.specialize({x:self.operands[1]}, assumptions=assumptions) else: return elimOneRight.specialize({x:self.operands[0]}, assumptions=assumptions) aVal = self.operands[:idx] bVal = self.operands[idx+1:] mVal = num(len(aVal)) nVal = num(len(bVal)) return elimOneAny.specialize({m:mVal, n:nVal, AA:aVal, BB:bVal}, assumptions=assumptions)