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 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 multi_elem_entries(element_from_part, start_qubit_idx, end_qubit_idx, *part_start_and_ends, check_part_index_span=True): ''' Yield consecutive vertical entries for MultiQubitElem to represent all parts of a multi-qubit operation in a quantum circuit involving all qubits from 'start_qubit_idx' to 'end_qubit_idx. There will be an entry for each "part" start/end pair of indices. In total, these must start from one, be consecutive, and cover the range from the 'start_qubit_idx' to the 'end_qubit_idx. The element_from_part function must return an element corresponding to a given 'part'. ''' targets = Interval(start_qubit_idx, end_qubit_idx) multi_qubit_gate_from_part = ( lambda part: MultiQubitElem(element_from_part(part), targets)) part = one if len(part_start_and_ends) == 0: raise ValueError("Must specify one or more 'part' start and end " "indices, starting from one and covering the range " "from %s to %s" % (start_qubit_idx, end_qubit_idx)) for part_start, part_end in part_start_and_ends: #try: # Equals(part, part_start).prove() #except ProofFailure: if part != part_start: raise ValueError("Part indices must be provably consecutive " "starting from 1: %s ≠ %s" % (part_start, part)) if part_start == part_end: # just a single element yield multi_qubit_gate_from_part(part) else: param = safe_dummy_var() yield ExprRange(param, multi_qubit_gate_from_part(param), part_start, part_end) part = Add(part_end, one).quick_simplified() if not check_part_index_span: lhs = Add(part_end, num(-1)).quick_simplified() rhs = Add(end_qubit_idx, Neg(start_qubit_idx)).quick_simplified() try: try: lhs = lhs.simplified() except: pass try: rhs = rhs.simplified() except: pass Equals(lhs, rhs).prove() except ProofFailure: raise ValueError("Part indices must span the range of the " "multi qubit operation: %s ≠ %s" % (lhs, rhs))
def known_vec_spaces(vecs, *, field=None): ''' Return the known vector spaces of the given vecs under the specified field (or the default field). ''' # Effort to appropriately handle an ExprRange operand added # here by wdc and ww on 1/3/2022. vec_spaces = [] for vec in vecs: if isinstance(vec, ExprRange): # create our expr range with defaults.temporary() as tmp_defaults: assumption = InSet(vec.parameter, Interval(vec.true_start_index, vec.true_end_index)) tmp_defaults.assumptions = ( defaults.assumptions + (assumption ,)) body = VecSpaces.known_vec_space(vec.body, field=field) vec_spaces.append( ExprRange(vec.parameter, body, vec.true_start_index, vec.true_end_index)) else: vec_spaces.append(VecSpaces.known_vec_space(vec, field=field)) return vec_spaces
int_within_complex in_natural_if_non_neg = Forall(a, InSet(a, Natural), domain=Integer, conditions=[GreaterThanEquals(a, zero)]) in_natural_if_non_neg in_natural_pos_if_pos = Forall(a, InSet(a, NaturalPos), domain=Integer, conditions=[GreaterThan(a, zero)]) in_natural_pos_if_pos interval_is_int = Forall((a, b), Forall(n, InSet(n, Integer), domain=Interval(a, b)), domain=Integer) interval_is_int interval_is_nat = Forall((a, b), Forall(n, InSet(n, Natural), domain=Interval(a, b)), domain=Natural) interval_is_nat interval_in_nat_pos = Forall((a, b), Forall(n, InSet(n, NaturalPos), domain=Interval(a, b)), domain=Integer, conditions=[GreaterThan(a, zero)]) interval_in_nat_pos
from proveit.logic import Forall, InSet, Equals, NotEquals, Iff, And, SetOfAll from proveit.numbers import Integer, Interval, Real, RealPos, Complex from proveit.numbers import Abs, Mod, ModAbs, GreaterThanEquals, LessThanEquals, Add, Sub, Neg, Mult, frac, IntervalCO from proveit.common import a, b, c, x, y, N, x_etc, x_multi from proveit.numbers.common import zero, one from proveit import begin_theorems, end_theorems begin_theorems(locals()) # transferred by wdc 3/11/2020 mod_int_closure = Forall((a, b), InSet(Mod(a, b), Integer), domain=Integer) mod_int_closure # transferred by wdc 3/11/2020 mod_in_interval = Forall((a, b), InSet( Mod(a, b), Interval(zero, Sub(b, one))), domain=Integer) mod_in_interval # transferred by wdc 3/11/2020 mod_real_closure = Forall((a, b), InSet(Mod(a, b), Real), domain=Real) mod_real_closure # transferred by wdc 3/11/2020 mod_abs_real_closure = Forall((a, b), InSet(ModAbs(a, b), Real), domain=Real) mod_abs_real_closure # transferred by wdc 3/11/2020 abs_complex_closure = Forall([a], InSet(Abs(a), Real), domain=Complex) abs_complex_closure # transferred by wdc 3/11/2020
m_ = Literal(pkg, 'm') # phase_m: Random variable for the phase result of the quantum phase estimation. # phase_m = m / 2^t phase_m_ = Literal(pkg, 'phase_m', {LATEX: r'\varphi_m'}) # b: The "best" outcome of m such that phase_m is as close as possible to # phase. b_ = Literal(pkg, 'b') # 2^t two_pow_t = Exp(two, t_) # 2^{t-1} two_pow_t_minus_one = Exp(two, Sub(t_, one)) # amplitude of output register as indexted alpha_ = Literal(pkg, 'alpha', {STRING: 'alpha', LATEX: r'\alpha'}) alpha_l = SubIndexed(alpha_, l) abs_alpha_l = Abs(alpha_l) alpha_l_sqrd = Exp(Abs(alpha_l), two) # delta: difference between the phase and the best phase_m delta_ = Literal(pkg, 'delta', {LATEX: r'\delta'}) full_domain = Interval(Add(Neg(Exp(two, Sub(t_, one))), one), Exp(two, Sub(t_, one))) neg_domain = Interval(Add(Neg(two_pow_t_minus_one), one), Neg(Add(eps, one))) pos_domain = Interval(Add(eps, one), two_pow_t_minus_one) eps_domain = Interval(one, Sub(two_pow_t_minus_one, two))
from proveit.logic import Forall, Equals from proveit.numbers import Sum, Integer, Interval, LessThan, Add, Sub from proveit.common import a, b, f, x, fa, fb, fx from proveit.numbers.common import one from proveit import begin_axioms, end_axioms begin_axioms(locals()) sum_single = Forall(f, Forall(a, Equals(Sum(x, fx, Interval(a, a)), fa), domain=Integer)) sum_single sum_split_last = Forall(f, Forall([a, b], Equals(Sum(x, fx, Interval(a, b)), Add(Sum(x, fx, Interval(a, Sub(b, one))), fb)), domain=Integer, conditions=[LessThan(a, b)])) sum_split_last end_axioms(locals(), __package__)