Theory Mutual_Fixed_Points
theory Mutual_Fixed_Points
imports AutoCorres2_Main.AutoCorres_Main
begin
text ‹
To define functions from (mutually) recursive C function we use @{command fixed_point}.
This is a generalisation of @{command partial_function} supporting mutual recursion and is also
based on chain complete partial orders (CCPO), cf:
▪ 🌐‹https://www21.in.tum.de/~krauss/publication/2016-overview-paper/›
▪ 🌐‹https://www21.in.tum.de/~krauss/publication/2010-monadic-functions/›
In contrast to @{command function} we do not have to provide any termination argument in order to get
get the equations and an induction principle. However, the induction principle only allows
to prove admissible properties (@{const ccpo.admissible}). Lukily, the simulation properties
that we use in autocorres are admissible.
Moreover, to perform the fixed point construction from the defining equations monotonicity of
the functionals has to be proven @{const monotone}. The lemmas for those proofs are
collected in @{thm partial_function_mono}.
›
thm partial_function_mono
fun even'::"nat ⇒ bool" and odd':: "nat ⇒ bool"
where
"even' 0 = True"
| "odd' 0 = False"
| "even' (Suc n) = odd' n"
| "odd' (Suc n) = even' n"
thm even'_odd'.induct
thm even'.simps
lemma even'_odd'_mod2:
"even' n = (n mod 2 = 0)"
"odd' n = (n mod 2 = 1)"
apply (induct n and n rule: even'_odd'.induct)
apply simp_all
apply arith
apply arith
done
fixed_point (option) eveno oddo:: "nat ⇒ bool option"
where
"eveno n = (if n = 0 then Some True else oddo (n - 1))"
| "oddo n = (if n = 0 then Some False else eveno (n - 1))"
by simp_all
print_theorems
thm eveno_oddo.induct
thm eveno.simps
thm oddo.simps
text ‹One can also use patterns in the defining equations.
The usage and effect differs from @{command function}.
▪ Patterns do not have to be complete but they have to be unambiguous (no overlapping patterns).
This is captured in the proof obligations @{const subsingleton_set}.
▪ There is no automatic disambiguation going on, like taking the order of appearance into account.
›
fixed_point (option) eveno' oddo':: "nat ⇒ bool option"
where
"eveno' 0 = Some True"
| "eveno' (Suc n) = oddo' n"
| "oddo' 0 = Some False"
| "oddo' (Suc n) = eveno' n"
thm subsingleton_set_def
by (auto simp add: subsingleton_set_def)
thm eveno'_oddo'.induct
thm eveno'.simps
thm oddo'.simps
text ‹One can also push the arguments to the right hand side.›
fixed_point (option) eveno'' oddo'':: "nat ⇒ bool option"
where
"eveno'' = (λn. if n = 0 then Some True else oddo'' (n - 1))"
| "oddo'' = (λn. if n = 0 then Some False else eveno'' (n - 1))"
by simp_all
thm eveno''_oddo''.induct
thm eveno''.simps
thm oddo''.simps
text ‹Partial correctness properties are admissible. So the induction principle can be used.
However, this is more an academic (artificial) choice here,
as it is more straightforward to use plain natural number induction on the parameter.›
lemma eveno_oodo_mod2:
"∀x. (eveno n = Some x) ⟶ (x = (n mod 2 = 0))"
"∀x. (oddo n = Some x) ⟶ (x = (n mod 2 = 1))"
apply (induct n and n rule: eveno_oddo.induct)
apply simp_all
apply (smt (verit, best) ccpo.admissibleI flat_lub_in_chain option.simps(3))
apply (smt (verit, best) ccpo.admissibleI flat_lub_in_chain option.simps(3))
apply (metis cong_exp_iff_simps(6) diff_Suc_Suc even'.cases minus_nat.diff_0
mod_Suc_eq mod_self nat_minus_mod not_mod2_eq_Suc_0_eq_0 numeral_1_eq_Suc_0)
by (metis One_nat_def Suc_pred bits_one_mod_two_eq_one bot_nat_0.not_eq_extremum
mod_Suc_eq nat_minus_mod)
lemma
"∀x. (eveno n = Some x) ⟶ (x = (n mod 2 = 0))"
"∀x. (oddo n = Some x) ⟶ (x = (n mod 2 = 1))"
apply (induct n)
apply (subst eveno.simps, simp)
apply (subst oddo.simps, simp)
apply (subst eveno.simps, simp)
apply (clarsimp, arith)
apply (subst oddo.simps, simp)
apply (clarsimp, arith)
done
text ‹Termination might be shown. Analogous to @{command function}, proving termination might
be a non-trivial effort requiring involved semantic arguments. In this case we can
use plain natural number induction on the parameter.›
lemma eveno_oodo_defined:
"(eveno n = None) = False"
"(oddo n = None) = False"
apply (induct n )
apply (simp_all add: eveno.simps oddo.simps)
done
text ‹For this example, natural number induction on the parameter is also sufficient to
directly proof total correctness.›
lemma
"eveno' n = Some (n mod 2 = 0)"
"oddo' n = Some (n mod 2 = 1)"
apply (induct n)
apply (simp_all add: eveno'.simps oddo'.simps)
apply arith
apply arith
done
fixed_point (spec_monad_gfp) fac:: "int ⇒ (int, unit) res_monad"
where
"fac n = (if n = 0 then return 0 else fac (n - 1) >>= (λm. return (n * m)))"
apply simp_all
done
thm fac.induct
thm fac.simps
fixed_point (spec_monad_gfp) odd even:: "nat ⇒ (bool, unit) res_monad"
where
"even n = (if n = 0 then return True else odd (n - 1))"
| "odd n = (if n = 0 then return False else even (n - 1))"
apply simp_all
done
thm odd_even.induct
thm odd.simps
thm even.simps
fixed_point (spec_monad_gfp)
F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20
:: "unit ⇒ (unit, unit) res_monad"
where
"F0 p = F1 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F1 p = F2 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F2 p = F3 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F3 p = F4 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F4 p = F5 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F5 p = F6 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F6 p = F7 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F7 p = F8 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F8 p = F9 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F9 p = F10 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F10 p = F1 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F11 p = F2 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F12 p = F3 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F13 p = F4 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F14 p = F5 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F15 p = F6 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F16 p = F7 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F17 p = F8 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F18 p = F9 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F19 p = F10 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
| "F20 p = F10 p >>= F2 >>= F3 >>= F4 >>= F5 >>= F6"
apply simp_all
done
thm F0_F1_F2_F3_F4_F5_F6_F7_F8_F9_F10_F11_F12_F13_F14_F15_F16_F17_F18_F19_F20.induct
locale numbers =
fixes NN::nat
begin
fixed_point (option) X Y Z:: "nat ⇒ nat option"
where
"X 0 = X 0"
| "X 1 = Y 0"
| "X 2 = Z 0"
| "X 3 = Some NN"
| "X 4 = None"
| "X 5 = None"
| "X 6 = None"
| "X 7 = None"
| "X 8 = None"
| "X 9 = None"
| "X 10 = None"
| "X 11 = None"
| "X 12 = None"
| "X 13 = None"
| "X 14 = None"
| "Y n = Z n"
| "Z n = Z n"
proof -
fix X Y Z and n :: nat
have "n = 0 ∨ n = 1 ∨ n = 2 ∨ n = 3 ∨ n = 4 ∨ n = 5 ∨ n = 6 ∨ n = 7 ∨ n = 8 ∨ n = 9 ∨ n = 10 ∨
n = 11 ∨ n = 12 ∨ n = 13 ∨ n = 14 ∨ 14 < n"
by arith
then show "?unique_X X Y Z n"
by auto
qed simp_all
thm X_Y_Z.induct
thm X.simps
end
fixed_point (spec_monad_gfp)
H0 H1 H2 H3 H4 H5 H6 H7 H8 H9 H10 H11 H12 H13 H14 H15 H16 H17 H18 H19 H20
G0 G1 G2 G3 G4 G5 G6 G7 G8 G9 G10 G11 G12 G13 G14 G15 G16 G17 G18 G19 G20
:: "unit ⇒ (unit, unit) res_monad"
where
"H0 p = H1 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H1 p = H2 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H2 p = H3 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H3 p = H4 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H4 p = H5 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H5 p = H6 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H6 p = H7 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H7 p = H8 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H8 p = H9 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H9 p = H10 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H10 p = H1 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H11 p = H2 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H12 p = H3 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H13 p = H4 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H14 p = H5 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H15 p = H6 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H16 p = H7 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H17 p = H8 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H18 p = H9 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H19 p = H10 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "H20 p = H10 p >>= H2 >>= H3 >>= H4 >>= H5 >>= H6"
| "G0 p = G1 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G1 p = G2 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G2 p = G3 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G3 p = G4 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G4 p = G5 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G5 p = G6 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G6 p = G7 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G7 p = G8 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G8 p = G9 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G9 p = G10 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G10 p = G1 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G11 p = G2 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G12 p = G3 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G13 p = G4 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G14 p = G5 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G15 p = G6 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G16 p = G7 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G17 p = G8 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G18 p = G9 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G19 p = G10 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
| "G20 p = G10 p >>= G2 >>= G3 >>= G4 >>= G5 >>= G6"
apply simp_all
done
end