def interval_union_subset(t): """Given t of the form I1 Un I2, return a theorem of the form I1 Un I2 SUB I. """ assert t.is_comb('union', 2), "interval_union_subset" I1, I2 = t.args a, b = I1.args c, d = I2.args if is_closed_interval(I1) and is_closed_interval(I2): pt = apply_theorem('closed_interval_union', inst=Inst(a=a, b=b, c=c, d=d)) return pt.on_prop( arg_conv( then_conv(arg1_conv(const_min_conv()), arg_conv(const_max_conv())))) elif is_open_interval(I1) and is_ropen_interval(I2): if eval_hol_expr(c) <= eval_hol_expr(a): pt = apply_theorem('open_ropen_interval_union1', auto.auto_solve(real.less_eq(c, a)), inst=Inst(b=b, d=d)) else: pt = apply_theorem('open_ropen_interval_union2', auto.auto_solve(real.less(a, c)), inst=Inst(b=b, d=d)) return pt.on_prop(arg_conv(arg_conv(const_max_conv()))) else: raise NotImplementedError return pt
def get_proof_term(self, t): if eval_hol_expr(t.arg1) <= eval_hol_expr(t.arg): return apply_theorem('real_max_eq_right', auto.auto_solve(real.less_eq(t.arg1, t.arg))) else: return apply_theorem('real_max_eq_left', auto.auto_solve(real.greater(t.arg1, t.arg)))
def combine_mem_bounds(pt1, pt2): """Given two inequalities of the form x </<= a and b </<= y, where a and b are constants, attempt to form the theorem x </<= y. """ assert pt1.prop.is_less_eq() or pt1.prop.is_less(), "combine_mem_bounds" assert pt2.prop.is_less_eq() or pt2.prop.is_less(), "combine_mem_bounds" x, a = pt1.prop.args b, y = pt2.prop.args # First obtain the comparison between a and b if eval_hol_expr(a) < eval_hol_expr(b): pt_ab = ProofTerm('const_inequality', real.less(a, b)) elif eval_hol_expr(a) <= eval_hol_expr(b): pt_ab = ProofTerm('const_inequality', real.less_eq(a, b)) else: raise TacticException # Next, successively combine the inequalities pt = inequality_trans(inequality_trans(pt1, pt_ab), pt2) return pt
def get_bounds_proof(t, var_range): """Given a term t and a mapping from variables to intervals, return a theorem for t belonging to an interval. t - Term, a HOL expression. var_range - dict(str, Thm): mapping from variables x to theorems of the form x Mem [a, b] or x Mem (a, b). Returns a theorem of the form t Mem [a, b] or t Mem (a, b). """ if t.ty == Term.VAR: assert t.name in var_range, "get_bounds_proof: variable %s not found" % t.name return var_range[t.name] elif t.is_number() or t == real.pi: return apply_theorem('const_interval', inst=Inst(x=t)) elif t.is_plus(): pt1 = get_bounds_proof(t.arg1, var_range) pt2 = get_bounds_proof(t.arg, var_range) if is_mem_closed(pt1) and is_mem_closed(pt2): pt = apply_theorem('add_interval_closed', pt1, pt2) elif is_mem_open(pt1) and is_mem_open(pt2): pt = apply_theorem('add_interval_open', pt1, pt2) elif is_mem_open(pt1) and is_mem_closed(pt2): pt = apply_theorem('add_interval_open_closed', pt1, pt2) elif is_mem_closed(pt1) and is_mem_open(pt2): pt = apply_theorem('add_interval_closed_open', pt1, pt2) elif is_mem_closed(pt1) and is_mem_lopen(pt2): pt = apply_theorem('add_interval_closed_lopen', pt1, pt2) elif is_mem_closed(pt1) and is_mem_ropen(pt2): pt = apply_theorem('add_interval_closed_ropen', pt1, pt2) elif is_mem_ropen(pt1) and is_mem_closed(pt2): pt = apply_theorem('add_interval_closed_ropen', pt2, pt1) pt = pt.on_prop(arg1_conv(rewr_conv('real_add_comm'))) else: raise NotImplementedError('get_bounds: %s, %s' % (pt1, pt2)) return norm_mem_interval(pt) elif t.is_uminus(): pt = get_bounds_proof(t.arg, var_range) if is_mem_closed(pt): pt = apply_theorem('neg_interval_closed', pt) elif is_mem_open(pt): pt = apply_theorem('neg_interval_open', pt) else: raise NotImplementedError return norm_mem_interval(pt) elif t.is_minus(): rewr_t = t.arg1 + (-t.arg) pt = get_bounds_proof(rewr_t, var_range) return pt.on_prop(arg1_conv(rewr_conv('real_minus_def', sym=True))) elif t.is_real_inverse(): pt = get_bounds_proof(t.arg, var_range) a, b = get_mem_bounds(pt) if eval_hol_expr(a) > 0 and is_mem_closed(pt): pt = apply_theorem('inverse_interval_pos_closed', auto.auto_solve(real_pos(a)), pt) else: raise NotImplementedError return norm_mem_interval(pt) elif t.is_times(): if t.arg1.has_var(): pt1 = get_bounds_proof(t.arg1, var_range) pt2 = get_bounds_proof(t.arg, var_range) a, b = get_mem_bounds(pt1) c, d = get_mem_bounds(pt2) if eval_hol_expr(a) >= 0 and eval_hol_expr(c) >= 0 and is_mem_open( pt1) and is_mem_open(pt2): pt = apply_theorem('mult_interval_pos_pos_open', auto.auto_solve(real_nonneg(a)), auto.auto_solve(real_nonneg(c)), pt1, pt2) elif eval_hol_expr(a) >= 0 and eval_hol_expr( c) >= 0 and is_mem_closed(pt1) and is_mem_closed(pt2): pt = apply_theorem('mult_interval_pos_pos_closed', auto.auto_solve(real_nonneg(a)), auto.auto_solve(real_nonneg(c)), pt1, pt2) elif eval_hol_expr(a) >= 0 and eval_hol_expr( c) >= 0 and is_mem_lopen(pt1) and is_mem_ropen(pt2): pt = apply_theorem('mult_interval_pos_pos_lopen_ropen', auto.auto_solve(real_nonneg(a)), auto.auto_solve(real_nonneg(c)), pt1, pt2) elif eval_hol_expr(b) <= 0 and eval_hol_expr( c) >= 0 and is_mem_open(pt1) and is_mem_open(pt2): pt = apply_theorem('mult_interval_neg_pos_open', auto.auto_solve(real_nonpos(b)), auto.auto_solve(real_nonneg(c)), pt1, pt2) else: raise NotImplementedError('get_bounds: %s, %s' % (pt1, pt2)) else: pt = get_bounds_proof(t.arg, var_range) a, b = get_mem_bounds(pt) c = t.arg1 nc = eval_hol_expr(c) if nc >= 0 and is_mem_closed(pt): pt = apply_theorem('mult_interval_pos_closed', auto.auto_solve(real_nonneg(c)), pt) elif nc >= 0 and is_mem_open(pt): pt = apply_theorem('mult_interval_pos_open', auto.auto_solve(real_nonneg(c)), pt) elif nc >= 0 and is_mem_lopen(pt): pt = apply_theorem('mult_interval_pos_lopen', auto.auto_solve(real_nonneg(c)), pt) elif nc >= 0 and is_mem_ropen(pt): pt = apply_theorem('mult_interval_pos_ropen', auto.auto_solve(real_nonneg(c)), pt) elif nc < 0 and is_mem_closed(pt): pt = apply_theorem('mult_interval_neg_closed', auto.auto_solve(real_neg(c)), pt) elif nc < 0 and is_mem_open(pt): pt = apply_theorem('mult_interval_neg_open', auto.auto_solve(real_neg(c)), pt) elif nc < 0 and is_mem_lopen(pt): pt = apply_theorem('mult_interval_neg_lopen', auto.auto_solve(real_neg(c)), pt) elif nc < 0 and is_mem_ropen(pt): pt = apply_theorem('mult_interval_neg_ropen', auto.auto_solve(real_neg(c)), pt) else: raise NotImplementedError return norm_mem_interval(pt) elif t.is_divides(): rewr_t = t.arg1 * (real.inverse(t.arg)) pt = get_bounds_proof(rewr_t, var_range) return pt.on_prop(arg1_conv(rewr_conv('real_divide_def', sym=True))) elif t.is_nat_power(): pt = get_bounds_proof(t.arg1, var_range) if not t.arg.is_number(): raise NotImplementedError return get_nat_power_bounds(pt, t.arg) elif t.is_real_power(): pt = get_bounds_proof(t.arg1, var_range) a, b = get_mem_bounds(pt) if not t.arg.is_number(): raise NotImplementedError p = t.arg.dest_number() if p >= 0 and eval_hol_expr(a) >= 0: nonneg_p = auto.auto_solve(real_nonneg(t.arg)) nonneg_a = auto.auto_solve(real_nonneg(a)) if is_mem_closed(pt): pt = apply_theorem('real_power_interval_pos_closed', nonneg_p, nonneg_a, pt) elif is_mem_open(pt): pt = apply_theorem('real_power_interval_pos_open', nonneg_p, nonneg_a, pt) else: raise NotImplementedError elif p < 0: neg_p = auto.auto_solve(real_neg(t.arg)) if is_mem_closed(pt) and eval_hol_expr(a) > 0: pos_a = auto.auto_solve(real_pos(a)) pt = apply_theorem('real_power_interval_neg_closed', neg_p, pos_a, pt) elif is_mem_open(pt): nonneg_a = auto.auto_solve(real_nonneg(a)) pt = apply_theorem('real_power_interval_neg_open', neg_p, nonneg_a, pt) elif is_mem_lopen(pt): nonneg_a = auto.auto_solve(real_nonneg(a)) pt = apply_theorem('real_power_interval_neg_lopen', neg_p, nonneg_a, pt) else: print(pt) raise NotImplementedError else: raise NotImplementedError return norm_mem_interval(pt) elif t.head == real.log: pt = get_bounds_proof(t.arg, var_range) a, b = get_mem_bounds(pt) if eval_hol_expr(a) > 0 and is_mem_closed(pt): pt = apply_theorem('log_interval_closed', auto.auto_solve(real_pos(a)), pt) elif eval_hol_expr(a) >= 0 and is_mem_open(pt): pt = apply_theorem('log_interval_open', auto.auto_solve(real_nonneg(a)), pt) else: raise NotImplementedError return norm_mem_interval(pt) elif t.head == real.exp: pt = get_bounds_proof(t.arg, var_range) if is_mem_closed(pt): pt = apply_theorem('exp_interval_closed', pt) elif is_mem_open(pt): pt = apply_theorem('exp_interval_open', pt) else: raise NotImplementedError return norm_mem_interval(pt) elif t.head == real.sin: pt = get_bounds_proof(t.arg, var_range) a, b = get_mem_bounds(pt) if eval_hol_expr(a) >= -math.pi / 2 and eval_hol_expr( b) <= math.pi / 2: if is_mem_closed(pt): pt = apply_theorem( 'sin_interval_main_closed', auto.auto_solve(real.greater_eq(a, -real.pi / 2)), auto.auto_solve(real.less_eq(b, real.pi / 2)), pt) elif is_mem_open(pt): pt = apply_theorem( 'sin_interval_main_open', auto.auto_solve(real.greater_eq(a, -real.pi / 2)), auto.auto_solve(real.less_eq(b, real.pi / 2)), pt) else: raise NotImplementedError elif eval_hol_expr(a) >= 0 and eval_hol_expr(b) <= math.pi: if is_mem_closed(pt): pt = apply_theorem('sin_interval_pos_closed', auto.auto_solve(real_nonneg(a)), auto.solve(real.less_eq(b, real.pi)), pt) elif is_mem_open(pt): pt = apply_theorem('sin_interval_pos_open', auto.auto_solve(real_nonneg(a)), auto.solve(real.less_eq(b, real.pi)), pt) else: raise NotImplementedError else: raise NotImplementedError return norm_mem_interval(pt) elif t.head == real.cos: pt = get_bounds_proof(t.arg, var_range) a, b = get_mem_bounds(pt) if eval_hol_expr(a) >= 0 and eval_hol_expr(b) <= math.pi: if is_mem_closed(pt): pt = apply_theorem('cos_interval_main_closed', auto.auto_solve(real_nonneg(a)), auto.auto_solve(real.less_eq(b, real.pi)), pt) elif is_mem_open(pt): pt = apply_theorem('cos_interval_main_open', auto.auto_solve(real_nonneg(a)), auto.auto_solve(real.less_eq(b, real.pi)), pt) else: raise NotImplementedError elif eval_hol_expr(a) >= -math.pi / 2 and eval_hol_expr( b) <= math.pi / 2: if is_mem_closed(pt): pt = apply_theorem( 'cos_interval_pos_closed', auto.auto_solve(real.greater_eq(a, -real.pi / 2)), auto.auto_solve(real.less_eq(b, real.pi / 2)), pt) elif is_mem_open(pt): pt = apply_theorem( 'cos_interval_pos_open', auto.auto_solve(real.greater_eq(a, -real.pi / 2)), auto.auto_solve(real.less_eq(b, real.pi / 2)), pt) else: raise NotImplementedError else: raise NotImplementedError return norm_mem_interval(pt) elif t.head == real.atn: pt = get_bounds_proof(t.arg, var_range) if is_mem_closed(pt): pt = apply_theorem('atn_interval_closed', pt) elif is_mem_open(pt): pt = apply_theorem('atn_interval_open', pt) else: raise NotImplementedError return norm_mem_interval(pt) else: print("Cannot deal with", t) raise NotImplementedError
def get_nat_power_bounds(pt, n): """Given theorem of the form t Mem I, obtain a theorem of the form t ^ n Mem J. """ a, b = get_mem_bounds(pt) if not n.is_number(): raise NotImplementedError if eval_hol_expr(a) >= 0 and is_mem_closed(pt): pt = apply_theorem('nat_power_interval_pos_closed', auto.auto_solve(real_nonneg(a)), pt, inst=Inst(n=n)) elif eval_hol_expr(a) >= 0 and is_mem_open(pt): pt = apply_theorem('nat_power_interval_pos_open', auto.auto_solve(real_nonneg(a)), pt, inst=Inst(n=n)) elif eval_hol_expr(a) >= 0 and is_mem_lopen(pt): pt = apply_theorem('nat_power_interval_pos_lopen', auto.auto_solve(real_nonneg(a)), pt, inst=Inst(n=n)) elif eval_hol_expr(a) >= 0 and is_mem_ropen(pt): pt = apply_theorem('nat_power_interval_pos_ropen', auto.auto_solve(real_nonneg(a)), pt, inst=Inst(n=n)) elif eval_hol_expr(b) <= 0 and is_mem_closed(pt): int_n = n.dest_number() if int_n % 2 == 0: even_pt = nat_as_even(int_n) pt = apply_theorem('nat_power_interval_neg_even_closed', auto.auto_solve(real_nonpos(b)), even_pt, pt) else: odd_pt = nat_as_odd(int_n) pt = apply_theorem('nat_power_interval_neg_odd_closed', auto.auto_solve(real_nonpos(b)), odd_pt, pt) elif eval_hol_expr(b) <= 0 and is_mem_open(pt): int_n = n.dest_number() if int_n % 2 == 0: even_pt = nat_as_even(int_n) pt = apply_theorem('nat_power_interval_neg_even_open', auto.auto_solve(real_nonpos(b)), even_pt, pt) else: odd_pt = nat_as_odd(int_n) pt = apply_theorem('nat_power_interval_neg_odd_open', auto.auto_solve(real_nonpos(b)), odd_pt, pt) elif is_mem_closed(pt): # Closed interval containing 0 t = pt.prop.arg1 assm1 = hol_set.mk_mem(t, real.closed_interval(a, Real(0))) assm2 = hol_set.mk_mem(t, real.closed_interval(Real(0), b)) pt1 = get_nat_power_bounds(ProofTerm.assume(assm1), n).implies_intr(assm1) pt2 = get_nat_power_bounds(ProofTerm.assume(assm2), n).implies_intr(assm2) x = Var('x', RealType) pt = apply_theorem('split_interval_closed', auto.auto_solve(real.less_eq(a, Real(0))), auto.auto_solve(real.less_eq(Real(0), b)), pt1, pt2, pt, inst=Inst(x=t, f=Lambda(x, x**n))) subset_pt = interval_union_subset(pt.prop.arg) pt = apply_theorem('subsetE', subset_pt, pt) elif is_mem_open(pt): # Open interval containing 0 t = pt.prop.arg1 assm1 = hol_set.mk_mem(t, real.open_interval(a, Real(0))) assm2 = hol_set.mk_mem(t, real.ropen_interval(Real(0), b)) pt1 = get_nat_power_bounds(ProofTerm.assume(assm1), n).implies_intr(assm1) pt2 = get_nat_power_bounds(ProofTerm.assume(assm2), n).implies_intr(assm2) x = Var('x', RealType) pt = apply_theorem('split_interval_open', auto.auto_solve(real.less_eq(a, Real(0))), auto.auto_solve(real.less_eq(Real(0), b)), pt1, pt2, pt, inst=Inst(x=t, f=Lambda(x, x**n))) subset_pt = interval_union_subset(pt.prop.arg) pt = apply_theorem('subsetE', subset_pt, pt) else: raise NotImplementedError return norm_mem_interval(pt)
def real_nonpos(a): return real.less_eq(a, Real(0))