def deduce_in_number_set(self, number_set, **defaults_config): from proveit.numbers import Natural, NaturalPos from proveit.logic import InSet if number_set == Natural: return self.deduce_in_natural() elif number_set == NaturalPos: return self.deduce_in_natural_pos() else: try: # Do this to avoid infinite recursion -- if # we already know this numeral is in NaturalPos # we should know how to prove that it is in any # number set that contains the natural numbers. if self.as_int() > 0: InSet(self, NaturalPos).prove(automation=False) else: InSet(self, Natural).prove(automation=False) except BaseException: # Try to prove that it is in the given number # set after proving that the numeral is in # the Natural set and the NaturalPos set. self.deduce_in_natural() if self.as_int() > 0: self.deduce_in_natural_pos() return InSet(self, number_set).conclude()
def shallow_simplification(self, *, must_evaluate=False, **defaults_config): ''' Returns a proven simplification equation for this Mod expression assuming the operands have been simplified. Specifically, performs reductions of the form (x mod L) = x where applicable and [(a mod L + b) mod L] = [(a + b) mod L]. ''' from . import (int_mod_elimination, real_mod_elimination, redundant_mod_elimination, redundant_mod_elimination_in_sum) from proveit.numbers import ( NaturalPos, RealPos, Interval, IntervalCO, subtract, zero, one) deduce_number_set(self.dividend) divisor_ns = deduce_number_set(self.divisor).domain if (NaturalPos.includes(divisor_ns) and InSet(self.dividend, Interval(zero, subtract(self.divisor, one))).proven()): # (x mod L) = x if L in N+ and x in {0 .. L-1} return int_mod_elimination.instantiate( {x:self.dividend, L:self.divisor}) if (RealPos.includes(divisor_ns) and InSet(self.dividend, IntervalCO(zero, self.divisor)).proven()): # (x mod L) = x if L in R+ and x in [0, L) return real_mod_elimination.instantiate( {x:self.dividend, L:self.divisor}) return Mod._redundant_mod_elimination( self, redundant_mod_elimination, redundant_mod_elimination_in_sum)
def derive_element_in_restricted_number_set_if_known( self, **defaults_config): ''' From (element in IntervalXX(x, y)), where either x ≥ 0 or y ≤ 0 is known or provable without automation, derive that the element is in RealPos, RealNeg, RealNonPos, or RealNonNeg as appropriate. If neither x ≥ 0 nor y ≤ 0 is known or provable without automation, raise an UnsatisfiedPrerequisites exception. ''' from proveit.numbers import RealNonNeg, RealNonPos _a = self.domain.lower_bound _b = self.domain.upper_bound if (InSet(_a, RealNonNeg).proven() or InSet(_b, RealNonPos).proven()): return self.derive_element_in_restricted_number_set() # Without employing further automation, can we prove the # lower bound is non-negative or the upper bound is # non-positive? try: _a.deduce_in_number_set(RealNonNeg, automation=False) except Exception: pass try: _b.deduce_in_number_set(RealNonPos, automation=False) except Exception: pass if (InSet(_a, RealNonNeg).proven() or InSet(_b, RealNonPos).proven()): return self.derive_element_in_restricted_number_set() raise UnsatisfiedPrerequisites( "Must know that the lower bound is non-negative or the " "upper bound is non-positive to perform " "derive_element_in_restricted_number_set_if_known")
def deduce_linear_bound(self, **defaults_config): ''' Bound the Sin function evaluation by a line. ''' from . import (sine_linear_bound, sine_linear_bound_pos, sine_linear_bound_nonneg, sine_linear_bound_neg, sine_linear_bound_nonpos) deduce_number_set(self.angle) if isinstance(self.angle, Abs): bound = sine_linear_bound.instantiate({theta: self.angle.operand}) elif InSet(self.angle, RealPos).proven(): bound = sine_linear_bound_pos.instantiate({theta: self.angle}) elif InSet(self.angle, RealNeg).proven(): bound = sine_linear_bound_neg.instantiate({theta: self.angle}) elif InSet(self.angle, RealNonNeg).proven(): bound = sine_linear_bound_nonneg.instantiate({theta: self.angle}) elif InSet(self.angle, RealNonPos).proven(): bound = sine_linear_bound_nonpos.instantiate({theta: self.angle}) else: _theta = Abs(self.angle) bound = sine_linear_bound.instantiate({theta: _theta}) if bound.rhs == self: return bound.with_direction_reversed() return bound
def includes(self, other_set): ''' Return True if this NumberSet includes the 'other_set' set. ''' from proveit.numbers.number_operation import ( sorted_number_sets, standard_number_sets, deduce_number_set) if other_set == self: return True if SubsetEq(other_set, self).proven(): return True if other_set not in standard_number_sets: # For example, 'other_set' could be an integer Interval # or real IntervalCC, IntervalOC, ...), so let's see if # we can prove that an arbitrary variable in the other_set # is also in self. _x = safe_dummy_var(self, other_set) assumptions = defaults.assumptions + (InSet(_x, other_set),) deduce_number_set(_x, assumptions=assumptions) if InSet(_x, self).proven(assumptions=assumptions): SubsetEq(other_set, self).conclude_as_folded() return True # Try one level of indirection via SubsetEq. for number_set in sorted_number_sets: if number_set in (other_set, self): continue if (SubsetEq(other_set, number_set).proven() and SubsetEq(number_set, self).proven()): return True return False # Not known to include the 'other'
def deduceInNumberSet(self, number_set, assumptions=USE_DEFAULTS): from proveit.number import Naturals, NaturalsPos from proveit.logic import InSet if number_set == Naturals: return self.deduceInNaturals() elif number_set == NaturalsPos: return self.deduceInNaturalsPos() else: try: # Do this to avoid infinite recursion -- if # we already know this numeral is in NaturalsPos # we should know how to prove that it is in any # number set that contains the naturals. if self.n > 0: InSet(self, NaturalsPos).prove(automation=False) else: InSet(self, Naturals).prove(automation=False) except: # Try to prove that it is in the given number # set after proving that the numeral is in # Naturals and NaturalsPos. self.deduceInNaturals() if self.n > 0: self.deduceInNaturalsPos() return InSet(self, number_set).conclude(assumptions)
def explicitConditions(self): ''' Return the conditions that are to be shown explicitly in the formatting (after the "such that" symbol "|") at this level according to the style. By default, this includes all of the 'joined' conditions except implicit 'domain' conditions. ''' from proveit.logic import InSet if hasattr(self, 'domains'): assert len(self.conditions) > len( self.domains), 'expecting a condition for each domain' for condition, domain in zip(self.conditions, self.domains): assert condition == InSet(self.instanceVar, domain) return self.conditions[len(self.domains):] # skip the domains else: explicit_domains = self.explicitDomains() conditions = [] for expr in self.joinedNestings(): if len(explicit_domains) == 0: conditions.extend(expr.conditions) else: assert expr.conditions[0] == InSet(expr.instanceVar, expr.domain) conditions.extend(expr.conditions[1:]) return conditions
def deduce_in_number_set(self, number_set, assumptions=USE_DEFAULTS): from proveit.numbers import Natural, NaturalPos, Digits from proveit.logic import InSet if number_set == Natural: return self.deduce_in_natural(assumptions) elif number_set == NaturalPos: return self.deduce_in_natural_pos(assumptions) elif number_set == Digits: return self.deduce_in_digits(assumptions) else: try: # Do this to avoid infinite recursion -- if # we already know this numeral is in the NaturalPos set # we should know how to prove that it is in any # number set that contains the natural numbers. if self.n > 0: InSet(self, NaturalPos).prove(automation=False) else: InSet(self, Natural).prove(automation=False) except BaseException: # Try to prove that it is in the given number # set after proving that the numeral is in the # Natural set and the NaturalPos set. self.deduce_in_natural() if self.n > 0: self.deduce_in_natural_pos() return InSet(self, number_set).conclude(assumptions)
def derive_element_in_restricted_number_set(self, **defaults_config): ''' From (member in Interval(x, y)), where x ≥ 0 or y ≤ 0, deduce that the element is in Natural, NaturalPos, IntegerNeg, or IntegerNonPos as appropriate. ''' _a = self.domain.lower_bound _b = self.domain.upper_bound _n = self.element # We wish to deduce a fact based upon the following # membership fact: self.expr.prove() if (not InSet(_a, Natural).proven() and not InSet(_b, IntegerNonPos).proven()): # If we don't know that a ≥ 0 or b ≤ 0, we can't prove # the element is in either restricted number set # (NaturalPos or IntegerNeg). So, try to sort a, b, 0 # to work this out. LessEq.sort([_a, _b, zero]) if InSet(_a, Natural).proven(): try: _a.deduce_in_number_set(NaturalPos, automation=False) except Exception: pass if InSet(_a, NaturalPos).proven(): # member in N^{>0} lower_bounding = self.derive_element_lower_bound() a_bounding = greater(_a, zero) lower_bounding.apply_transitivity(a_bounding) return InSet(_n, NaturalPos).prove() else: # member in N lower_bounding = self.derive_element_lower_bound() a_bounding = greater_eq(_a, zero) lower_bounding.apply_transitivity(a_bounding) return InSet(_n, Natural).prove() if InSet(_b, IntegerNonPos).proven(): try: _b.deduce_in_number_set(IntegerNeg, automation=False) except Exception: pass if InSet(_b, IntegerNeg).proven(): # member in Z^{<0} upper_bounding = self.derive_element_upper_bound() b_bounding = Less(_b, zero) upper_bounding.apply_transitivity(b_bounding) return InSet(_n, IntegerNeg).prove() else: # member in Z^{≤0} upper_bounding = self.derive_element_upper_bound() b_bounding = LessEq(_b, zero) upper_bounding.apply_transitivity(b_bounding) return InSet(_n, IntegerNonPos).prove()
def deduce_in_number_set(self, number_set, **defaults_config): interval_membership = self.deduce_in_interval() if isinstance(number_set, Interval): if number_set == interval_membership.domain: return interval_membership return number_set.deduce_elem_in_set(self) if InSet(self, number_set).proven(): # proven as a side-effect return InSet(self, number_set).prove() raise NotImplementedError("Proving %s in %s has not been implemented" % (self, number_set))
def deduce_as_mon_dec_func(fxn, *, domain=None, **defaults_config): ''' Prove that the Lambda-map specified by fxn is contained in the set of monotonically-decreasing functions defined over the domain. For example, we might have fxn = Lambda(x, 1/x^2) and domain = RealPos, in which case we try to prove that Lambda(x, 1/x^2) is in the set of MonDecFuncs(RealPos). ''' membership = None if domain is not None and InSet(fxn, MonDecFuncs(domain)).proven(): # fxn already known to be a monotonically-decreasing function. return InSet(fxn, MonDecFuncs(domain)).prove() if hasattr(fxn, 'deduce_as_mon_dec_func'): # If there is a 'deduce_as_mon_dec_func' class method for the # fxn, try that. membership = fxn.deduce_as_mon_dec_func() # in the original VecSpaces.deduce_as_vec_space(), the following # checked for proper class membership before returning the # the membership; instead we are dealing with a set membership # and temporarily achieve this check manually further below # if membership is not None: # InClass.check_proven_class_membership( # membership, expr, VecSpaces) # if field is not None and membership.domain.field != field: # raise ValueError("'deduce_as_vec_space' proved membership in " # "vector spaces over %s, not over the requested " # "%s field"%(membership.domain.field, field)) # def check_proven_class_membership(membership, element, class_of_class): # if (not isinstance(membership, Judgment) # or not isinstance(membership.expr, InClass) # or membership.element != element # or not isinstance(membership.domain, class_of_class)): # raise ValueError( # "Failed to meet expectation: %s is supposed to be a " # "proven Judgment that %s is a member of a class " # "represented by an Expression of type %s" # %(membership, element, class_of_class)) if membership is not None: if (not isinstance(membership, Judgment) or not isinstance(membership.expr, InSet) or membership.element != fxn or not isinstance(membership.domain, MonDecFuncs)): raise ValueError( "Failed ... with message to be completed!") return membership raise NotImplementedError( "'deduce_as_mon_dec_func' is not implemented for this case")
def deduceInNumberSet(self, number_set, assumptions=USE_DEFAULTS): ''' Given a number set number_set (such as Integers, Reals, etc), attempt to prove that the given expression is in that number set using the appropriate closure theorem. ''' from proveit.number.absolute_value._theorems_ import ( absComplexClosure, absNonzeroClosure, absComplexClosureNonNegReals) from proveit.number import Complexes, Reals, RealsNonNeg, RealsPos # among other things, make sure non-existent assumptions # manifest as empty tuple () rather than None assumptions = defaults.checkedAssumptions(assumptions) if number_set == Reals: return absComplexClosure.specialize({a: self.operand}, assumptions=assumptions) if number_set == RealsPos: return absNonzeroClosure.specialize({a: self.operand}, assumptions=assumptions) if number_set == RealsNonNeg: return absComplexClosureNonNegReals.specialize( {a: self.operand}, assumptions=assumptions) # To be thorough and a little more general, we check if the # specified number_set is already proven to *contain* one of # the number sets we have theorems for -- for example, # Y=Complexes contain X=Reals, and # Y=(-1, inf) contains X=RealsPos, # but we don't have specific thms for those supersets Y. # If so, use the appropiate thm to determine that self is in X, # then prove that self must also be in Y since Y contains X. if Subset(Reals, number_set).proven(assumptions=assumptions): absComplexClosure.specialize({a: self.operand}, assumptions=assumptions) return InSet(self, number_set).prove(assumptions=assumptions) if Subset(RealsPos, number_set).proven(assumptions=assumptions): absNonzeroClosure.specialize({a: self.operand}, assumptions=assumptions) return InSet(self, number_set).prove(assumptions=assumptions) if Subset(RealsNonNeg, number_set).proven(assumptions=assumptions): absComplexClosureNonNegReals.specialize({a: self.operand}, assumptions=assumptions) return InSet(self, number_set).prove(assumptions=assumptions) # otherwise, we just don't have the right thm to make it work msg = ("'Abs.deduceInNumberSet()' not implemented for " "the %s set" % str(number_set)) raise ProofFailure(InSet(self, number_set), assumptions, msg)
def side_effects(self, judgment): ''' Yield some possible side effects of real IntervalXX set nonmembership: (1) If element is real, deduce some possible bounds on it; (2) Deduce that the nonmembership claim is Boolean ''' _a = self.domain.lower_bound _b = self.domain.upper_bound _x = self.element if ((InSet(_a, Real)).proven() and (InSet(_b, Real)).proven() and (InSet(_x, Real)).proven()): yield self.deduce_real_element_bounds
def deduce_in_vec_space(self, vec_space=None, *, field, **defaults_config): ''' Prove that this Qmult is in a vector space (e.g., if it is a ket). ''' from proveit.physics.quantum import QmultCodomain # In the process of proving that 'self' is in QmultCodomain, # it will prove it is a vector in a Hilbert space if # appropriate. QmultCodomain.membership_object(self).conclude() if vec_space is not None: return InSet(self, vec_space).prove() return InSet(self, VecSpaces.known_vec_space(self, field=field)).prove()
def deduce_in_number_set(self, number_set, **defaults_config): from proveit.numbers import (Natural, NaturalPos, Digits, IntegerNonPos, RationalNonPos, RealNonPos) from proveit.logic import InSet, SubsetEq if number_set == Natural: return self.deduce_in_natural() elif number_set == NaturalPos: return self.deduce_in_natural_pos() elif number_set == IntegerNonPos: if self.n > 0: raise ProofFailure( InSet(self, number_set), defaults.assumptions, "%s is positive"%self) return InSet(self, number_set).conclude_as_last_resort() elif number_set == Digits: return self.deduce_in_digits() else: try: # Do this to avoid infinite recursion -- if # we already know this numeral is in the NaturalPos set # we should know how to prove that it is in any # number set that contains the natural numbers. if self.n > 0: InSet(self, NaturalPos).prove(automation=False) else: InSet(self, Natural).prove(automation=False) InSet(self, IntegerNonPos).prove(automation=False) except BaseException: # Try to prove that it is in the given number # set after proving that the numeral is in the # Natural set and the NaturalPos set. if self.n > 0: self.deduce_in_natural_pos() else: self.deduce_in_natural() self.deduce_in_integer_nonpos() if self.n > 0: sub_rel = SubsetEq(NaturalPos, number_set) else: if number_set in (RationalNonPos, RealNonPos): sub_rel = SubsetEq(IntegerNonPos, number_set) # Allow automation for this minor thing even # if automation has been disabled coming into this. sub_rel.prove(automation=True) else: sub_rel = SubsetEq(Natural, number_set) # Prove membership via inclusion: return sub_rel.derive_superset_membership(self)
def deduce_in_number_set(expr, number_set, **defaults_config): ''' Prove that 'expr' is an Expression that respresents a number in the given 'number_set'. ''' from proveit.logic import InSet membership = InSet(expr, number_set) if membership.proven(): # Already proven. We're done. return membership.prove() if hasattr(expr, 'deduce_in_number_set'): # Use 'deduce_in_number_set' method. return expr.deduce_in_number_set(number_set) # Try prove(). return membership.prove()
def derive_quantification(self, instance_param=None, **defaults_config): ''' From P(i) and ... and P(j), represented as a single ExprRange in a conjunction, prove forall_{k in {i .. j}} P(k). If 'instance_param' is provided, use it as the 'k' parameter. Otherwise, use the parameter of the ExprRange. ''' from proveit import ExprRange from proveit.logic import InSet from proveit.numbers import Interval from . import quantification_from_conjunction if (self.operands.num_entries() != 1 or not isinstance(self.operands[0], ExprRange)): raise ValueError("'derive_quantification' may only be used " "on a conjunction with a single ExprRange " "operand entry.") expr_range = self.operands[0] _i = expr_range.true_start_index _j = expr_range.true_end_index _k = expr_range.parameter if instance_param is None else instance_param _P = expr_range.lambda_map proven_quantification = quantification_from_conjunction.instantiate( { i: _i, j: _j, k: _k, P: _P }, preserve_expr=self).derive_consequent() if defaults.automation: # While we are at it, as an "unofficial" side-effect, # let's instantatiate forall_{k in {i .. j}} P(k) to derive # {k in {i .. j}} |- P(k) # and induce side-effects for P(k). assumptions = defaults.assumptions + (InSet(_k, Interval(_i, _j)), ) proven_quantification.instantiate(assumptions=assumptions) # We'll do it with the canonical variable as well for good # measure, if it is any different. canonical_version = proven_quantification.canonical_version() if canonical_version._style_id != proven_quantification._style_id: _k = canonical_version.instance_var assumptions = defaults.assumptions + (InSet( _k, Interval(_i, _j)), ) canonical_version.instantiate(assumptions=assumptions) return proven_quantification
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 shallow_simplification(self, *, must_evaluate=False, **defaults_config): ''' Returns a proven simplification equation for this VecSum expression assuming the operands have been simplified. For the trivial case of summing over only one item (currently implemented just for a Interval where the endpoints are equal), derive and return this vector summation expression equated with the simplified form of the single term. Also reduce the VecSum to a number Sum if applicable. ''' from proveit.numbers import Complex from . import vec_sum_single if (isinstance(self.domain,Interval) and self.domain.lower_bound == self.domain.upper_bound): # Reduce singular summation. if hasattr(self, 'index'): return vec_sum_single.instantiate( {Function(v, self.index): self.summand, a: self.domain.lower_bound}) inner_assumptions = defaults.assumptions + self.conditions.entries if hasattr(self.summand, 'deduce_in_number_set'): # Maybe we can reduce the VecSum to a number Sum. self.summand.deduce_in_number_set( Complex, assumptions=inner_assumptions) if InSet(self.summand, Complex).proven(assumptions=inner_assumptions): # If the operands are all complex numbers, this # VecAdd will reduce to number Add. return self.number_sum_reduction() return GroupSum.shallow_simplification( self, must_evaluate=must_evaluate)
def deduceInNumberSet(self, numberSet, assumptions=USE_DEFAULTS): from ._theorems_ import summationNatsClosure, summationIntsClosure, summationRealsClosure, summationComplexesClosure P_op, P_op_sub = Operation(P, self.instanceVars), self.instanceExpr Q_op, Q_op_sub = Operation(Qmulti, self.instanceVars), self.conditions Operation(P, self.instanceVars) self.summand if numberSet == Naturals: thm = summationNatsClosure elif numberSet == Integers: thm = summationIntsClosure elif numberSet == Reals: thm = summationRealsClosure elif numberSet == Complexes: thm = summationComplexesClosure else: raise ProofFailure( InSet(self, numberSet), assumptions, "'deduceInNumberSet' not implemented for the %s set" % str(numberSet)) return thm.specialize( { P_op: P_op_sub, S: self.domain, Q_op: Q_op_sub }, relabelMap={ xMulti: self.instanceVars }, assumptions=assumptions).deriveConsequent(assumptions=assumptions)
def side_effects(self, judgment): ''' Yield some possible side effects of Interval set nonmembership: (1) if element is an integer, deduce some possible bounds on it; ''' if InSet(self.element, Integer).proven(): yield self.deduce_int_element_bounds
def double_scaling_reduction(self, **defaults_config): from . import doubly_scaled_as_singly_scaled if not isinstance(self.scaled, ScalarMult): raise ValueError("'double_scaling_reduction' is only applicable " "for a doubly nested ScalarMult") # Reduce doubly-nested ScalarMult _x = self.scaled.scaled # _V = VecSpaces.known_vec_space(_x) # the following is a little klunky, but trying to avoid the # use of a default field=Real if we're actually dealing with # complex scalars somewhere in the vector from proveit import free_vars if any([InSet(elem, Complex).proven() for elem in free_vars(self)]): _V = VecSpaces.known_vec_space(self, field=Complex) else: _V = VecSpaces.known_vec_space(self) _K = VecSpaces.known_field(_V) _alpha = self.scalar _beta = self.scaled.scalar return doubly_scaled_as_singly_scaled.instantiate({ K: _K, V: _V, x: _x, alpha: _alpha, beta: _beta })
def rounding_deduce_in_number_set(expr, number_set, rounding_real_closure_thm, rounding_real_pos_closure_thm, assumptions=USE_DEFAULTS): ''' Given a number set number_set, attempt to prove that the given Ceil, Floor, or Round expression is in that number set using the appropriate closure theorem. ''' from proveit import ProofFailure from proveit import x from proveit.logic import InSet from proveit.numbers import Integer, Natural # among other things, convert any assumptions=None # to assumptions=() assumptions = defaults.checked_assumptions(assumptions) if number_set == Integer: return rounding_real_closure_thm.instantiate({x: expr.operand}, assumptions=assumptions) if number_set == Natural: return rounding_real_pos_closure_thm.instantiate( {x: expr.operand}, assumptions=assumptions) msg = ("The rounding_methods.py function " "'rounding_deduce_in_number_set()' is not implemented for the " "%s set" % str(number_set)) raise ProofFailure(InSet(expr, number_set), assumptions, msg)
def deduce_in_number_set(self, number_set, assumptions=USE_DEFAULTS): from . import (summation_nat_closure, summation_int_closure, summation_real_closure, summation_complex_closure) _x = self.instance_param P_op, _P_op = Function(P, _x), self.instance_expr Q_op, _Q_op = Function(Q, _x), self.condition self.summand if number_set == Natural: thm = summation_nat_closure elif number_set == Integer: thm = summation_int_closure elif number_set == Real: thm = summation_real_closure elif number_set == Complex: thm = summation_complex_closure else: raise ProofFailure( InSet(self, number_set), assumptions, ("'deduce_in_number_set' not implemented for the %s set" % str(number_set))) impl = thm.instantiate({ x: _x, P_op: _P_op, Q_op: _Q_op }, assumptions=assumptions) return impl.derive_consequent(assumptions=assumptions)
def conclude(self, assumptions=USE_DEFAULTS): ''' Attempt to conclude that the element is in the exponentiated set. ''' from proveit.logic import InSet from proveit.logic.sets.membership import (exp_set_0, exp_set_1, exp_set_2, exp_set_3, exp_set_4, exp_set_5, exp_set_6, exp_set_7, exp_set_8, exp_set_9) from proveit.numbers import zero, is_literal_int, DIGITS element = self.element domain = self.domain elem_in_set = InSet(element, domain) if not isinstance(element, ExprTuple): raise ProofFailure( elem_in_set, assumptions, "Can only automatically deduce membership in exponentiated " "sets for an element that is a list") exponent_eval = domain.exponent.evaluation(assumptions=assumptions) exponent = exponent_eval.rhs base = domain.base #print(exponent, base, exponent.as_int(),element, domain, len(element)) if is_literal_int(exponent): if exponent == zero: return exp_set_0.instantiate({S: base}, assumptions=assumptions) if element.num_entries() != exponent.as_int(): raise ProofFailure( elem_in_set, assumptions, "Element not a member of the exponentiated set; " "incorrect list length") elif exponent in DIGITS: # thm = forall_S forall_{a, b... in S} (a, b, ...) in S^n thm = locals()['exp_set_%d' % exponent.as_int()] expr_map = {S: base} # S is the base # map a, b, ... to the elements of element. expr_map.update({ proveit.__getattr__(chr(ord('a') + k)): elem_k for k, elem_k in enumerate(element) }) elem_in_set = thm.instantiate(expr_map, assumptions=assumptions) else: raise ProofFailure( elem_in_set, assumptions, "Automatic deduction of membership in exponentiated sets " "is not supported beyond an exponent of 9") else: raise ProofFailure( elem_in_set, assumptions, "Automatic deduction of membership in exponentiated sets is " "only supported for an exponent that is a literal integer") if exponent_eval.lhs != exponent_eval.rhs: # after proving that the element is in the set taken to # the evaluation of the exponent, substitute back in the # original exponent. return exponent_eval.sub_left_side_into(elem_in_set, assumptions=assumptions) return elem_in_set
def deduce_in_number_set(self, number_set, assumptions=USE_DEFAULTS): ''' Given a number set number_set (such as Integer, Real, etc), attempt to prove that the given Mod expression is in that number set using the appropriate closure theorem. ''' from proveit.logic import InSet from proveit.numbers.modular import ( mod_int_closure, mod_int_to_nat_closure, mod_real_closure) from proveit.numbers import Integer, Natural, Real # among other things, make sure non-existent assumptions # manifest as empty tuple () rather than None assumptions = defaults.checked_assumptions(assumptions) if number_set == Integer: return mod_int_closure.instantiate( {a: self.dividend, b: self.divisor}, assumptions=assumptions) if number_set == Natural: return mod_int_to_nat_closure.instantiate( {a: self.dividend, b: self.divisor}, assumptions=assumptions) if number_set == Real: return mod_real_closure.instantiate( {a: self.dividend, b: self.divisor}, assumptions=assumptions) msg = ("'Mod.deduce_in_number_set()' not implemented for " "the %s set" % str(number_set)) raise ProofFailure(InSet(self, number_set), assumptions, msg)
def conclude(self, **defaults_config): ''' Conclude something of the form a < b. ''' from proveit.logic import InSet from proveit.numbers import Add, zero, RealPos, deduce_number_set from . import positive_if_real_pos if self.upper == zero: # Special case with upper bound of zero. from . import negative_if_real_neg concluded = negative_if_real_neg.instantiate({a: self.lower}) return concluded if self.lower == zero: # Special case with lower bound of zero. deduce_number_set(self.upper) if InSet(self.upper, RealPos).proven(): positive_if_real_pos.instantiate({a: self.upper}) if ((isinstance(self.lower, Add) and self.upper in self.lower.terms.entries) or (isinstance(self.upper, Add) and self.lower in self.upper.terms.entries)): try: # Conclude an sum is bounded by one of its terms. return self.conclude_as_bounded_by_term() except UnsatisfiedPrerequisites: # If prerequisites weren't satisfied to do this, # we can still try something else. pass return NumberOrderingRelation.conclude(self)
def deduceInNumberSet(self, number_set, assumptions=USE_DEFAULTS): ''' Given a number set number_set (such as Integers, Reals, etc), attempt to prove that the given ModAbs expression is in that number set using the appropriate closure theorem. ''' from proveit._common_ import a, b from proveit.logic import InSet from proveit.number.modular._theorems_ import ( modAbsIntClosure, modAbsRealClosure) from proveit.number import Integers, Reals # among other things, make sure non-existent assumptions # manifest as empty tuple () rather than None assumptions = defaults.checkedAssumptions(assumptions) if number_set == Integers: return modAbsIntClosure.specialize( {a:self.value, b:self.divisor}, assumptions=assumptions) if number_set == Reals: return modAbsRealClosure.specialize( {a:self.value, b:self.divisor}, assumptions=assumptions) msg = ("'ModAbs.deduceInNumberSet()' not implemented for " "the %s set"%str(number_set)) raise ProofFailure(InSet(self, number_set), assumptions, msg)
def rounding_deduceInNumberSet(expr, number_set, roundingRealClosureThm, roundingRealPosClosureThm, assumptions=USE_DEFAULTS): ''' Given a number set number_set, attempt to prove that the given Ceil, Floor, or Round expression is in that number set using the appropriate closure theorem. ''' from proveit import ProofFailure from proveit._common_ import x from proveit.logic import InSet from proveit.number import Integers, Naturals # among other things, convert any assumptions=None # to assumptions=() assumptions = defaults.checkedAssumptions(assumptions) if number_set == Integers: return roundingRealClosureThm.specialize( {x:expr.operand}, assumptions=assumptions) if number_set == Naturals: return roundingRealPosClosureThm.specialize( {x:expr.operand}, assumptions=assumptions) msg = ("The rounding_methods.py function " "'rounding_deduceInNumberSet()' is not implemented for the " "%s set"%str(number_set)) raise ProofFailure(InSet(expr, number_set), assumptions, msg)
def generalize(self, forall_vars, domain=None, conditions=tuple(), **defaults_config): r''' This makes a generalization of this expression, prepending Forall operations according to new_forall_vars and new_conditions and/or new_domain that will bind 'arbitrary' free variables. This overrides the expr version to absorb antecedent into conditions if they match. For example, [A(x) => [B(x, y) => P(x, y)]] generalized forall x, y such that A(x), B(x, y) becomes forall_{x, y | A(x), B(x, y)} P(x, y). ''' from proveit.logic import InSet hypothesized_conditions = set() conditions_set = set(composite_expression(conditions)) if domain is not None: # add in the effective conditions from the domain for var in composite_expression(forall_vars): conditions_set.add(InSet(var, domain)) expr = self while isinstance(expr, Implies) and expr.antecedent in conditions_set: hypothesized_conditions.add(expr.antecedent) expr = expr.consequent if len(hypothesized_conditions) == 0: # Just use the expr version return expr.generalize(self, forall_vars, domain, conditions) return expr.generalize(expr, forall_vars, domain, conditions)