def testNormAbsoluteValue(self): test_data = [ ("abs x", ["x >= 0"], "x"), ("abs x", ["x Mem real_closed_interval 0 1"], "x"), ("abs x", ["x Mem real_closed_interval (-1) 0"], "-1 * x"), ("abs (sin x)", ["x Mem real_closed_interval 0 (pi / 2)"], "sin x"), ("abs (sin x)", ["x Mem real_closed_interval (-pi / 2) 0"], "-1 * sin x"), ("abs (log x)", ["x Mem real_open_interval (exp (-1)) 1"], "-1 * log x"), ] vars = {'x': 'real'} context.set_context('interval_arith', vars=vars) for t, conds, res in test_data: conds_pt = [ ProofTerm.assume(parser.parse_term(cond)) for cond in conds ] cv = auto.auto_conv(conds_pt) test_conv(self, 'interval_arith', cv, vars=vars, t=t, t_res=res, assms=conds)
def testNormPoly(self): test_data = [ ("x + x", "2 * x"), ("x + 2 * x", "3 * x"), ("(1 / 2) * x + (1 / 3) * x", "5 / 6 * x"), ("x + y + x", "2 * x + y"), ("x + (-1) * x", "(0::real)"), ("x + (-1) * y + y", "x"), ("x + y + (-1) * x", "y"), ("(x + y) * (x + y)", "2 * (x * y) + x ^ (2::nat) + y ^ (2::nat)"), ("(x + y) * (x - y)", "x ^ (2::nat) + -1 * y ^ (2::nat)"), ("x ^ (3::real)", "x ^ (3::nat)"), ("(2::real) ^ (3::nat)", "(8::real)"), ("(2::real) ^ (-(1::real))", "1 / 2"), ("(9::real) ^ (1 / 2)", "(3::real)"), ("(9::real) ^ (1 / 3)", "(3::real) ^ (2 / 3)"), ("(3::real) ^ (4 / 3)", "3 * (3::real) ^ (1 / 3)"), ("(2::real) ^ -(1 / 2)", "1 / 2 * 2 ^ (1 / 2)"), ("(1 / 4) ^ (1 / 2)", "1 / 2"), ("((3::real) ^ (1 / 2) * 3 ^ (1 / 2))", "(3::real)"), ("(2::real) * (-((1/2) * -(3 ^ (1/2))) + 1)", "2 + (3::real) ^ (1 / 2)"), ("(0::real) ^ (6::nat)", "(0::real)"), ] vars = {'x': 'real', 'y': 'real'} for expr, res in test_data: test_conv(self, 'transcendentals', auto.auto_conv(), vars=vars, t=expr, t_res=res)
def get_proof_term(self, t): if not is_real_ineq(t): return refl(t) pt_refl = refl(t).on_rhs(real_norm_comparison()) left_expr = pt_refl.rhs.arg1 summands = integer.strip_plus(left_expr) first = summands[0] if not left_expr.is_plus() or not first.is_constant(): return pt_refl first_value = real_eval(first) if pt_refl.rhs.is_greater_eq(): pt_th = ProofTerm.theorem("real_sub_both_sides_geq") elif pt_refl.rhs.is_greater(): pt_th = ProofTerm.theorem("real_sub_both_sides_gt") elif pt_refl.rhs.is_less_eq(): pt_th = ProofTerm.theorem("real_sub_both_sides_leq") elif pt_refl.rhs.is_less(): pt_th = ProofTerm.theorem("real_sub_both_sides_le") else: raise NotImplementedError(str(t)) inst = matcher.first_order_match(pt_th.lhs, pt_refl.rhs, inst=matcher.Inst(c=first)) return pt_refl.transitive(pt_th.substitution(inst=inst)).on_rhs( auto.auto_conv())
def get_proof_term(self, t): pt = refl(t).on_rhs(binop_conv(to_exponent_form())) if pt.rhs.arg1.is_comb('exp', 1) and pt.rhs.arg.is_comb('exp', 1): # Both sides are exponentials return pt.on_rhs(rewr_conv('real_exp_add', sym=True), arg_conv(auto.auto_conv(self.conds))) elif pt.rhs.arg1.is_nat_power() and pt.rhs.arg.is_nat_power(): # Both sides are natural number powers, simply add return pt.on_rhs(rewr_conv('real_pow_add', sym=True), arg_conv(nat.nat_conv())) else: # First check that x > 0 can be proved. If not, just return # without change. x = pt.rhs.arg1.arg1 try: x_gt_0 = auto.solve(x > 0, self.conds) except TacticException: return refl(t) # Convert both sides to real powers if pt.rhs.arg1.is_nat_power(): pt = pt.on_rhs(arg1_conv(rewr_conv('rpow_pow', sym=True))) if pt.rhs.arg.is_nat_power(): pt = pt.on_rhs(arg_conv(rewr_conv('rpow_pow', sym=True))) pt = pt.on_rhs(rewr_conv('rpow_add', sym=True, conds=[x_gt_0]), arg_conv(real_eval_conv())) # Simplify back to nat if possible if pt.rhs.arg.is_comb('of_nat', 1): pt = pt.on_rhs(rewr_conv('rpow_pow'), arg_conv(rewr_conv('nat_of_nat_def', sym=True))) return pt.on_rhs(from_exponent_form())
def testNormRealDerivative(self): test_data = [ # Differentiable everywhere ("real_derivative (%x. x) x", [], "(1::real)"), ("real_derivative (%x. 3) x", [], "(0::real)"), ("real_derivative (%x. 3 * x) x", [], "(3::real)"), ("real_derivative (%x. x ^ (2::nat)) x", [], "2 * x"), ("real_derivative (%x. x ^ (3::nat)) x", [], "3 * x ^ (2::nat)"), ("real_derivative (%x. (x + 1) ^ (3::nat)) x", [], "3 + 6 * x + 3 * x ^ (2::nat)"), ("real_derivative (%x. exp x) x", [], "exp x"), ("real_derivative (%x. exp (x ^ (2::nat))) x", [], "2 * (exp (x ^ (2::nat)) * x)"), # ("real_derivative (%x. exp (exp x)) x", [], "exp (x + exp x)"), ("real_derivative (%x. sin x) x", [], "cos x"), ("real_derivative (%x. cos x) x", [], "-1 * sin x"), ("real_derivative (%x. sin x * cos x) x", [], "(cos x) ^ (2::nat) + -1 * (sin x) ^ (2::nat)"), # Differentiable with conditions ("real_derivative (%x. 1 / x) x", ["x Mem real_open_interval 0 1"], "-1 * x ^ -(2::real)"), ("real_derivative (%x. 1 / (x ^ (2::nat) + 1)) x", ["x Mem real_open_interval (-1) 1"], "-2 * (x * (1 + 2 * x ^ (2::nat) + x ^ (4::nat)) ^ -(1::real))"), ("real_derivative (%x. log x) x", ["x Mem real_open_interval 0 1"], "x ^ -(1::real)"), ("real_derivative (%x. log (sin x)) x", ["x Mem real_open_interval 0 1"], "cos x * (sin x) ^ -(1::real)"), ("real_derivative (%x. sqrt x) x", ["x Mem real_open_interval 0 1"], "1 / 2 * x ^ -(1 / 2)"), ("real_derivative (%x. sqrt (x ^ (2::nat) + 1)) x", ["x Mem real_open_interval (-1) 1" ], "x * (1 + x ^ (2::nat)) ^ -(1 / 2)"), # Real power ("real_derivative (%x. x ^ (1 / 3)) x", ["x Mem real_open_interval 0 1"], "1 / 3 * x ^ -(2 / 3)"), ("real_derivative (%x. 2 ^ x) x", ["x Mem real_open_interval (-1) 1"], "log 2 * 2 ^ x"), ] vars = {'x': 'real'} context.set_context('interval_arith', vars=vars) for t, conds, res in test_data: conds_pt = [ ProofTerm.assume(parser.parse_term(cond)) for cond in conds ] cv = auto.auto_conv(conds_pt) test_conv(self, 'interval_arith', cv, vars=vars, t=t, t_res=res, assms=conds)
def get_proof_term(self, t): if not t.is_equals() and not t.is_compares() or t.arg1.get_type( ) != RealType: return refl(t) pt = refl(t) if t.is_equals(): pt1 = pt.on_rhs(rewr_conv('real_sub_0', sym=True), auto.auto_conv()) elif t.is_greater_eq(): pt1 = pt.on_rhs(rewr_conv('real_geq_sub'), auto.auto_conv()) elif t.is_greater(): pt1 = pt.on_rhs(rewr_conv('real_gt_sub'), auto.auto_conv()) elif t.is_less_eq(): pt1 = pt.on_rhs(rewr_conv('real_leq_sub'), auto.auto_conv()) elif t.is_less(): pt1 = pt.on_rhs(rewr_conv('real_le_sub'), auto.auto_conv()) else: raise ConvException(str(t)) summands = integer.strip_plus(pt1.rhs.arg1) first = summands[0] if first.is_var(): return pt1 elif first.is_number() and real_eval(first) > 0: return pt1 elif first.is_times() and real_eval(first.arg1) > 0: return pt1 lhs = pt1.rhs if lhs.is_equals(): return pt1.on_rhs(rewr_conv('real_eq_neg2', sym=True), auto.auto_conv()) elif lhs.is_greater_eq(): return pt1.on_rhs(rewr_conv('real_geq_leq'), auto.auto_conv()) elif lhs.is_greater(): return pt1.on_rhs(rewr_conv('real_gt_le'), auto.auto_conv()) elif lhs.is_less_eq(): return pt1.on_rhs(rewr_conv('real_leq_geq'), auto.auto_conv()) elif lhs.is_less(): return pt1.on_rhs(rewr_conv('real_le_gt'), auto.auto_conv())
def testNormTranscendental(self): test_data = [ ("sin 0", "(0::real)"), ("sin (1 / 6 * pi)", "1 / 2"), ("cos 0", "(1::real)"), ("cos (1 / 6 * pi)", "1 / 2 * 3 ^ (1 / 2)"), ("exp 0", "(1::real)"), ("cos (pi / 4)", "1 / 2 * 2 ^ (1 / 2)"), ("sin (13 / 6 * pi)", "1 / 2"), ("sin (7 / 6 * pi)", "-(1 / 2)"), ("sin (5 / 6 * pi)", "1 / 2"), ("cos (7 / 6 * pi)", "-(1 / 2) * 3 ^ (1 / 2)"), ("cos (-pi / 2)", "(0::real)"), ("log 1", "(0::real)"), ("log (exp 2)", "(2::real)"), ("log 9", "2 * log 3"), ("log (9 / 10)", "-1 * log 2 + 2 * log 3 + -1 * log 5"), ("log (1 / 2)", "-1 * log(2)"), ("(0::real) ^ (6::nat)", "(0::real)"), ] for t, res in test_data: test_conv(self, 'interval_arith', auto.auto_conv(), t=t, t_res=res)
def testNormRealIntegral(self): test_data = [ # Linearity and common integrals ("real_integral (real_closed_interval 0 1) (%x. 1)", "(1::real)"), ("real_integral (real_closed_interval 0 1) (%x. 2 * x)", "(1::real)"), ("real_integral (real_closed_interval 0 1) (%x. x + 1)", "3 / 2"), ("real_integral (real_closed_interval 0 1) (%x. x ^ (2::nat))", "1 / 3"), ("real_integral (real_closed_interval 0 1) (%x. exp x)", "-1 + exp 1"), ("real_integral (real_closed_interval 0 1) (%x. sin x)", "1 + -1 * cos 1"), ("real_integral (real_closed_interval 0 1) (%x. cos x)", "sin 1"), ("1/2 * (-2 * real_integral (real_closed_interval 0 (1/2)) (%x. exp x))", "1 + -1 * exp (1 / 2)"), # Normalize body ("real_integral (real_closed_interval 0 1) (%x. x ^ (2::nat) * x)", "1 / 4"), ("real_integral (real_closed_interval 0 1) (%x. x ^ (1 / 3) * (x ^ (1 / 2) + 1))", "57 / 44"), ("real_integral (real_closed_interval (exp (-1)) 1) (%x. abs (log x))", "-1 * real_integral (real_closed_interval (exp (-1)) 1) (%x. log x)" ), ("real_integral (real_closed_interval 0 (1 / 2 * pi)) (%x. 2 ^ (1 / 2) * cos x * (2 + -2 * sin x ^ (2::nat)) ^ (1 / 2))", "2 ^ (1 / 2) * real_integral (real_closed_interval 0 (1 / 2 * pi)) (%x. cos x * (2 + -2 * sin x ^ (2::nat)) ^ (1 / 2))" ) ] for expr, res in test_data: test_conv(self, 'interval_arith', auto.auto_conv(), t=expr, t_res=res)
def handle_leq_stage1(self, pts): if not pts: return None, None, None # ⊢ max(max(...(max(x_1, x_2), x_3)...), x_n-1), x_n) < 0 max_pos_pt = functools.reduce( lambda pt1, pt2: logic.apply_theorem("max_less_0", pt1, pt2), pts[1:], pts[0]) # ⊢ 0 < 2 two_pos_pt = ProofTerm("real_compare", Real(2) > Real(0)) # ⊢ max(...) / 2 < 0 max_divides_two_pos = logic.apply_theorem("real_neg_div_pos", max_pos_pt, two_pos_pt) # ⊢ 2 ≥ 1 two_larger_one = ProofTerm("real_compare", Real(2) >= Real(1)) # ⊢ max(...) ≤ max(...) / 2 less_half_pt = logic.apply_theorem("real_neg_divides_larger_1", two_larger_one, max_pos_pt) # ⊢ max(...) / 2 = -δ delta_2 = Var("δ_2", RealType) pt_delta_eq = ProofTerm.assume(Eq(less_half_pt.prop.arg, -delta_2)) # ⊢ δ > 0 delta_pos_pt = max_divides_two_pos.on_prop( rewr_conv("real_le_gt"), top_conv(replace_conv(pt_delta_eq)), auto.auto_conv()) # max(...) ≤ -δ less_half_pt_delta = less_half_pt.on_prop( arg_conv(replace_conv(pt_delta_eq))) return less_half_pt_delta, delta_pos_pt, pt_delta_eq
def norm_mem_interval(pt): """Normalize membership in interval.""" return pt.on_prop(arg_conv(binop_conv(auto.auto_conv())))