diff --git a/Holmakefile b/Holmakefile index 53d736c31728464cf0c1465cddbd548cc0423458..65724144f1e9f0f58fec43e2a4c2f83b2e539272 100644 --- a/Holmakefile +++ b/Holmakefile @@ -1 +1 @@ -INCLUDES = $(FLOVERDIR)/hol4/semantics $(HOLDIR)/examples/algebra/polynomial +INCLUDES = $(FLOVERDIR)/hol4 $(FLOVERDIR)/hol4/semantics $(HOLDIR)/examples/algebra/polynomial diff --git a/approxPolyScript.sml b/approxPolyScript.sml new file mode 100644 index 0000000000000000000000000000000000000000..554978498aaafc6e0bfc2e729a88c9973a4895e4 --- /dev/null +++ b/approxPolyScript.sml @@ -0,0 +1,497 @@ +(** **) +open realTheory realLib RealArith transcTheory; +open realPolyTheory realPolyProofsTheory mcLaurinApproxTheory transcLangTheory; +open preamble; + +val _ = new_theory "approxPoly"; + +(** functions computing the McLaurin series for transcendental functions **) +Definition expPoly_def: + expPoly 0 = [] ∧ (* x pow 0 * inv FACT 0 *) + expPoly (SUC n) = (expPoly n) ++ [inv (&FACT n)] +End + +Definition cosPoly_def: + cosPoly 0 = [] ∧ + cosPoly (SUC n) = + if (EVEN n) then + cosPoly n ++ [-1 pow (n DIV 2) * inv (&FACT n)] + else cosPoly n ++ [0] +End + +Definition sinPoly_def: + sinPoly 0 = [] ∧ + sinPoly (SUC n) = + if (EVEN n) then sinPoly n ++ [0] + else sinPoly n ++ [-1 pow ((n - 1) DIV 2) * inv (&FACT n)] +End + +(** Define an approximation function that translates transcendental functions into + polynomials **) +(* Error for exp if upper bound ≤ 1/2 *) +Definition expErrSmall_def: + expErrSmall approxSteps = inv (&FACT approxSteps * 2 pow (approxSteps - 1)) +End + +(* General, more coarse bound *) +Definition expErrBig_def: + expErrBig n approxSteps = + 2 pow n * &n pow approxSteps * inv (&FACT approxSteps * 2 pow approxSteps) +End + +Definition cosErr_def: + cosErr iv approxSteps = (max (abs (FST iv)) (abs (SND iv))) pow approxSteps * (* ^(cosErr_EVAL_THM |> concl |> rhs)*) + inv (&FACT approxSteps) +End + +Definition sinErr_def: + sinErr iv approxSteps = (max (abs (FST iv)) (abs (SND iv))) pow approxSteps * (* ^(sinErr_EVAL_THM |> concl |> rhs) *) + inv (&FACT approxSteps) +End + +Definition internalSteps_def: + internalSteps:num = 40 +End + +(** + Approximate a function described by transcLang with a real-number polynomial, + also returns the approximation error +**) +Definition approxPoly_def: + approxPoly (transc:trFun) (iv:real#real) approxSteps :(poly#real) option = + case transc of + | Exp => + if iv = (0, inv 2) then + SOME (expPoly approxSteps, expErrSmall approxSteps) + else if FST iv = 0 then + SOME (expPoly approxSteps, expErrBig (clg (SND iv * 2)) approxSteps) + else NONE + | Sin => SOME (sinPoly approxSteps, sinErr iv approxSteps) + | Cos => SOME (cosPoly approxSteps, cosErr iv approxSteps) +End + +(** Simple properties of polynomials used for proofs later **) +Theorem expPoly_LENGTH: + LENGTH (expPoly n) = n +Proof + Induct_on ‘n’ >> gs[expPoly_def] +QED + +Theorem cosPoly_LENGTH: + LENGTH (cosPoly n) = n +Proof + Induct_on ‘n’ >> gs[cosPoly_def] + >> cond_cases_tac >> gs[] +QED + +Theorem sinPoly_LENGTH: + LENGTH (sinPoly n) = n +Proof + Induct_on ‘n’ >> gs[sinPoly_def] + >> cond_cases_tac >> gs[] +QED + +(** The polynomials compute the sum part of the McLaurin series **) +Theorem exp_sum_to_poly: + ∀ n x. evalPoly (expPoly n) x = sum (0,n) (λ m. x pow m / &FACT m) +Proof + Induct_on ‘n’ >> gs[expPoly_def, evalPoly_def, sum] + >> rpt strip_tac >> gs[evalPoly_app, evalPoly_def, expPoly_LENGTH] +QED + +Theorem cos_sum_to_poly: + ∀ n x. evalPoly (cosPoly n) x = + sum(0,n) + (λm. + (&FACT m)â»Â¹ * x pow m * + if EVEN m then cos 0 * -1 pow (m DIV 2) + else sin 0 * -1 pow ((SUC m) DIV 2)) +Proof + Induct_on ‘n’ >> gs[sum, evalPoly_def, cosPoly_def] + >> cond_cases_tac + >> gs[evalPoly_app, COS_0, SIN_0, evalPoly_def, cosPoly_LENGTH] +QED + +Theorem sin_sum_to_poly: + ∀ n x. + evalPoly (sinPoly n) x = + sum(0,n) + (λm. + (&FACT m)â»Â¹ * x pow m * + if EVEN m then sin 0 * -1 pow (m DIV 2) + else cos 0 * -1 pow ((m - 1) DIV 2)) +Proof + Induct_on ‘n’ >> gs[sum, evalPoly_def, sinPoly_def] + >> cond_cases_tac + >> gs[evalPoly_app, SIN_0, COS_0, evalPoly_def, sinPoly_LENGTH] +QED + +(** Theorems about the remainder term of the McLaurin series **) +Theorem exp_remainder_bounded_small: + ∀ n x t. + 0 < n ∧ abs t ≤ abs x ∧ 0 ≤ x ∧ + t ≤ inv 2 ∧ x ≤ inv 2 ⇒ + abs (exp t / &FACT n * x pow n) ≤ inv (&FACT n * 2 pow (n - 1)) +Proof + rpt strip_tac >> rewrite_tac[real_div, abs] + >> qmatch_goalsub_abbrev_tac ‘(if 0 ≤ exp_bound then _ else _) ≤ _’ + >> ‘0 ≤ exp_bound’ + by ( + unabbrev_all_tac + >> rpt (irule REAL_LE_MUL >> gs[POW_POS, EXP_POS_LE])) + >> simp[] >> unabbrev_all_tac + >> irule REAL_LE_TRANS + >> qexists_tac ‘(1 + 2 * inv 2) * (inv (&FACT n) * x pow n)’ + >> conj_tac + >- ( + rewrite_tac[GSYM REAL_MUL_ASSOC] + >> irule REAL_LE_RMUL_IMP + >> conj_tac + >- ( + Cases_on ‘0 ≤ t’ + >- ( + irule REAL_LE_TRANS + >> qexists_tac ‘1 + 2 * t’ >> conj_tac + >- (irule REAL_EXP_BOUND_LEMMA >> gs[]) + >> real_tac) + >> ‘t = - (- t)’ by real_tac + >> pop_assum $ once_rewrite_tac o single + >> once_rewrite_tac[EXP_NEG] + >> ‘- (inv 2) ≤ -t’ by real_tac + >> irule REAL_LE_TRANS + >> qexists_tac ‘inv (exp (- (inv 2)))’ + >> conj_tac + >- (irule REAL_INV_LE_ANTIMONO_IMPR >> gs[EXP_POS_LT, EXP_MONO_LE]) + >> rewrite_tac[EXP_NEG, REAL_INV_INV] + >> irule REAL_EXP_BOUND_LEMMA >> gs[]) + >> irule REAL_LE_MUL >> gs[REAL_LE_INV, POW_POS]) + >> ‘1 + 2 * inv 2 = 2’ by gs[] + >> pop_assum $ rewrite_tac o single + >> rewrite_tac[GSYM REAL_MUL_ASSOC, REAL_INV_MUL'] + >> irule REAL_LE_TRANS + >> qexists_tac ‘2 * (inv (&FACT n) * inv 2 pow n)’ + >> conj_tac + >- ( + irule REAL_LE_LMUL_IMP >> reverse conj_tac >- gs[] + >> irule REAL_LE_LMUL_IMP >> reverse conj_tac >- gs[REAL_LE_INV] + >> irule POW_LE >> gs[]) + >> Cases_on ‘n’ >- gs[] + >> rewrite_tac[pow] + >> gs[REAL_INV_MUL'] +QED + +Theorem exp_remainder_bounded_big: + ∀ n m x t. + 0 < n ∧ abs t ≤ abs x ∧ EVEN n ∧ + abs x ≤ &m * (inv 2) ∧ + t ≤ &m * (inv 2) ⇒ + abs (exp t / &FACT n * x pow n) ≤ 2 pow m * &m pow n * (inv (&FACT n * 2 pow n)) +Proof + rpt strip_tac >> rewrite_tac[real_div, abs] + >> qmatch_goalsub_abbrev_tac ‘(if 0 ≤ exp_bound then _ else _) ≤ _’ + >> ‘0 ≤ exp_bound’ + by ( + unabbrev_all_tac + >> rpt (irule REAL_LE_MUL >> gs[POW_POS, EXP_POS_LE])) + >> pop_assum $ rewrite_tac o single + >> unabbrev_all_tac + >> irule REAL_LE_TRANS + >> qexists_tac ‘exp (&m * inv 2) * (inv (&FACT n) * x pow n)’ + >> conj_tac + >- ( + rewrite_tac[GSYM REAL_MUL_ASSOC] + >> irule REAL_LE_RMUL_IMP + >> conj_tac + >- gs[EXP_MONO_LE] + >> irule REAL_LE_MUL >> gs[REAL_LE_INV, POW_POS]) + >> rewrite_tac[EXP_N] + >> qmatch_goalsub_abbrev_tac ‘_ * cst_err ≤ _’ + >> irule REAL_LE_TRANS + >> qexists_tac ‘(1 + 2 * inv 2) pow m * cst_err’ + >> conj_tac + >- ( + irule REAL_LE_RMUL_IMP + >> conj_tac + >- ( + irule POW_LE >> rewrite_tac[EXP_POS_LE] + >> irule REAL_EXP_BOUND_LEMMA >> gs[]) + >> unabbrev_all_tac + >> irule REAL_LE_MUL >> gs[REAL_LE_INV, POW_POS]) + >> ‘1 + 2 * inv 2 = 2’ by gs[] + >> pop_assum $ rewrite_tac o single + >> unabbrev_all_tac + >> rewrite_tac[REAL_MUL_ASSOC] + >> qmatch_goalsub_abbrev_tac ‘cst_err * x pow n’ + >> irule REAL_LE_TRANS + >> qexists_tac ‘cst_err * (&m * inv 2) pow n’ >> conj_tac + >- ( + irule REAL_LE_LMUL_IMP >> conj_tac + >- (irule REAL_LE_TRANS >> qexists_tac ‘abs x pow n’ + >> gs[POW_LE, POW_ABS, ABS_LE]) + >> unabbrev_all_tac >> irule REAL_LE_MUL + >> gs[REAL_LE_INV, POW_POS]) + >> rewrite_tac [POW_MUL] + >> unabbrev_all_tac + >> qmatch_goalsub_abbrev_tac ‘curr_bound ≤ _’ + >> ‘curr_bound = 2 pow m * &m pow n * (inv (&FACT n * 2 pow n))’ + by (unabbrev_all_tac >> gs[REAL_POW_INV]) + >> pop_assum $ rewrite_tac o single + >> unabbrev_all_tac >> gs[] +QED + +Theorem sin_even_remainder_bounded: + ∀ n. + EVEN n ⇒ + inv (&FACT n) * sin t * x pow n * -1 pow (n DIV 2) ≤ + abs(inv (&FACT n) * x pow n * -1 pow (n DIV 2)) +Proof + rpt strip_tac + >> ‘inv (&FACT n) * x pow n * -1 pow (n DIV 2) = inv (&FACT n) * 1 * x pow n * -1 pow (n DIV 2)’ + by real_tac + >> pop_assum $ rewrite_tac o single + >> rewrite_tac[GSYM REAL_MUL_ASSOC] + >> once_rewrite_tac[REAL_ABS_MUL] + >> ‘0 ≤ inv (&FACT n)’ + by gs[REAL_LE_INV] + >> ‘abs (inv (&FACT n)) = inv (&FACT n)’ by gs[abs] + >> pop_assum $ rewrite_tac o single + >> irule REAL_LE_LMUL_IMP + >> reverse conj_tac >- gs[] + >> once_rewrite_tac[REAL_ABS_MUL] + >> Cases_on ‘0 ≤ x pow n * -1 pow (n DIV 2)’ + >- ( + ‘abs (x pow n * -1 pow (n DIV 2)) = x pow n * -1 pow (n DIV 2)’ by gs[abs] + >> pop_assum $ rewrite_tac o single + >> irule REAL_LE_RMUL_IMP >> gs[SIN_BOUNDS]) + >> ‘x pow n * -1 pow (n DIV 2) < 0’ by real_tac + >> irule REAL_LE_TRANS + >> qexists_tac ‘-1 * (x pow n * -1 pow (n DIV 2))’ + >> conj_tac + >- ( + once_rewrite_tac [REAL_MUL_COMM] + >> drule REAL_LE_LMUL_NEG + >> disch_then $ qspecl_then [‘sin t’, ‘-1’] $ rewrite_tac o single + >> gs[SIN_BOUNDS]) + >> ‘∃ y. x pow n * -1 pow (n DIV 2) = -1 * y ∧ 0 ≤ y’ + by (qexists_tac ‘-1 * x pow n * -1 pow (n DIV 2)’ + >> real_tac) + >> qpat_x_assum `_ = -1 * y` $ rewrite_tac o single + >> gs[ABS_LE] +QED + +Theorem cos_even_remainder_bounded: + ∀ n. + EVEN n ⇒ + inv (&FACT n) * cos t * x pow n * -1 pow (n DIV 2) ≤ + abs(inv (&FACT n) * x pow n * -1 pow (n DIV 2)) +Proof + rpt strip_tac + >> ‘inv (&FACT n) * x pow n * -1 pow (n DIV 2) = inv (&FACT n) * 1 * x pow n * -1 pow (n DIV 2)’ + by real_tac + >> pop_assum $ rewrite_tac o single + >> rewrite_tac[GSYM REAL_MUL_ASSOC] + >> once_rewrite_tac[REAL_ABS_MUL] + >> ‘0 ≤ inv (&FACT n)’ + by gs[REAL_LE_INV] + >> ‘abs (inv (&FACT n)) = inv (&FACT n)’ by gs[abs] + >> pop_assum $ rewrite_tac o single + >> irule REAL_LE_LMUL_IMP + >> reverse conj_tac >- gs[] + >> once_rewrite_tac[REAL_ABS_MUL] + >> Cases_on ‘0 ≤ x pow n * -1 pow (n DIV 2)’ + >- ( + ‘abs (x pow n * -1 pow (n DIV 2)) = x pow n * -1 pow (n DIV 2)’ by gs[abs] + >> pop_assum $ rewrite_tac o single + >> irule REAL_LE_RMUL_IMP >> gs[COS_BOUNDS]) + >> ‘x pow n * -1 pow (n DIV 2) < 0’ by real_tac + >> irule REAL_LE_TRANS + >> qexists_tac ‘-1 * (x pow n * -1 pow (n DIV 2))’ + >> conj_tac + >- ( + once_rewrite_tac [REAL_MUL_COMM] + >> drule REAL_LE_LMUL_NEG + >> disch_then $ qspecl_then [‘cos t’, ‘-1’] $ rewrite_tac o single + >> gs[COS_BOUNDS]) + >> ‘∃ y. x pow n * -1 pow (n DIV 2) = -1 * y ∧ 0 ≤ y’ + by (qexists_tac ‘-1 * x pow n * -1 pow (n DIV 2)’ + >> real_tac) + >> qpat_x_assum `_ = -1 * y` $ rewrite_tac o single + >> gs[ABS_LE] +QED + +Definition approxPolySideCond_def: + approxPolySideCond approxSteps = + (0 < approxSteps ∧ EVEN approxSteps ∧ EVEN (approxSteps DIV 2)) +End + +Theorem approxPoly_soundness: + ∀ transc iv approxSteps p err. + approxPolySideCond approxSteps ∧ + approxPoly transc iv approxSteps = SOME (p, err) ⇒ + ∀ x. + FST iv ≤ x ∧ x ≤ SND iv ⇒ + abs (getFun transc x - evalPoly p x) ≤ err +Proof + Cases_on ‘transc’ >> gs[approxPoly_def] + >> rpt strip_tac >> gs[approxPolySideCond_def] + (* exp function *) + >- ( + gs[interp_def, getFun_def] + >> Cases_on ‘iv = (0, inv 2)’ >> gs[] + (* exp function, 0 to 1/2 *) + >- ( + qspecl_then [‘x’, ‘approxSteps’] strip_assume_tac MCLAURIN_EXP_LE + >> pop_assum $ rewrite_tac o single + >> rpt VAR_EQ_TAC + >> rewrite_tac[exp_sum_to_poly] + >> qmatch_goalsub_abbrev_tac ‘abs (exp_taylor + taylor_rem - exp_taylor) ≤ _’ + >> ‘exp_taylor + taylor_rem - exp_taylor = taylor_rem’ by real_tac + >> pop_assum $ rewrite_tac o single + >> unabbrev_all_tac + >> ‘expErrSmall approxSteps = inv (&FACT approxSteps * 2 pow (approxSteps - 1))’ + by EVAL_TAC + >> rename1 ‘exp t’ + >> qspecl_then [‘approxSteps’, ‘x’,‘t’] mp_tac exp_remainder_bounded_small + >> impl_tac >> gs[] + >> real_tac) + (* exp function, 0 to 1 *) + >> ‘1 ≠inv 2’ + by (once_rewrite_tac [GSYM REAL_INV1] + >> CCONTR_TAC + >> pop_assum $ mp_tac o SIMP_RULE std_ss [] + >> rewrite_tac[REAL_INV_INJ] >> real_tac) + >> rpt VAR_EQ_TAC + >> rewrite_tac[GSYM poly_compat, eval_simps] + >> pop_assum $ rewrite_tac o single + >> rewrite_tac[exp_sum_to_poly] + >> qspecl_then [‘x’, ‘approxSteps’] strip_assume_tac MCLAURIN_EXP_LE + >> pop_assum $ rewrite_tac o single + >> qmatch_goalsub_abbrev_tac ‘abs (exp_taylor + taylor_rem - exp_taylor) ≤ _’ + >> ‘exp_taylor + taylor_rem - exp_taylor = taylor_rem’ by real_tac + >> pop_assum $ rewrite_tac o single + >> unabbrev_all_tac + >> qmatch_goalsub_abbrev_tac ‘expErrBig n _’ + >> ‘expErrBig n approxSteps = 2 pow n * &n pow approxSteps * inv (&FACT approxSteps * 2 pow approxSteps)’ + by (rewrite_tac[] >> EVAL_TAC) + >> pop_assum $ rewrite_tac o single + >> qspecl_then [‘approxSteps’, ‘n’, ‘x’,‘t’] mp_tac exp_remainder_bounded_big + >> impl_tac + >- ( + rpt conj_tac >> TRY (gs[] >> real_tac >> NO_TAC) + >> ‘2 * x ≤ &n’ + by (unabbrev_all_tac >> cond_cases_tac + >> gs[] + >- ( + ‘SND iv = 0’ by real_tac + >> pop_assum $ rewrite_tac o single + >> ‘x = 0’ by real_tac + >> pop_assum $ rewrite_tac o single + >> gs[REAL_MUL_RZERO, REAL_DIV_LZERO, EVAL “flr 0â€]) + >- ( + pop_assum $ rewrite_tac o single o GSYM + >> real_tac) + >> irule REAL_LE_TRANS + >> qexists_tac ‘&clg (2 * x)’ + >> gs[LE_NUM_CEILING] + >> cond_cases_tac >> gs[] + >> rewrite_tac[GSYM REAL_OF_NUM_LE] + >> irule REAL_LE_TRANS >> qexists_tac ‘&flr (2 * SND iv)’ + >> conj_tac + >> gs[REAL_OF_NUM_LE] + >> irule NUM_FLOOR_MONO + >> rpt conj_tac >> real_tac) + >- gs[abs] + >> irule REAL_LE_TRANS >> qexists_tac ‘abs t’ + >> conj_tac >- gs[ABS_LE] + >> irule REAL_LE_TRANS >> qexists_tac ‘abs x’ + >> gs[abs]) + >> rewrite_tac[]) + (* sin *) + >- ( + gs[interp_def, getFun_def] >> rpt VAR_EQ_TAC + >> qspecl_then [‘x’, ‘approxSteps’] strip_assume_tac MCLAURIN_SIN_LE + >> gs[] + >> pop_assum $ rewrite_tac o single + >> gs[sin_sum_to_poly] + >> qmatch_goalsub_abbrev_tac ‘abs (sin_taylor + taylor_rem - sin_taylor) ≤ _’ + >> ‘sin_taylor + taylor_rem - sin_taylor = taylor_rem’ by real_tac + >> pop_assum $ rewrite_tac o single + >> unabbrev_all_tac + >> ‘inv (&FACT approxSteps) * sin t * x pow approxSteps * -1 pow (approxSteps DIV 2) = + (sin t * ((x pow approxSteps) * inv (&FACT approxSteps) * -1 pow (approxSteps DIV 2)))’ + by real_tac + >> ‘-(x pow approxSteps) * inv (&FACT approxSteps) * sin t = + -(sin t * ((x pow approxSteps) * inv (&FACT approxSteps)))’ + by real_tac + >> rewrite_tac [] + >> ntac 2 $ pop_assum $ rewrite_tac o single + >> rewrite_tac[GSYM REAL_MUL_ASSOC] + >> qmatch_goalsub_abbrev_tac ‘_ * err_sin_concr’ + >> rewrite_tac [ABS_NEG, Once ABS_MUL] + >> irule REAL_LE_TRANS + >> qexists_tac ‘ 1 * abs err_sin_concr’ >> conj_tac + >- (irule REAL_LE_RMUL_IMP >> unabbrev_all_tac >> gs[SIN_BOUND, ABS_POS]) + >> rewrite_tac [REAL_MUL_LID, sinErr_def, ABS_MUL] + >> ‘abs err_sin_concr = err_sin_concr’ + by (unabbrev_all_tac + >> rewrite_tac[ABS_REFL] + >> irule REAL_LE_MUL >> conj_tac + >> gs[REAL_POW_GE0] + >> irule REAL_LE_MUL >> gs[REAL_POS, REAL_POW_GE0]) + >> pop_assum $ rewrite_tac o single + >> unabbrev_all_tac + >> rewrite_tac [sinErr_def] + >> imp_res_tac EVEN_ODD_EXISTS >> gs[POW_MINUS1] + >> irule REAL_LE_LMUL_IMP >> gs[GSYM POW_ABS] + >> irule REAL_LE_TRANS + >> qexists_tac ‘abs (x pow (2 * m))’ >> gs[ABS_LE, GSYM POW_ABS] + >> irule POW_LE >> gs[ABS_POS] + >> irule RealSimpsTheory.maxAbs >> gs[]) + (* cos function *) + >- ( + gs[interp_def, getFun_def] >> rpt VAR_EQ_TAC + >> qspecl_then [‘x’, ‘approxSteps’] strip_assume_tac MCLAURIN_COS_LE + >> gs[] + >> pop_assum $ rewrite_tac o single + >> gs[cos_sum_to_poly] + >> qmatch_goalsub_abbrev_tac ‘abs (cos_taylor + taylor_rem - cos_taylor) ≤ _’ + >> ‘cos_taylor + taylor_rem - cos_taylor = taylor_rem’ by real_tac + >> pop_assum $ rewrite_tac o single + >> unabbrev_all_tac + >> ‘(x pow approxSteps) * cos t * inv (&FACT approxSteps) = + (cos t * ((x pow approxSteps) * inv (&FACT approxSteps)))’ + by real_tac + >> ‘-(x pow approxSteps) * cos t * inv (&FACT approxSteps) = + -(cos t * ((x pow approxSteps) * inv (&FACT approxSteps)))’ + by real_tac + >> rewrite_tac [] + >> ntac 2 $ pop_assum $ rewrite_tac o single + >> rewrite_tac [GSYM REAL_MUL_ASSOC] + >> qmatch_goalsub_abbrev_tac ‘abs (cos _ * err_cos_concr)’ + >> irule REAL_LE_TRANS + >> qexists_tac ‘ 1 * abs err_cos_concr’ >> conj_tac + >- (rewrite_tac[ABS_MUL] >> irule REAL_LE_RMUL_IMP >> unabbrev_all_tac >> gs[COS_BOUND, ABS_POS]) + >> rewrite_tac[REAL_MUL_LID] + >> ‘abs err_cos_concr = err_cos_concr’ + by (unabbrev_all_tac + >> rewrite_tac[ABS_REFL] + >> irule REAL_LE_MUL >> conj_tac + >- (irule REAL_LE_INV >> gs[REAL_POS]) + >> irule REAL_LE_MUL >> conj_tac + >> gs[REAL_POW_GE0]) + >> pop_assum $ rewrite_tac o single + >> unabbrev_all_tac + >> rewrite_tac [cosErr_def] + >> imp_res_tac EVEN_ODD_EXISTS >> gs[POW_MINUS1] + >> irule REAL_LE_LMUL_IMP >> gs[GSYM POW_ABS] + >> irule REAL_LE_TRANS + >> qexists_tac ‘abs (x pow (2 * m))’ >> gs[ABS_LE, GSYM POW_ABS] + >> irule POW_LE >> gs[ABS_POS] + >> irule RealSimpsTheory.maxAbs >> gs[]) + (* Tan function *) + >- ( cheat ) + (* Sqrt function *) + >> cheat +QED + +val _ = export_theory(); diff --git a/checkerScript.sml b/checkerScript.sml index c60c734de4f76d012eb07c36725bda8185522a3e..5fc8f1a87a716b1c7d0f61c3a48c24f43227ff25 100644 --- a/checkerScript.sml +++ b/checkerScript.sml @@ -10,120 +10,6 @@ open preamble; val _ = new_theory "checker"; -Definition approx_steps_def[simp]: - approx_steps:num = 14 -End - -Theorem exp_err_small_EVAL_THM = EVAL “inv (&FACT approx_steps * 2 pow (approx_steps - 1))†-Theorem exp_err_big_EVAL_THM = EVAL “ inv (&FACT approx_steps * 2 pow approx_steps)†-Theorem exp_poly_cst_EVAL_THM = EVAL “exp_poly approx_steps†- -Definition exp_err_small_def: - exp_err_small approxSteps = (* ^(exp_err_small_EVAL_THM |> concl |> rhs) *) - inv (&FACT approxSteps * 2 pow (approxSteps - 1)) -End - -Definition exp_err_big_def: - exp_err_big n approxSteps = 2 pow n * &n pow approxSteps * (* ^(exp_err_big_EVAL_THM |> rhs o concl)*) - inv (&FACT approxSteps * 2 pow approxSteps) -End - -Definition exp_poly_cst: - exp_poly_cst = ^(exp_poly_cst_EVAL_THM |> concl |> rhs) -End - -Triviality one_inv_one: - 1 * inv 1 = 1 -Proof - gs[REAL_MUL_RINV] -QED - -Triviality mul_neg_one: - -1 * x = - x:real -Proof - real_tac -QED - -(** Still needs to be multiplied with x pow n **) -Theorem cos_err_EVAL_THM = EVAL “inv (&FACT approx_steps)†-Theorem cos_poly_cst_EVAL_THM = EVAL “cos_poly approx_steps†|> SIMP_RULE std_ss [one_inv_one, REAL_MUL_LID, mul_neg_one] - -Definition cos_err_def: - cos_err iv approxSteps = (max (abs (FST iv)) (abs (SND iv))) pow approxSteps * (* ^(cos_err_EVAL_THM |> concl |> rhs)*) - inv (&FACT approxSteps) -End - -Definition cos_poly_cst_def: - cos_poly_cst = ^(cos_poly_cst_EVAL_THM |> concl |> rhs) -End - -Theorem sin_err_EVAL_THM = EVAL “inv (&FACT approx_steps)†-Theorem sin_poly_cst_EVAL_THM = EVAL “sin_poly approx_steps†|> SIMP_RULE std_ss [one_inv_one, REAL_MUL_LID, mul_neg_one] - -Definition sin_err_def: - sin_err iv approxSteps = (max (abs (FST iv)) (abs (SND iv))) pow approxSteps * (* ^(sin_err_EVAL_THM |> concl |> rhs) *) - inv (&FACT approxSteps) -End - -Definition sin_poly_cst_def: - sin_poly_cst = ^(sin_poly_cst_EVAL_THM |> concl |> rhs) -End - -Definition internalSteps_def: - internalSteps:num = 40 -End - -Definition ubTransc_def: - ubTransc tr ub = - if tr = "exp" then - let expPoly = exp_poly internalSteps in - evalPoly expPoly ub + exp_err_big (clg (ub * 2)) internalSteps - else if tr = "cos" ∨ tr = "sin" then 1 - else 0 -End - -(** - Approximate a function described by transcLang with a real-number polynomial, - also returns the approximation error -**) -Definition approxPoly_def: - approxPoly transc (iv:real#real) approxSteps :(poly#real) option = - case transc of - | Fun tr Var => - if tr = "exp" then - if iv = (0, 1 * inv 2) then - SOME (exp_poly approxSteps, exp_err_small approxSteps) - else if FST iv = 0 then SOME (exp_poly approxSteps, exp_err_big (clg (SND iv * 2)) approxSteps) - else NONE - else if tr = "cos" then - SOME (cos_poly approxSteps, cos_err iv approxSteps) - else if tr = "sin" then - SOME (sin_poly approxSteps, sin_err iv approxSteps) - else NONE - | Add tr1 tr2 => - (case approxPoly tr1 iv approxSteps of - | NONE => NONE - | SOME (appr1, err1) => - case approxPoly tr2 iv approxSteps of - | NONE => NONE - | SOME (appr2, err2) => - SOME (appr1 +p appr2, err1 + err2)) - | Sub tr1 tr2 => - (case approxPoly tr1 iv approxSteps of - | NONE => NONE - | SOME (appr1, err1) => - case approxPoly tr2 iv approxSteps of - | NONE => NONE - | SOME (appr2, err2) => - SOME (appr1 -p appr2, err1 + err2)) - | Neg tr1 => - (case approxPoly tr1 iv approxSteps of - | NONE => NONE - | SOME (appr1, err1) => - SOME (--p appr1, err1)) - | _ => NONE -End - (** Checks that the zero intervals encoded in the certificate actually are all of the zeros of derivative of the difference between the approximated @@ -380,212 +266,6 @@ Proof Induct_on ‘hints’ >> gs[getExpHint_def, CaseEq"hint"] QED -Definition approxPolySideCond_def: - approxPolySideCond approxSteps = - (0 < approxSteps ∧ EVEN approxSteps ∧ EVEN (approxSteps DIV 2)) -End - -Theorem approxPoly_soundness: - ∀ transc iv approxSteps p err. - approxPolySideCond approxSteps ∧ - approxPoly transc iv approxSteps = SOME (p, err) ⇒ - ∀ x. - FST iv ≤ x ∧ x ≤ SND iv ⇒ - abs (interp transc x - evalPoly p x) ≤ err -Proof - ho_match_mp_tac approxPoly_ind - >> rpt strip_tac - >> qpat_x_assum ‘approxPoly _ _ _ = SOME _’ mp_tac - >> Cases_on ‘transc’ >> simp[Once approxPoly_def, CaseEq"transc", CaseEq"option", CaseEq"prod"] - >> rpt strip_tac >> gs[approxPolySideCond_def] - >- ( - ‘s = "exp" ∨ s = "cos" ∨ s = "sin"’ - by (every_case_tac >> gs[getExpHint_SOME_MEM]) - (* exp function *) - >- ( - gs[interp_def, getFun_def] - >> Cases_on ‘iv = (0, inv 2)’ >> gs[] - (* exp function, 0 to 1/2 *) - >- ( - qspecl_then [‘x’, ‘approxSteps’] strip_assume_tac MCLAURIN_EXP_LE - >> pop_assum $ rewrite_tac o single - >> rpt VAR_EQ_TAC - >> rewrite_tac[exp_sum_to_poly] - >> qmatch_goalsub_abbrev_tac ‘abs (exp_taylor + taylor_rem - exp_taylor) ≤ _’ - >> ‘exp_taylor + taylor_rem - exp_taylor = taylor_rem’ by real_tac - >> pop_assum $ rewrite_tac o single - >> unabbrev_all_tac - >> ‘exp_err_small approxSteps = inv (&FACT approxSteps * 2 pow (approxSteps - 1))’ by EVAL_TAC - >> rename1 ‘exp t’ - >> qspecl_then [‘approxSteps’, ‘x’,‘t’] mp_tac exp_remainder_bounded_small - >> impl_tac >> gs[] - >> real_tac) - (* exp function, 0 to 1 *) - >> ‘1 ≠inv 2’ - by (once_rewrite_tac [GSYM REAL_INV1] - >> CCONTR_TAC - >> pop_assum $ mp_tac o SIMP_RULE std_ss [] - >> rewrite_tac[REAL_INV_INJ] >> real_tac) - >> rpt VAR_EQ_TAC - >> rewrite_tac[GSYM poly_compat, eval_simps] - >> pop_assum $ rewrite_tac o single - >> rewrite_tac[exp_sum_to_poly] - >> qspecl_then [‘x’, ‘approxSteps’] strip_assume_tac MCLAURIN_EXP_LE - >> pop_assum $ rewrite_tac o single - >> qmatch_goalsub_abbrev_tac ‘abs (exp_taylor + taylor_rem - exp_taylor) ≤ _’ - >> ‘exp_taylor + taylor_rem - exp_taylor = taylor_rem’ by real_tac - >> pop_assum $ rewrite_tac o single - >> unabbrev_all_tac - >> qmatch_goalsub_abbrev_tac ‘exp_err_big n _’ - >> ‘exp_err_big n approxSteps = 2 pow n * &n pow approxSteps * inv (&FACT approxSteps * 2 pow approxSteps)’ - by (rewrite_tac[] >> EVAL_TAC) - >> pop_assum $ rewrite_tac o single - >> qspecl_then [‘approxSteps’, ‘n’, ‘x’,‘t’] mp_tac exp_remainder_bounded_big - >> impl_tac - >- ( - rpt conj_tac >> TRY (gs[] >> real_tac >> NO_TAC) - >> ‘2 *x ≤ &n’ - by (unabbrev_all_tac >> cond_cases_tac - >> gs[] - >- ( - ‘SND iv = 0’ by real_tac - >> pop_assum $ rewrite_tac o single - >> ‘x = 0’ by real_tac - >> pop_assum $ rewrite_tac o single - >> gs[REAL_MUL_RZERO, REAL_DIV_LZERO, EVAL “flr 0â€]) - >- ( - pop_assum $ rewrite_tac o single o GSYM - >> real_tac) - >> irule REAL_LE_TRANS - >> qexists_tac ‘&clg (2 * x)’ - >> gs[LE_NUM_CEILING] - >> cond_cases_tac >> gs[] - >> rewrite_tac[GSYM REAL_OF_NUM_LE] - >> irule REAL_LE_TRANS >> qexists_tac ‘&flr (2 * SND iv)’ - >> conj_tac - >> gs[REAL_OF_NUM_LE] - >> irule NUM_FLOOR_MONO - >> rpt conj_tac >> real_tac) - >- gs[] - >> irule REAL_LE_TRANS >> qexists_tac ‘abs t’ - >> conj_tac >- gs[ABS_LE] - >> irule REAL_LE_TRANS >> qexists_tac ‘abs x’ - >> gs[abs]) - >> rewrite_tac[]) - (* cos function *) - >- ( - gs[interp_def, getFun_def] >> rpt VAR_EQ_TAC - >> qspecl_then [‘x’, ‘approxSteps’] strip_assume_tac MCLAURIN_COS_LE - >> gs[] - >> pop_assum $ rewrite_tac o single - >> gs[cos_sum_to_poly] - >> qmatch_goalsub_abbrev_tac ‘abs (cos_taylor + taylor_rem - cos_taylor) ≤ _’ - >> ‘cos_taylor + taylor_rem - cos_taylor = taylor_rem’ by real_tac - >> pop_assum $ rewrite_tac o single - >> unabbrev_all_tac - >> ‘(x pow approxSteps) * cos t * inv (&FACT approxSteps) = - (cos t * ((x pow approxSteps) * inv (&FACT approxSteps)))’ - by real_tac - >> ‘-(x pow approxSteps) * cos t * inv (&FACT approxSteps) = - -(cos t * ((x pow approxSteps) * inv (&FACT approxSteps)))’ - by real_tac - >> rewrite_tac [] - >> ntac 2 $ pop_assum $ rewrite_tac o single - >> rewrite_tac [GSYM REAL_MUL_ASSOC] - >> qmatch_goalsub_abbrev_tac ‘abs (cos _ * err_cos_concr)’ - >> irule REAL_LE_TRANS - >> qexists_tac ‘ 1 * abs err_cos_concr’ >> conj_tac - >- (rewrite_tac[ABS_MUL] >> irule REAL_LE_RMUL_IMP >> unabbrev_all_tac >> gs[COS_BOUND, ABS_POS]) - >> rewrite_tac[REAL_MUL_LID] - >> ‘abs err_cos_concr = err_cos_concr’ - by (unabbrev_all_tac - >> rewrite_tac[ABS_REFL] - >> irule REAL_LE_MUL >> conj_tac - >- (irule REAL_LE_INV >> gs[REAL_POS]) - >> irule REAL_LE_MUL >> conj_tac - >> gs[REAL_POW_GE0]) - >> pop_assum $ rewrite_tac o single - >> unabbrev_all_tac - >> rewrite_tac [cos_err_def] - >> imp_res_tac EVEN_ODD_EXISTS >> gs[POW_MINUS1] - >> irule REAL_LE_LMUL_IMP >> gs[GSYM POW_ABS] - >> irule REAL_LE_TRANS - >> qexists_tac ‘abs (x pow (2 * m))’ >> gs[ABS_LE, GSYM POW_ABS] - >> irule POW_LE >> gs[ABS_POS] - >> irule RealSimpsTheory.maxAbs >> gs[]) - (* sin *) - >> gs[interp_def, getFun_def] >> rpt VAR_EQ_TAC - >> qspecl_then [‘x’, ‘approxSteps’] strip_assume_tac MCLAURIN_SIN_LE - >> gs[] - >> pop_assum $ rewrite_tac o single - >> gs[sin_sum_to_poly] - >> qmatch_goalsub_abbrev_tac ‘abs (sin_taylor + taylor_rem - sin_taylor) ≤ _’ - >> ‘sin_taylor + taylor_rem - sin_taylor = taylor_rem’ by real_tac - >> pop_assum $ rewrite_tac o single - >> unabbrev_all_tac - >> ‘inv (&FACT approxSteps) * sin t * x pow approxSteps * -1 pow (approxSteps DIV 2) = - (sin t * ((x pow approxSteps) * inv (&FACT approxSteps) * -1 pow (approxSteps DIV 2)))’ - by real_tac - >> ‘-(x pow approxSteps) * inv (&FACT approxSteps) * sin t = - -(sin t * ((x pow approxSteps) * inv (&FACT approxSteps)))’ - by real_tac - >> rewrite_tac [] - >> ntac 2 $ pop_assum $ rewrite_tac o single - >> rewrite_tac[GSYM REAL_MUL_ASSOC] - >> qmatch_goalsub_abbrev_tac ‘_ * err_sin_concr’ - >> rewrite_tac [ABS_NEG, Once ABS_MUL] - >> irule REAL_LE_TRANS - >> qexists_tac ‘ 1 * abs err_sin_concr’ >> conj_tac - >- (irule REAL_LE_RMUL_IMP >> unabbrev_all_tac >> gs[SIN_BOUND, ABS_POS]) - >> rewrite_tac [REAL_MUL_LID, sin_err_def, ABS_MUL] - >> ‘abs err_sin_concr = err_sin_concr’ - by (unabbrev_all_tac - >> rewrite_tac[ABS_REFL] - >> irule REAL_LE_MUL >> conj_tac - >> gs[REAL_POW_GE0] - >> irule REAL_LE_MUL >> gs[REAL_POS, REAL_POW_GE0]) - >> pop_assum $ rewrite_tac o single - >> unabbrev_all_tac - >> rewrite_tac [sin_err_def] - >> imp_res_tac EVEN_ODD_EXISTS >> gs[POW_MINUS1] - >> irule REAL_LE_LMUL_IMP >> gs[GSYM POW_ABS] - >> irule REAL_LE_TRANS - >> qexists_tac ‘abs (x pow (2 * m))’ >> gs[ABS_LE, GSYM POW_ABS] - >> irule POW_LE >> gs[ABS_POS] - >> irule RealSimpsTheory.maxAbs >> gs[]) - >- ( - rpt VAR_EQ_TAC - >> gs[interp_def, eval_simps] - >> qmatch_goalsub_abbrev_tac ‘abs (f_x + g_x - (f_poly_x + g_poly_x)) ≤ _’ - >> ‘f_x + g_x - (f_poly_x + g_poly_x) = (f_x - f_poly_x) + (g_x - g_poly_x)’ - by real_tac - >> pop_assum $ rewrite_tac o single - >> irule REAL_LE_TRANS - >> qexists_tac ‘abs (f_x - f_poly_x) + abs (g_x - g_poly_x)’ - >> gs[REAL_ABS_TRIANGLE] - >> irule REAL_LE_ADD2 >> unabbrev_all_tac >> gs[]) - >- ( - rpt VAR_EQ_TAC - >> gs[interp_def, eval_simps] - >> qmatch_goalsub_abbrev_tac ‘abs (f_x - g_x - (f_poly_x - g_poly_x)) ≤ _’ - >> ‘f_x - g_x - (f_poly_x - g_poly_x) = (f_x - f_poly_x) - (g_x - g_poly_x)’ - by real_tac - >> pop_assum $ rewrite_tac o single - >> irule REAL_LE_TRANS - >> qexists_tac ‘abs (f_x - f_poly_x) + abs (- (g_x - g_poly_x))’ - >> conj_tac - >- (rewrite_tac[real_sub] >> irule REAL_ABS_TRIANGLE) - >> gs[real_sub] - >> irule REAL_LE_ADD2 >> unabbrev_all_tac >> gs[]) - >> rpt VAR_EQ_TAC - >> gs[interp_def, eval_simps, real_sub] - >> qmatch_goalsub_abbrev_tac ‘abs (- f_x + f_poly_x)’ - >> ‘- f_x + f_poly_x = f_poly_x - f_x’ by real_tac - >> pop_assum $ rewrite_tac o single - >> once_rewrite_tac [ABS_SUB] - >> unabbrev_all_tac >> gs[real_sub] -QED - (* Theorem checker_soundness: ∀ cert approxSteps. diff --git a/mcLaurinApproxScript.sml b/mcLaurinApproxScript.sml index ae5728ea525e82cadd863fe76d779eb922823810..4a44a00f4b45f64f9816d20b2470d3248b762389 100644 --- a/mcLaurinApproxScript.sml +++ b/mcLaurinApproxScript.sml @@ -114,46 +114,6 @@ Proof >> gs[] QED -Theorem sin_even_remainder_bounded: - ∀ n. - EVEN n ⇒ - inv (&FACT n) * sin t * x pow n * -1 pow (n DIV 2) ≤ - abs(inv (&FACT n) * x pow n * -1 pow (n DIV 2)) -Proof - rpt strip_tac - >> ‘inv (&FACT n) * x pow n * -1 pow (n DIV 2) = inv (&FACT n) * 1 * x pow n * -1 pow (n DIV 2)’ - by real_tac - >> pop_assum $ rewrite_tac o single - >> rewrite_tac[GSYM REAL_MUL_ASSOC] - >> once_rewrite_tac[REAL_ABS_MUL] - >> ‘0 ≤ inv (&FACT n)’ - by gs[REAL_LE_INV] - >> ‘abs (inv (&FACT n)) = inv (&FACT n)’ by gs[abs] - >> pop_assum $ rewrite_tac o single - >> irule REAL_LE_LMUL_IMP - >> reverse conj_tac >- gs[] - >> once_rewrite_tac[REAL_ABS_MUL] - >> Cases_on ‘0 ≤ x pow n * -1 pow (n DIV 2)’ - >- ( - ‘abs (x pow n * -1 pow (n DIV 2)) = x pow n * -1 pow (n DIV 2)’ by gs[abs] - >> pop_assum $ rewrite_tac o single - >> irule REAL_LE_RMUL_IMP >> gs[SIN_BOUNDS]) - >> ‘x pow n * -1 pow (n DIV 2) < 0’ by real_tac - >> irule REAL_LE_TRANS - >> qexists_tac ‘-1 * (x pow n * -1 pow (n DIV 2))’ - >> conj_tac - >- ( - once_rewrite_tac [REAL_MUL_COMM] - >> drule REAL_LE_LMUL_NEG - >> disch_then $ qspecl_then [‘sin t’, ‘-1’] $ rewrite_tac o single - >> gs[SIN_BOUNDS]) - >> ‘∃ y. x pow n * -1 pow (n DIV 2) = -1 * y ∧ 0 ≤ y’ - by (qexists_tac ‘-1 * x pow n * -1 pow (n DIV 2)’ - >> real_tac) - >> qpat_x_assum `_ = -1 * y` $ rewrite_tac o single - >> gs[ABS_LE] -QED - Theorem MCLAURIN_COS_LE: ∀ x n. ∃t. abs(t) ≤ abs (x) ∧ (\n. if EVEN n then @@ -229,7 +189,6 @@ Proof >> gs[] QED - (*** Prove lemma for bound on exp in the interval, x ∈ [0, 0.5] based on John Harrison's paper **) @@ -324,275 +283,7 @@ Proof >> MATCH_MP_TAC REAL_LE_MUL >> gs[] QED -Definition exp_poly_def: - exp_poly 0 = [] ∧ (* x pow 0 * inv FACT 0 *) - exp_poly (SUC n) = (exp_poly n) ++ [inv (&FACT n)] -End - -Theorem exp_poly_LENGTH: - LENGTH (exp_poly n) = n -Proof - Induct_on ‘n’ >> gs[exp_poly_def] -QED - -Theorem exp_sum_to_poly: - ∀ n x. evalPoly (exp_poly n) x = sum (0,n) (λ m. x pow m / &FACT m) -Proof - Induct_on ‘n’ >> gs[exp_poly_def, evalPoly_def, sum] - >> rpt strip_tac >> gs[evalPoly_app, evalPoly_def, exp_poly_LENGTH] -QED - -Theorem exp_remainder_bounded_small: - ∀ n x t. - 0 < n ∧ abs t ≤ abs x ∧ 0 ≤ x ∧ - t ≤ inv 2 ∧ x ≤ inv 2 ⇒ - abs (exp t / &FACT n * x pow n) ≤ inv (&FACT n * 2 pow (n - 1)) -Proof - rpt strip_tac >> rewrite_tac[real_div, abs] - >> qmatch_goalsub_abbrev_tac ‘(if 0 ≤ exp_bound then _ else _) ≤ _’ - >> ‘0 ≤ exp_bound’ - by ( - unabbrev_all_tac - >> rpt (irule REAL_LE_MUL >> gs[POW_POS, EXP_POS_LE])) - >> simp[] >> unabbrev_all_tac - >> irule REAL_LE_TRANS - >> qexists_tac ‘(1 + 2 * inv 2) * (inv (&FACT n) * x pow n)’ - >> conj_tac - >- ( - rewrite_tac[GSYM REAL_MUL_ASSOC] - >> irule REAL_LE_RMUL_IMP - >> conj_tac - >- ( - Cases_on ‘0 ≤ t’ - >- ( - irule REAL_LE_TRANS - >> qexists_tac ‘1 + 2 * t’ >> conj_tac - >- (irule REAL_EXP_BOUND_LEMMA >> gs[]) - >> real_tac) - >> ‘t = - (- t)’ by real_tac - >> pop_assum $ once_rewrite_tac o single - >> once_rewrite_tac[EXP_NEG] - >> ‘- (inv 2) ≤ -t’ by real_tac - >> irule REAL_LE_TRANS - >> qexists_tac ‘inv (exp (- (inv 2)))’ - >> conj_tac - >- (irule REAL_INV_LE_ANTIMONO_IMPR >> gs[EXP_POS_LT, EXP_MONO_LE]) - >> rewrite_tac[EXP_NEG, REAL_INV_INV] - >> irule REAL_EXP_BOUND_LEMMA >> gs[]) - >> irule REAL_LE_MUL >> gs[REAL_LE_INV, POW_POS]) - >> ‘1 + 2 * inv 2 = 2’ by gs[] - >> pop_assum $ rewrite_tac o single - >> rewrite_tac[GSYM REAL_MUL_ASSOC, REAL_INV_MUL'] - >> irule REAL_LE_TRANS - >> qexists_tac ‘2 * (inv (&FACT n) * inv 2 pow n)’ - >> conj_tac - >- ( - irule REAL_LE_LMUL_IMP >> reverse conj_tac >- gs[] - >> irule REAL_LE_LMUL_IMP >> reverse conj_tac >- gs[REAL_LE_INV] - >> irule POW_LE >> gs[]) - >> Cases_on ‘n’ >- gs[] - >> rewrite_tac[pow] - >> gs[REAL_INV_MUL'] -QED - -Theorem exp_remainder_bounded_big: - ∀ n m x t. - 0 < n ∧ abs t ≤ abs x ∧ 0 ≤ x ∧ - x ≤ &m * (inv 2) ∧ - t ≤ &m * (inv 2) ⇒ - abs (exp t / &FACT n * x pow n) ≤ 2 pow m * &m pow n * (inv (&FACT n * 2 pow n)) -Proof - rpt strip_tac >> rewrite_tac[real_div, abs] - >> qmatch_goalsub_abbrev_tac ‘(if 0 ≤ exp_bound then _ else _) ≤ _’ - >> ‘0 ≤ exp_bound’ - by ( - unabbrev_all_tac - >> rpt (irule REAL_LE_MUL >> gs[POW_POS, EXP_POS_LE])) - >> pop_assum $ rewrite_tac o single - >> unabbrev_all_tac - >> irule REAL_LE_TRANS - >> qexists_tac ‘exp (&m * inv 2) * (inv (&FACT n) * x pow n)’ - >> conj_tac - >- ( - rewrite_tac[GSYM REAL_MUL_ASSOC] - >> irule REAL_LE_RMUL_IMP - >> conj_tac - >- gs[EXP_MONO_LE] - >> irule REAL_LE_MUL >> gs[REAL_LE_INV, POW_POS]) - >> rewrite_tac[EXP_N] - >> qmatch_goalsub_abbrev_tac ‘_ * cst_err ≤ _’ - >> irule REAL_LE_TRANS - >> qexists_tac ‘(1 + 2 * inv 2) pow m * cst_err’ - >> conj_tac - >- ( - irule REAL_LE_RMUL_IMP - >> conj_tac - >- ( - irule POW_LE >> rewrite_tac[EXP_POS_LE] - >> irule REAL_EXP_BOUND_LEMMA >> gs[]) - >> unabbrev_all_tac - >> irule REAL_LE_MUL >> gs[REAL_LE_INV, POW_POS]) - >> ‘1 + 2 * inv 2 = 2’ by gs[] - >> pop_assum $ rewrite_tac o single - >> unabbrev_all_tac - >> rewrite_tac[REAL_MUL_ASSOC] - >> qmatch_goalsub_abbrev_tac ‘cst_err * x pow n’ - >> irule REAL_LE_TRANS - >> qexists_tac ‘cst_err * (&m * inv 2) pow n’ >> conj_tac - >- ( - irule REAL_LE_LMUL_IMP >> conj_tac - >- gs[POW_LE] - >> unabbrev_all_tac >> irule REAL_LE_MUL - >> gs[REAL_LE_INV, POW_POS]) - >> rewrite_tac [POW_MUL] - >> unabbrev_all_tac - >> qmatch_goalsub_abbrev_tac ‘curr_bound ≤ _’ - >> ‘curr_bound = 2 pow m * &m pow n * (inv (&FACT n * 2 pow n))’ - by (unabbrev_all_tac >> gs[REAL_POW_INV]) - >> pop_assum $ rewrite_tac o single - >> unabbrev_all_tac >> gs[] -QED - -Definition cos_poly_def: - cos_poly 0 = [] ∧ - cos_poly (SUC n) = - if (EVEN n) then - cos_poly n ++ [-1 pow (n DIV 2) * inv (&FACT n)] - else cos_poly n ++ [0] -End - -Theorem LENGTH_cos_poly: - LENGTH (cos_poly n) = n -Proof - Induct_on ‘n’ >> gs[cos_poly_def] - >> cond_cases_tac >> gs[] -QED - -Theorem cos_sum_to_poly: - ∀ n x. evalPoly (cos_poly n) x = - sum(0,n) - (λm. - (&FACT m)â»Â¹ * x pow m * - if EVEN m then cos 0 * -1 pow (m DIV 2) - else sin 0 * -1 pow ((SUC m) DIV 2)) -Proof - Induct_on ‘n’ >> gs[sum, evalPoly_def, cos_poly_def] - >> cond_cases_tac - >> gs[evalPoly_app, COS_0, SIN_0, evalPoly_def, LENGTH_cos_poly] -QED - -Theorem cos_even_remainder_bounded: - ∀ n. - EVEN n ⇒ - inv (&FACT n) * cos t * x pow n * -1 pow (n DIV 2) ≤ - abs(inv (&FACT n) * x pow n * -1 pow (n DIV 2)) -Proof - rpt strip_tac - >> ‘inv (&FACT n) * x pow n * -1 pow (n DIV 2) = inv (&FACT n) * 1 * x pow n * -1 pow (n DIV 2)’ - by real_tac - >> pop_assum $ rewrite_tac o single - >> rewrite_tac[GSYM REAL_MUL_ASSOC] - >> once_rewrite_tac[REAL_ABS_MUL] - >> ‘0 ≤ inv (&FACT n)’ - by gs[REAL_LE_INV] - >> ‘abs (inv (&FACT n)) = inv (&FACT n)’ by gs[abs] - >> pop_assum $ rewrite_tac o single - >> irule REAL_LE_LMUL_IMP - >> reverse conj_tac >- gs[] - >> once_rewrite_tac[REAL_ABS_MUL] - >> Cases_on ‘0 ≤ x pow n * -1 pow (n DIV 2)’ - >- ( - ‘abs (x pow n * -1 pow (n DIV 2)) = x pow n * -1 pow (n DIV 2)’ by gs[abs] - >> pop_assum $ rewrite_tac o single - >> irule REAL_LE_RMUL_IMP >> gs[COS_BOUNDS]) - >> ‘x pow n * -1 pow (n DIV 2) < 0’ by real_tac - >> irule REAL_LE_TRANS - >> qexists_tac ‘-1 * (x pow n * -1 pow (n DIV 2))’ - >> conj_tac - >- ( - once_rewrite_tac [REAL_MUL_COMM] - >> drule REAL_LE_LMUL_NEG - >> disch_then $ qspecl_then [‘cos t’, ‘-1’] $ rewrite_tac o single - >> gs[COS_BOUNDS]) - >> ‘∃ y. x pow n * -1 pow (n DIV 2) = -1 * y ∧ 0 ≤ y’ - by (qexists_tac ‘-1 * x pow n * -1 pow (n DIV 2)’ - >> real_tac) - >> qpat_x_assum `_ = -1 * y` $ rewrite_tac o single - >> gs[ABS_LE] -QED - -(** sin **) -Definition sin_poly_def: - sin_poly 0 = [] ∧ - sin_poly (SUC n) = - if (EVEN n) then sin_poly n ++ [0] - else sin_poly n ++ [-1 pow ((n - 1) DIV 2) * inv (&FACT n)] -End - -Theorem LENGTH_sin_poly: - LENGTH (sin_poly n) = n -Proof - Induct_on ‘n’ >> gs[sin_poly_def] - >> cond_cases_tac >> gs[] -QED - -Theorem sin_sum_to_poly: - ∀ n x. - evalPoly (sin_poly n) x = - sum(0,n) - (λm. - (&FACT m)â»Â¹ * x pow m * - if EVEN m then sin 0 * -1 pow (m DIV 2) - else cos 0 * -1 pow ((m - 1) DIV 2)) -Proof - Induct_on ‘n’ >> gs[sum, evalPoly_def, sin_poly_def] - >> cond_cases_tac - >> gs[evalPoly_app, SIN_0, COS_0, evalPoly_def, LENGTH_sin_poly] -QED - -Theorem sin_even_remainder_bounded: - ∀ n. - EVEN n ⇒ - inv (&FACT n) * sin t * x pow n * -1 pow (n DIV 2) ≤ - abs(inv (&FACT n) * x pow n * -1 pow (n DIV 2)) -Proof - rpt strip_tac - >> ‘inv (&FACT n) * x pow n * -1 pow (n DIV 2) = inv (&FACT n) * 1 * x pow n * -1 pow (n DIV 2)’ - by real_tac - >> pop_assum $ rewrite_tac o single - >> rewrite_tac[GSYM REAL_MUL_ASSOC] - >> once_rewrite_tac[REAL_ABS_MUL] - >> ‘0 ≤ inv (&FACT n)’ - by gs[REAL_LE_INV] - >> ‘abs (inv (&FACT n)) = inv (&FACT n)’ by gs[abs] - >> pop_assum $ rewrite_tac o single - >> irule REAL_LE_LMUL_IMP - >> reverse conj_tac >- gs[] - >> once_rewrite_tac[REAL_ABS_MUL] - >> Cases_on ‘0 ≤ x pow n * -1 pow (n DIV 2)’ - >- ( - ‘abs (x pow n * -1 pow (n DIV 2)) = x pow n * -1 pow (n DIV 2)’ by gs[abs] - >> pop_assum $ rewrite_tac o single - >> irule REAL_LE_RMUL_IMP >> gs[SIN_BOUNDS]) - >> ‘x pow n * -1 pow (n DIV 2) < 0’ by real_tac - >> irule REAL_LE_TRANS - >> qexists_tac ‘-1 * (x pow n * -1 pow (n DIV 2))’ - >> conj_tac - >- ( - once_rewrite_tac [REAL_MUL_COMM] - >> drule REAL_LE_LMUL_NEG - >> disch_then $ qspecl_then [‘sin t’, ‘-1’] $ rewrite_tac o single - >> gs[SIN_BOUNDS]) - >> ‘∃ y. x pow n * -1 pow (n DIV 2) = -1 * y ∧ 0 ≤ y’ - by (qexists_tac ‘-1 * x pow n * -1 pow (n DIV 2)’ - >> real_tac) - >> qpat_x_assum `_ = -1 * y` $ rewrite_tac o single - >> gs[ABS_LE] -QED - - (** Mclaurin series for sqrt fucntion **) - (** Idea is to convert the sqrt function to exp (ln x /2) **) Theorem diff_chain: ∀x. ((λx. 1 + x) diffl 1) x @@ -609,7 +300,6 @@ Proof >> gs[limTheory.DIFF_X] QED - Theorem SQRT_EXPLN_DIFF: ∀x. 0 <= x ⇒ ((λx. exp ((\x. (ln (1+x)) / &2) x)) diffl (exp ((\x. (ln (1+x)) / &2) x) * (inv (1+x) / &2))) x @@ -649,7 +339,6 @@ Proof >> gs[REAL_LET_ADD] QED - Theorem exp_add_EXPLN: ∀ m t. m ≠0 ⇒ 0 ≤ t ⇒ exp (ln (1 + t) * &(2 * m + 1) / &2) = @@ -898,7 +587,6 @@ Proof (λx. &FACT (2 * PRE m) *( (\x. (exp (ln (1 + x) * &(2 * PRE m + 1) / 2))â»Â¹ ) x)) ’ by gs[FUN_EQ_THM] - >> pop_assum $ rewrite_tac o single >> irule limTheory.DIFF_CMUL >> ‘ &(2 * m) = &2 * &m ’ by gs[GSYM REAL_OF_NUM_MUL] @@ -1018,7 +706,6 @@ fun real_rw (t:Q.tmquote) = fun transitivity_for t = irule REAL_LE_TRANS >> qexists_tac t - Theorem EXP_MINUS_ONE_POS: ∀ x. 0 ≤ x ⇒ 0 ≤ exp x - 1 @@ -1029,6 +716,7 @@ Proof >> gs[EXP_0, EXP_MONO_LE] QED +(** TODO: Move? Theorem MCLAURIN_EXP_COMPOSITE_ERR: ∀ (f:real->real) (q:poly) (r:real->real) x n lb ub ubQ. 0 ≤ ubQ ∧ (* The upper bound is positive *) @@ -1093,6 +781,7 @@ Proof >> qspec_then ‘r x’ mp_tac REAL_EXP_BOUND_LEMMA >> gs[] QED + **) Theorem MCLAURIN_SIN_COMPOSITE: ∀ f q r x. diff --git a/transcIntvSemScript.sml b/transcIntvSemScript.sml new file mode 100644 index 0000000000000000000000000000000000000000..256fd2345aaa7f89c86347b48cb98c9d91af52ff --- /dev/null +++ b/transcIntvSemScript.sml @@ -0,0 +1,257 @@ +(** + Define a simple "language" for describing transcendental + functions. For now we only allow combinations, i.e. + exp (sin (cos ...) but no additional operators like +,-,*,/ +**) +open realTheory realLib RealArith transcTheory; +open IntervalArithTheory sqrtApproxTheory IntervalValidationTheory; +open realPolyTheory transcLangTheory approxPolyTheory; +open preamble; + +val _ = new_theory "transcIntvSem"; + +Definition intvUop_def: + intvUop (Neg:transcLang$unop) iv = negateInterval iv ∧ + intvUop Inv iv = invertInterval iv +End + +Definition intvBop_def: + intvBop (Add:transcLang$binop) iv1 iv2 = addInterval iv1 iv2 ∧ + intvBop Sub iv1 iv2 = subtractInterval iv1 iv2 ∧ + intvBop Mul iv1 iv2 = multInterval iv1 iv2 ∧ + intvBop Div iv1 iv2 = divideInterval iv1 iv2 +End + +Definition evalPolyIntv_def: + evalPolyIntv [] iv = (0,0) ∧ + evalPolyIntv (c::cs) iv = intvBop Add (c,c) (intvBop Mul iv (evalPolyIntv cs iv)) +End + +Definition internalSteps_def: + internalSteps:num = 40 +End + +Definition newtonIters_def: + newtonIters:num = 4 +End + +(** + compute an interval bound for a transcendental/ HOL4 uncomputable function. + We include sqrt here as it cannot be evaluated in HOL4 directly. + The newton approximation trick is borrowed from FloVer. + As we have to validate the newton approximation afterwards, it may fail + to compute an interval bound thus we return an option here. + In practice, we have not yet encountered a case where 4 iterations where not + sufficient in combination with the multiplications +**) +Definition getFunIv_def: + getFunIv Exp iv = + (let + lbExp = evalPoly (expPoly internalSteps) (FST iv); + ubExp = evalPoly (expPoly internalSteps) (SND iv) + + if iv = (0, inv 2) then expErrSmall internalSteps + else expErrBig (clg (abs (SND iv) * 2)) internalSteps; + in + SOME (lbExp, ubExp)) ∧ + getFunIv Sin iv = SOME (-1, 1) ∧ + getFunIv Cos iv = SOME (-1, 1) ∧ + getFunIv Tan iv = SOME (-1, 1) ∧ + getFunIv Sqrt iv = + (* we do a newton approximation of the lower and upper bounds, + 0 < FST iv has to be checked before *) + let sqrtLo = newton newtonIters (FST iv * 0.99) (IVlo iv * 0.99); + sqrtHi = newton newtonIters (SND iv * 1.01) (SND iv * 1.01); + newIV = (sqrtLo, sqrtHi) + in + if (validate_newton_down sqrtLo (FST iv) ∧ + validate_newton_up sqrtHi (SND iv)) then + SOME newIV + else NONE +End + +Definition interpIntv_def: + interpIntv (Var x) (env:(string#(real#real)) list) = + do xv <- FIND (λ (y, iv). y = x) env; + return (SND xv); + od ∧ + interpIntv (Cst c) env = SOME (c,c) ∧ + interpIntv (Uop uop t) env = + do r <- interpIntv t env; + assert ((~ (uop = Inv)) ∨ (SND r < 0 ∨ 0 < FST r )); + return (intvUop uop r) + od ∧ + interpIntv (Bop bop t1 t2) env = + do + r1 <- interpIntv t1 env; + r2 <- interpIntv t2 env; + if bop = Div ∧ ~(SND r2 < 0 ∨ 0 < FST r2) + then NONE + else return (intvBop bop r1 r2); + od ∧ + interpIntv (Fun s t) env = + do + r <- interpIntv t env; + (* Sqrt defined for positive values only *) + assert ((~ (s = Sqrt)) ∨ (0 < FST r)); + (* Tan cannot be done at 0 because we approximate it with sin x/cos x *) + assert ((~ (s = Tan)) ∨ (SND r < 0 ∨ 0 < FST r )); + getFunIv s r; + od ∧ + interpIntv (Poly p t) env = + do + r <- interpIntv t env; + return (evalPolyIntv p r) + od +End + +Definition varsContained_def: + varsContained (cenv:(string#real) list) (ivenv:(string#(real#real)) list) = + ∀ x xiv. + FIND (λ (y,r). y = x) ivenv = SOME xiv ⇒ + ∃ xr. + FIND (λ (y,r). y = x) cenv = SOME xr ∧ + FST (SND xiv) ≤ SND xr ∧ SND xr ≤ SND (SND xiv) +End + +Theorem evalPolyIntv_sound: + ∀ p x iv. + FST iv ≤ x ∧ + x ≤ SND iv ⇒ + FST (evalPolyIntv p iv) ≤ evalPoly p x ∧ + evalPoly p x ≤ SND (evalPolyIntv p iv) +Proof + Induct_on ‘p’ >> gs[evalPolyIntv_def, evalPoly_def] + >> rpt strip_tac + >> first_x_assum $ drule_then $ drule_then assume_tac + >> ‘contained (evalPoly p x) (evalPolyIntv p iv)’ by gs[contained_def] + >> ‘contained x iv’ by gs[contained_def] + >> pop_assum $ mp_then Any mp_tac interval_multiplication_valid + >> disch_then (fn th => pop_assum $ mp_then Any mp_tac th) + >> qspec_then ‘h’ (assume_tac o SIMP_RULE std_ss [pointInterval_def]) validPointInterval + >> pop_assum $ mp_then Any mp_tac (SIMP_RULE std_ss [validIntervalAdd_def] interval_addition_valid) + >> disch_then (fn th => disch_then $ mp_then Any mp_tac th) + >> strip_tac >> gs[contained_def, intvBop_def] +QED + +Theorem interpIntv_sound: + ∀ t cenv ivenv iv r. + varsContained cenv ivenv ∧ + interpIntv t ivenv = SOME iv ⇒ + ∃ r. + interp t cenv = SOME r ∧ + FST iv ≤ r ∧ r ≤ SND iv +Proof + Induct_on ‘t’ >> gs[interpIntv_def, interp_def] + >> rpt strip_tac + >- ( + last_x_assum drule >> disch_then $ drule_then strip_assume_tac + >> gs[PULL_EXISTS] + >> Cases_on ‘t0’ >> gs[getFun_def, getFunIv_def] + >> rpt VAR_EQ_TAC >> gs[SIN_BOUNDS, COS_BOUNDS] + (* exp *) + >- ( + conj_tac + (* lower bound *) + >- ( + irule REAL_LE_TRANS >> qexists_tac ‘exp (FST r)’ + >> gs[EXP_MONO_LE] + >> qspecl_then [‘FST r’, ‘internalSteps’] strip_assume_tac MCLAURIN_EXP_LE + >> pop_assum $ rewrite_tac o single + >> gs[exp_sum_to_poly] + >> irule REAL_LE_MUL + >> gs[POW_POS, internalSteps_def] + >> irule REAL_LE_MUL + >> gs[EXP_POS_LE]) + (* upper bound *) + >> irule REAL_LE_TRANS >> qexists_tac ‘exp (SND r)’ + >> gs[EXP_MONO_LE] + >> qspecl_then [‘SND r’, ‘internalSteps’] strip_assume_tac MCLAURIN_EXP_LE + >> pop_assum $ rewrite_tac o single + >> gs[exp_sum_to_poly] + >> qmatch_goalsub_abbrev_tac ‘exp_err ≤ _’ + >> irule REAL_LE_TRANS >> qexists_tac ‘abs exp_err’ >> gs[ABS_LE] + >> unabbrev_all_tac + >> Cases_on ‘r = (0, inv 2)’ + >> asm_rewrite_tac[expErrSmall_def, GSYM real_div] + >- ( + irule exp_remainder_bounded_small + >> Cases_on ‘r’ >> gs[internalSteps_def] + >> gs[abs] >> every_case_tac >> real_tac) + >> asm_rewrite_tac[expErrBig_def] + >> irule exp_remainder_bounded_big + >> qmatch_goalsub_abbrev_tac ‘abs (SND r) ≤ upExp’ + >> ‘abs (SND r) ≤ upExp’ + by ( + unabbrev_all_tac + >> cond_cases_tac >> gs[] + >- (pop_assum $ rewrite_tac o single o GSYM >> gs[]) + >> irule REAL_LE_TRANS >> qexists_tac ‘&clg (2 * abs (SND r))’ + >> gs[LE_NUM_CEILING]) + >> Cases_on ‘r’ >> rpt conj_tac >> TRY( gs[internalSteps_def] >> NO_TAC) + >> irule REAL_LE_TRANS + >> qexists_tac ‘abs (SND (q,r''))’ >> gs[] + >> irule REAL_LE_TRANS >> qexists_tac ‘abs t'’ >> gs[ABS_LE]) + (* tan 1 *) + >- ( cheat ) + (* tan 2 *) + >- ( cheat ) + (* sqrt *) + >> first_x_assum $ mp_then Any mp_tac validate_newton_lb_valid + >> impl_tac >> gs[] + >- ( + reverse conj_tac >- real_tac + >> irule newton_method_pos >> conj_tac + >> irule REAL_LE_MUL >> gs[] >> real_tac) + >> first_x_assum $ mp_then Any mp_tac validate_newton_ub_valid + >> impl_tac >> gs[] + >- ( + reverse conj_tac >- real_tac + >> irule newton_method_pos >> conj_tac + >> irule REAL_LE_MUL >> gs[] >> real_tac) + >> rpt strip_tac + >> irule REAL_LE_TRANS + THENL [ + qexists_tac ‘sqrt (FST r)’, + qexists_tac ‘sqrt (SND r)’] + >> gs[] + >> irule SQRT_MONO_LE >> real_tac) + >- ( + first_x_assum $ drule_then $ drule_then strip_assume_tac + >> drule_then drule evalPolyIntv_sound + >> disch_then $ qspec_then ‘l’ assume_tac + >> gs[PULL_EXISTS]) + >- ( + gs[PULL_EXISTS] + >> ntac 2 ( + last_x_assum drule + >> disch_then $ drule_then strip_assume_tac) + >> Cases_on ‘b’ >> gs[interp_def, intvBop_def] + >- ( + qspecl_then [‘r1’, ‘r2’] mp_tac interval_addition_valid + >> gs[validIntervalAdd_def, contained_def, appBop_def] + >> rpt $ disch_then drule) + >- ( + qspecl_then [‘r1’, ‘r2’] mp_tac interval_subtraction_valid + >> gs[validIntervalSub_def, contained_def, appBop_def] + >> rpt $ disch_then drule) + >- ( + qspecl_then [‘r1’, ‘r2’] mp_tac interval_multiplication_valid + >> gs[contained_def, appBop_def]) + >> qspecl_then [‘r1’, ‘r2’] mp_tac interval_division_valid + >> gs[contained_def, appBop_def]) + >- ( + gs[PULL_EXISTS] + >> last_x_assum drule + >> disch_then $ drule_then strip_assume_tac + >> Cases_on ‘u’ >> gs[interp_def, intvUop_def, appUop_def] + >- ( + qspec_then ‘r’ mp_tac interval_negation_valid + >> gs[contained_def]) + >> qspec_then ‘r’ mp_tac interval_inversion_valid + >> gs[contained_def]) + >> gs[varsContained_def, PULL_EXISTS] + >> res_tac + >> gs[] +QED + +val _ = export_theory(); diff --git a/transcLangScript.sml b/transcLangScript.sml index 8277a11298268ca90e46441ebdc3b9a29881bafb..911e75f6f9d3ef7791bd6904c4a89903912ac962 100644 --- a/transcLangScript.sml +++ b/transcLangScript.sml @@ -4,37 +4,138 @@ exp (sin (cos ...) but no additional operators like +,-,*,/ **) open realTheory realLib RealArith transcTheory; +open realPolyTheory; open preamble; val _ = new_theory "transcLang"; +val _ = monadsyntax.enable_monadsyntax(); +val _ = monadsyntax.enable_monad "option"; + +Datatype: + binop = Add | Sub | Mul | Div +End + +Datatype: + unop = Neg | Inv +End + +Datatype: + trFun = Exp | Sin | Cos | Tan | Sqrt +End + Datatype: transc = - Fun string transc - | Add transc transc - | Sub transc transc - | Neg transc - | Var + Fun trFun transc + | Poly poly transc + | Bop binop transc transc + | Uop unop transc + | Cst real + | Var string End Definition getFun_def: - getFun s = - case s of - |"sqrt" => sqrt - | "exp" => exp - | "sin" => sin - | "cos" => cos - | "tan" => tan - | _ => λ x. x + getFun Exp = exp ∧ + getFun Sin = sin ∧ + getFun Cos = cos ∧ + getFun Tan = tan ∧ + getFun Sqrt = sqrt +End + +Definition appUop_def: + appUop Neg r = - r ∧ + appUop Inv r = inv r +End + +Definition appBop_def: + appBop Add = realax$real_add ∧ + appBop Sub = $- ∧ + appBop Mul = $* ∧ + appBop Div = $/ End Definition interp_def: - interp Var x = x ∧ - interp (Neg t) x = - (interp t x) ∧ - interp (Add t1 t2) x = (interp t1 x) + (interp t2 x) ∧ - interp (Sub t1 t2) x = (interp t1 x) - (interp t2 x) ∧ - interp (Fun s trans) x = - (getFun s) (interp trans x) + interp (Var x) env = + do v <- FIND (λ (y,r). y = x) env; + return (SND v); + od ∧ + interp (Cst c) env = SOME c ∧ + interp (Uop uop t) env = + do r <- interp t env; + return (appUop uop r) + od ∧ + interp (Bop bop t1 t2) env = + do + r1 <- interp t1 env; + r2 <- interp t2 env; + return (appBop bop r1 r2); + od ∧ + interp (Fun s t) env = + do + r <- interp t env; + return ((getFun s) r); + od ∧ + interp (Poly p t) env = + do + r <- interp t env; + return (evalPoly p r) + od +End + +Datatype: + transcProg = + Let string transc transcProg + | Ret transc +End + +Definition interpProg_def: + interpProg (Let x e p) env = + do + r <- interp e env; + interpProg p ((x, r)::env) + od ∧ + interpProg (Ret e) env = interp e env End +Definition transcProgEq_def: + transcProgEq p1 p2 = + ∀ env. + interpProg p1 env = interpProg p2 env +End + +Theorem transcProgEq_sym: + transcProgEq p1 p1 +Proof + gs[transcProgEq_def] +QED + +Theorem transcProgEq_tan_ret: + ∀ x t. + transcProgEq (Ret (Fun Tan t)) (Ret (Bop Div (Fun Sin t) (Fun Cos t))) +Proof + gs[transcProgEq_def, interpProg_def, interp_def] + >> rpt strip_tac + >> Cases_on ‘interp t env’ >> gs[getFun_def, tan, appBop_def] +QED + +Theorem transcProgEq_Let_rule: + x = y ∧ + (∀ env. interp e1 env = interp e2 env) ∧ + transcProgEq p1 p2 ⇒ + transcProgEq (Let x e1 p1) (Let y e2 p2) +Proof + rpt strip_tac >> gs[transcProgEq_def] + >> rpt strip_tac >> gs[interpProg_def] +QED + +Theorem transcProgEq_tan_let: + ∀ x t. + transcProgEq (Let x (Fun Tan t) p) (Let x (Bop Div (Fun Sin t) (Fun Cos t)) p) +Proof + rpt gen_tac >> irule transcProgEq_Let_rule >> gs[transcProgEq_sym] + >> rpt strip_tac + >> gs[interp_def] + >> Cases_on ‘interp t env’ >> gs[getFun_def, appBop_def, tan] +QED + val _ = export_theory();