# Theory Ferrack

```(*  Title:      HOL/Decision_Procs/Ferrack.thy
Author:     Amine Chaieb
*)

theory Ferrack
imports Complex_Main Dense_Linear_Order DP_Library
"HOL-Library.Code_Target_Numeral"
begin

section ‹Quantifier elimination for ‹ℝ (0, 1, +, <)››

(*********************************************************************************)
(****                            SHADOW SYNTAX AND SEMANTICS                  ****)
(*********************************************************************************)

datatype (plugins del: size) num = C int | Bound nat | CN nat int num | Neg num | Add num num| Sub num num
| Mul int num

instantiation num :: size
begin

primrec size_num :: "num ⇒ nat"
where
"size_num (C c) = 1"
| "size_num (Bound n) = 1"
| "size_num (Neg a) = 1 + size_num a"
| "size_num (Add a b) = 1 + size_num a + size_num b"
| "size_num (Sub a b) = 3 + size_num a + size_num b"
| "size_num (Mul c a) = 1 + size_num a"
| "size_num (CN n c a) = 3 + size_num a "

instance ..

end

(* Semantics of numeral terms (num) *)
primrec Inum :: "real list ⇒ num ⇒ real"
where
"Inum bs (C c) = (real_of_int c)"
| "Inum bs (Bound n) = bs!n"
| "Inum bs (CN n c a) = (real_of_int c) * (bs!n) + (Inum bs a)"
| "Inum bs (Neg a) = -(Inum bs a)"
| "Inum bs (Add a b) = Inum bs a + Inum bs b"
| "Inum bs (Sub a b) = Inum bs a - Inum bs b"
| "Inum bs (Mul c a) = (real_of_int c) * Inum bs a"
(* FORMULAE *)
datatype (plugins del: size) fm  =
T| F| Lt num| Le num| Gt num| Ge num| Eq num| NEq num|
Not fm| And fm fm|  Or fm fm| Imp fm fm| Iff fm fm| E fm| A fm

instantiation fm :: size
begin

primrec size_fm :: "fm ⇒ nat"
where
"size_fm (Not p) = 1 + size_fm p"
| "size_fm (And p q) = 1 + size_fm p + size_fm q"
| "size_fm (Or p q) = 1 + size_fm p + size_fm q"
| "size_fm (Imp p q) = 3 + size_fm p + size_fm q"
| "size_fm (Iff p q) = 3 + 2 * (size_fm p + size_fm q)"
| "size_fm (E p) = 1 + size_fm p"
| "size_fm (A p) = 4 + size_fm p"
| "size_fm T = 1"
| "size_fm F = 1"
| "size_fm (Lt _) = 1"
| "size_fm (Le _) = 1"
| "size_fm (Gt _) = 1"
| "size_fm (Ge _) = 1"
| "size_fm (Eq _) = 1"
| "size_fm (NEq _) = 1"

instance ..

end

lemma size_fm_pos [simp]: "size p > 0" for p :: fm
by (induct p) simp_all

(* Semantics of formulae (fm) *)
primrec Ifm ::"real list ⇒ fm ⇒ bool"
where
"Ifm bs T = True"
| "Ifm bs F = False"
| "Ifm bs (Lt a) = (Inum bs a < 0)"
| "Ifm bs (Gt a) = (Inum bs a > 0)"
| "Ifm bs (Le a) = (Inum bs a ≤ 0)"
| "Ifm bs (Ge a) = (Inum bs a ≥ 0)"
| "Ifm bs (Eq a) = (Inum bs a = 0)"
| "Ifm bs (NEq a) = (Inum bs a ≠ 0)"
| "Ifm bs (Not p) = (¬ (Ifm bs p))"
| "Ifm bs (And p q) = (Ifm bs p ∧ Ifm bs q)"
| "Ifm bs (Or p q) = (Ifm bs p ∨ Ifm bs q)"
| "Ifm bs (Imp p q) = ((Ifm bs p) ⟶ (Ifm bs q))"
| "Ifm bs (Iff p q) = (Ifm bs p = Ifm bs q)"
| "Ifm bs (E p) = (∃x. Ifm (x#bs) p)"
| "Ifm bs (A p) = (∀x. Ifm (x#bs) p)"

lemma IfmLeSub: "⟦ Inum bs s = s' ; Inum bs t = t' ⟧ ⟹ Ifm bs (Le (Sub s t)) = (s' ≤ t')"
by simp

lemma IfmLtSub: "⟦ Inum bs s = s' ; Inum bs t = t' ⟧ ⟹ Ifm bs (Lt (Sub s t)) = (s' < t')"
by simp

lemma IfmEqSub: "⟦ Inum bs s = s' ; Inum bs t = t' ⟧ ⟹ Ifm bs (Eq (Sub s t)) = (s' = t')"
by simp

lemma IfmNot: " (Ifm bs p = P) ⟹ (Ifm bs (Not p) = (¬P))"
by simp

lemma IfmAnd: " ⟦ Ifm bs p = P ; Ifm bs q = Q⟧ ⟹ (Ifm bs (And p q) = (P ∧ Q))"
by simp

lemma IfmOr: " ⟦ Ifm bs p = P ; Ifm bs q = Q⟧ ⟹ (Ifm bs (Or p q) = (P ∨ Q))"
by simp

lemma IfmImp: " ⟦ Ifm bs p = P ; Ifm bs q = Q⟧ ⟹ (Ifm bs (Imp p q) = (P ⟶ Q))"
by simp

lemma IfmIff: " ⟦ Ifm bs p = P ; Ifm bs q = Q⟧ ⟹ (Ifm bs (Iff p q) = (P = Q))"
by simp

lemma IfmE: " (!! x. Ifm (x#bs) p = P x) ⟹ (Ifm bs (E p) = (∃x. P x))"
by simp

lemma IfmA: " (!! x. Ifm (x#bs) p = P x) ⟹ (Ifm bs (A p) = (∀x. P x))"
by simp

fun not:: "fm ⇒ fm"
where
"not (Not p) = p"
| "not T = F"
| "not F = T"
| "not p = Not p"

lemma not[simp]: "Ifm bs (not p) = Ifm bs (Not p)"
by (cases p) auto

definition conj :: "fm ⇒ fm ⇒ fm"
where
"conj p q =
(if p = F ∨ q = F then F
else if p = T then q
else if q = T then p
else if p = q then p else And p q)"

lemma conj[simp]: "Ifm bs (conj p q) = Ifm bs (And p q)"
by (cases "p = F ∨ q = F", simp_all add: conj_def) (cases p, simp_all)

definition disj :: "fm ⇒ fm ⇒ fm"
where
"disj p q =
(if p = T ∨ q = T then T
else if p = F then q
else if q = F then p
else if p = q then p else Or p q)"

lemma disj[simp]: "Ifm bs (disj p q) = Ifm bs (Or p q)"
by (cases "p = T ∨ q = T", simp_all add: disj_def) (cases p, simp_all)

definition imp :: "fm ⇒ fm ⇒ fm"
where
"imp p q =
(if p = F ∨ q = T ∨ p = q then T
else if p = T then q
else if q = F then not p
else Imp p q)"

lemma imp[simp]: "Ifm bs (imp p q) = Ifm bs (Imp p q)"
by (cases "p = F ∨ q = T") (simp_all add: imp_def)

definition iff :: "fm ⇒ fm ⇒ fm"
where
"iff p q =
(if p = q then T
else if p = Not q ∨ Not p = q then F
else if p = F then not q
else if q = F then not p
else if p = T then q
else if q = T then p
else Iff p q)"

lemma iff[simp]: "Ifm bs (iff p q) = Ifm bs (Iff p q)"
by (unfold iff_def, cases "p = q", simp, cases "p = Not q", simp) (cases "Not p = q", auto)

lemma conj_simps:
"conj F Q = F"
"conj P F = F"
"conj T Q = Q"
"conj P T = P"
"conj P P = P"
"P ≠ T ⟹ P ≠ F ⟹ Q ≠ T ⟹ Q ≠ F ⟹ P ≠ Q ⟹ conj P Q = And P Q"

lemma disj_simps:
"disj T Q = T"
"disj P T = T"
"disj F Q = Q"
"disj P F = P"
"disj P P = P"
"P ≠ T ⟹ P ≠ F ⟹ Q ≠ T ⟹ Q ≠ F ⟹ P ≠ Q ⟹ disj P Q = Or P Q"

lemma imp_simps:
"imp F Q = T"
"imp P T = T"
"imp T Q = Q"
"imp P F = not P"
"imp P P = T"
"P ≠ T ⟹ P ≠ F ⟹ P ≠ Q ⟹ Q ≠ T ⟹ Q ≠ F ⟹ imp P Q = Imp P Q"

lemma trivNot: "p ≠ Not p" "Not p ≠ p"
by (induct p) auto

lemma iff_simps:
"iff p p = T"
"iff p (Not p) = F"
"iff (Not p) p = F"
"iff p F = not p"
"iff F p = not p"
"p ≠ Not T ⟹ iff T p = p"
"p≠ Not T ⟹ iff p T = p"
"p≠q ⟹ p≠ Not q ⟹ q≠ Not p ⟹ p≠ F ⟹ q≠ F ⟹ p ≠ T ⟹ q ≠ T ⟹ iff p q = Iff p q"
using trivNot
by (simp_all add: iff_def, cases p, auto)

(* Quantifier freeness *)
fun qfree:: "fm ⇒ bool"
where
"qfree (E p) = False"
| "qfree (A p) = False"
| "qfree (Not p) = qfree p"
| "qfree (And p q) = (qfree p ∧ qfree q)"
| "qfree (Or  p q) = (qfree p ∧ qfree q)"
| "qfree (Imp p q) = (qfree p ∧ qfree q)"
| "qfree (Iff p q) = (qfree p ∧ qfree q)"
| "qfree p = True"

(* Boundedness and substitution *)
primrec numbound0:: "num ⇒ bool" (* a num is INDEPENDENT of Bound 0 *)
where
"numbound0 (C c) = True"
| "numbound0 (Bound n) = (n > 0)"
| "numbound0 (CN n c a) = (n ≠ 0 ∧ numbound0 a)"
| "numbound0 (Neg a) = numbound0 a"
| "numbound0 (Add a b) = (numbound0 a ∧ numbound0 b)"
| "numbound0 (Sub a b) = (numbound0 a ∧ numbound0 b)"
| "numbound0 (Mul i a) = numbound0 a"

lemma numbound0_I:
assumes nb: "numbound0 a"
shows "Inum (b#bs) a = Inum (b'#bs) a"
using nb by (induct a) simp_all

primrec bound0:: "fm ⇒ bool" (* A Formula is independent of Bound 0 *)
where
"bound0 T = True"
| "bound0 F = True"
| "bound0 (Lt a) = numbound0 a"
| "bound0 (Le a) = numbound0 a"
| "bound0 (Gt a) = numbound0 a"
| "bound0 (Ge a) = numbound0 a"
| "bound0 (Eq a) = numbound0 a"
| "bound0 (NEq a) = numbound0 a"
| "bound0 (Not p) = bound0 p"
| "bound0 (And p q) = (bound0 p ∧ bound0 q)"
| "bound0 (Or p q) = (bound0 p ∧ bound0 q)"
| "bound0 (Imp p q) = ((bound0 p) ∧ (bound0 q))"
| "bound0 (Iff p q) = (bound0 p ∧ bound0 q)"
| "bound0 (E p) = False"
| "bound0 (A p) = False"

lemma bound0_I:
assumes bp: "bound0 p"
shows "Ifm (b#bs) p = Ifm (b'#bs) p"
using bp numbound0_I[where b="b" and bs="bs" and b'="b'"]
by (induct p) auto

lemma not_qf[simp]: "qfree p ⟹ qfree (not p)"
by (cases p) auto

lemma not_bn[simp]: "bound0 p ⟹ bound0 (not p)"
by (cases p) auto

lemma conj_qf[simp]: "⟦qfree p ; qfree q⟧ ⟹ qfree (conj p q)"
using conj_def by auto
lemma conj_nb[simp]: "⟦bound0 p ; bound0 q⟧ ⟹ bound0 (conj p q)"
using conj_def by auto

lemma disj_qf[simp]: "⟦qfree p ; qfree q⟧ ⟹ qfree (disj p q)"
using disj_def by auto
lemma disj_nb[simp]: "⟦bound0 p ; bound0 q⟧ ⟹ bound0 (disj p q)"
using disj_def by auto

lemma imp_qf[simp]: "⟦qfree p ; qfree q⟧ ⟹ qfree (imp p q)"
using imp_def by (cases "p=F ∨ q=T",simp_all add: imp_def)
lemma imp_nb[simp]: "⟦bound0 p ; bound0 q⟧ ⟹ bound0 (imp p q)"
using imp_def by (cases "p=F ∨ q=T ∨ p=q",simp_all add: imp_def)

lemma iff_qf[simp]: "⟦qfree p ; qfree q⟧ ⟹ qfree (iff p q)"
unfolding iff_def by (cases "p = q") auto
lemma iff_nb[simp]: "⟦bound0 p ; bound0 q⟧ ⟹ bound0 (iff p q)"
using iff_def unfolding iff_def by (cases "p = q") auto

fun decrnum:: "num ⇒ num"
where
"decrnum (Bound n) = Bound (n - 1)"
| "decrnum (Neg a) = Neg (decrnum a)"
| "decrnum (Sub a b) = Sub (decrnum a) (decrnum b)"
| "decrnum (Mul c a) = Mul c (decrnum a)"
| "decrnum (CN n c a) = CN (n - 1) c (decrnum a)"
| "decrnum a = a"

fun decr :: "fm ⇒ fm"
where
"decr (Lt a) = Lt (decrnum a)"
| "decr (Le a) = Le (decrnum a)"
| "decr (Gt a) = Gt (decrnum a)"
| "decr (Ge a) = Ge (decrnum a)"
| "decr (Eq a) = Eq (decrnum a)"
| "decr (NEq a) = NEq (decrnum a)"
| "decr (Not p) = Not (decr p)"
| "decr (And p q) = conj (decr p) (decr q)"
| "decr (Or p q) = disj (decr p) (decr q)"
| "decr (Imp p q) = imp (decr p) (decr q)"
| "decr (Iff p q) = iff (decr p) (decr q)"
| "decr p = p"

lemma decrnum:
assumes nb: "numbound0 t"
shows "Inum (x # bs) t = Inum bs (decrnum t)"
using nb by (induct t rule: decrnum.induct) simp_all

lemma decr:
assumes nb: "bound0 p"
shows "Ifm (x # bs) p = Ifm bs (decr p)"
using nb by (induct p rule: decr.induct) (simp_all add: decrnum)

lemma decr_qf: "bound0 p ⟹ qfree (decr p)"
by (induct p) simp_all

fun isatom :: "fm ⇒ bool" (* test for atomicity *)
where
"isatom T = True"
| "isatom F = True"
| "isatom (Lt a) = True"
| "isatom (Le a) = True"
| "isatom (Gt a) = True"
| "isatom (Ge a) = True"
| "isatom (Eq a) = True"
| "isatom (NEq a) = True"
| "isatom p = False"

lemma bound0_qf: "bound0 p ⟹ qfree p"
by (induct p) simp_all

definition djf :: "('a ⇒ fm) ⇒ 'a ⇒ fm ⇒ fm"
where
"djf f p q =
(if q = T then T
else if q = F then f p
else (let fp = f p in case fp of T ⇒ T | F ⇒ q | _ ⇒ Or (f p) q))"

definition evaldjf :: "('a ⇒ fm) ⇒ 'a list ⇒ fm"
where "evaldjf f ps = foldr (djf f) ps F"

lemma djf_Or: "Ifm bs (djf f p q) = Ifm bs (Or (f p) q)"
by (cases "q = T", simp add: djf_def, cases "q = F", simp add: djf_def)
(cases "f p", simp_all add: Let_def djf_def)

lemma djf_simps:
"djf f p T = T"
"djf f p F = f p"
"q ≠ T ⟹ q ≠ F ⟹ djf f p q = (let fp = f p in case fp of T ⇒ T | F ⇒ q | _ ⇒ Or (f p) q)"

lemma evaldjf_ex: "Ifm bs (evaldjf f ps) ⟷ (∃p ∈ set ps. Ifm bs (f p))"
by (induct ps) (simp_all add: evaldjf_def djf_Or)

lemma evaldjf_bound0:
assumes nb: "∀x∈ set xs. bound0 (f x)"
shows "bound0 (evaldjf f xs)"
using nb by (induct xs, auto simp add: evaldjf_def djf_def Let_def) (case_tac "f a", auto)

lemma evaldjf_qf:
assumes nb: "∀x∈ set xs. qfree (f x)"
shows "qfree (evaldjf f xs)"
using nb by (induct xs, auto simp add: evaldjf_def djf_def Let_def) (case_tac "f a", auto)

fun disjuncts :: "fm ⇒ fm list"
where
"disjuncts (Or p q) = disjuncts p @ disjuncts q"
| "disjuncts F = []"
| "disjuncts p = [p]"

lemma disjuncts: "(∃q∈ set (disjuncts p). Ifm bs q) = Ifm bs p"
by (induct p rule: disjuncts.induct) auto

lemma disjuncts_nb: "bound0 p ⟹ ∀q∈ set (disjuncts p). bound0 q"
proof -
assume nb: "bound0 p"
then have "list_all bound0 (disjuncts p)"
by (induct p rule: disjuncts.induct) auto
then show ?thesis
by (simp only: list_all_iff)
qed

lemma disjuncts_qf: "qfree p ⟹ ∀q∈ set (disjuncts p). qfree q"
proof -
assume qf: "qfree p"
then have "list_all qfree (disjuncts p)"
by (induct p rule: disjuncts.induct) auto
then show ?thesis
by (simp only: list_all_iff)
qed

definition DJ :: "(fm ⇒ fm) ⇒ fm ⇒ fm"
where "DJ f p = evaldjf f (disjuncts p)"

lemma DJ:
assumes fdj: "∀p q. Ifm bs (f (Or p q)) = Ifm bs (Or (f p) (f q))"
and fF: "f F = F"
shows "Ifm bs (DJ f p) = Ifm bs (f p)"
proof -
have "Ifm bs (DJ f p) = (∃q ∈ set (disjuncts p). Ifm bs (f q))"
also have "… = Ifm bs (f p)"
using fdj fF by (induct p rule: disjuncts.induct) auto
finally show ?thesis .
qed

lemma DJ_qf:
assumes fqf: "∀p. qfree p ⟶ qfree (f p)"
shows "∀p. qfree p ⟶ qfree (DJ f p) "
proof clarify
fix p
assume qf: "qfree p"
have th: "DJ f p = evaldjf f (disjuncts p)"
from disjuncts_qf[OF qf] have "∀q∈ set (disjuncts p). qfree q" .
with fqf have th':"∀q∈ set (disjuncts p). qfree (f q)"
by blast
from evaldjf_qf[OF th'] th show "qfree (DJ f p)"
by simp
qed

lemma DJ_qe:
assumes qe: "∀bs p. qfree p ⟶ qfree (qe p) ∧ (Ifm bs (qe p) = Ifm bs (E p))"
shows "∀bs p. qfree p ⟶ qfree (DJ qe p) ∧ (Ifm bs ((DJ qe p)) = Ifm bs (E p))"
proof clarify
fix p :: fm
fix bs
assume qf: "qfree p"
from qe have qth: "∀p. qfree p ⟶ qfree (qe p)"
by blast
from DJ_qf[OF qth] qf have qfth: "qfree (DJ qe p)"
by auto
have "Ifm bs (DJ qe p) ⟷ (∃q∈ set (disjuncts p). Ifm bs (qe q))"
also have "… ⟷ (∃q ∈ set(disjuncts p). Ifm bs (E q))"
using qe disjuncts_qf[OF qf] by auto
also have "… = Ifm bs (E p)"
by (induct p rule: disjuncts.induct) auto
finally show "qfree (DJ qe p) ∧ Ifm bs (DJ qe p) = Ifm bs (E p)"
using qfth by blast
qed

(* Simplification *)

fun maxcoeff:: "num ⇒ int"
where
"maxcoeff (C i) = ¦i¦"
| "maxcoeff (CN n c t) = max ¦c¦ (maxcoeff t)"
| "maxcoeff t = 1"

lemma maxcoeff_pos: "maxcoeff t ≥ 0"
by (induct t rule: maxcoeff.induct, auto)

fun numgcdh:: "num ⇒ int ⇒ int"
where
"numgcdh (C i) = (λg. gcd i g)"
| "numgcdh (CN n c t) = (λg. gcd c (numgcdh t g))"
| "numgcdh t = (λg. 1)"

definition numgcd :: "num ⇒ int"
where "numgcd t = numgcdh t (maxcoeff t)"

fun reducecoeffh:: "num ⇒ int ⇒ num"
where
"reducecoeffh (C i) = (λg. C (i div g))"
| "reducecoeffh (CN n c t) = (λg. CN n (c div g) (reducecoeffh t g))"
| "reducecoeffh t = (λg. t)"

definition reducecoeff :: "num ⇒ num"
where
"reducecoeff t =
(let g = numgcd t
in if g = 0 then C 0 else if g = 1 then t else reducecoeffh t g)"

fun dvdnumcoeff:: "num ⇒ int ⇒ bool"
where
"dvdnumcoeff (C i) = (λg. g dvd i)"
| "dvdnumcoeff (CN n c t) = (λg. g dvd c ∧ dvdnumcoeff t g)"
| "dvdnumcoeff t = (λg. False)"

lemma dvdnumcoeff_trans:
assumes gdg: "g dvd g'"
and dgt':"dvdnumcoeff t g'"
shows "dvdnumcoeff t g"
using dgt' gdg
by (induct t rule: dvdnumcoeff.induct) (simp_all add: gdg dvd_trans[OF gdg])

lemma natabs0: "nat ¦x¦ = 0 ⟷ x = 0"
by arith

lemma numgcd0:
assumes g0: "numgcd t = 0"
shows "Inum bs t = 0"
using g0[simplified numgcd_def]
by (induct t rule: numgcdh.induct) (auto simp add: natabs0 maxcoeff_pos max.absorb2)

lemma numgcdh_pos:
assumes gp: "g ≥ 0"
shows "numgcdh t g ≥ 0"
using gp by (induct t rule: numgcdh.induct) auto

lemma numgcd_pos: "numgcd t ≥0"
by (simp add: numgcd_def numgcdh_pos maxcoeff_pos)

lemma reducecoeffh:
assumes gt: "dvdnumcoeff t g"
and gp: "g > 0"
shows "real_of_int g *(Inum bs (reducecoeffh t g)) = Inum bs t"
using gt
proof (induct t rule: reducecoeffh.induct)
case (1 i)
then have gd: "g dvd i"
by simp
with assms show ?case
next
case (2 n c t)
then have gd: "g dvd c"
by simp
from assms 2 show ?case
by (simp add: real_of_int_div[OF gd] algebra_simps)
qed (auto simp add: numgcd_def gp)

fun ismaxcoeff:: "num ⇒ int ⇒ bool"
where
"ismaxcoeff (C i) = (λx. ¦i¦ ≤ x)"
| "ismaxcoeff (CN n c t) = (λx. ¦c¦ ≤ x ∧ ismaxcoeff t x)"
| "ismaxcoeff t = (λx. True)"

lemma ismaxcoeff_mono: "ismaxcoeff t c ⟹ c ≤ c' ⟹ ismaxcoeff t c'"
by (induct t rule: ismaxcoeff.induct) auto

lemma maxcoeff_ismaxcoeff: "ismaxcoeff t (maxcoeff t)"
proof (induct t rule: maxcoeff.induct)
case (2 n c t)
then have H:"ismaxcoeff t (maxcoeff t)" .
have thh: "maxcoeff t ≤ max ¦c¦ (maxcoeff t)"
by simp
from ismaxcoeff_mono[OF H thh] show ?case
by simp
qed simp_all

lemma zgcd_gt1:
"¦i¦ > 1 ∧ ¦j¦ > 1 ∨ ¦i¦ = 0 ∧ ¦j¦ > 1 ∨ ¦i¦ > 1 ∧ ¦j¦ = 0"
if "gcd i j > 1" for i j :: int
proof -
have "¦k¦ ≤ 1 ⟷ k = - 1 ∨ k = 0 ∨ k = 1" for k :: int
by auto
with that show ?thesis
qed

lemma numgcdh0:"numgcdh t m = 0 ⟹  m =0"
by (induct t rule: numgcdh.induct) auto

lemma dvdnumcoeff_aux:
assumes "ismaxcoeff t m"
and mp: "m ≥ 0"
and "numgcdh t m > 1"
shows "dvdnumcoeff t (numgcdh t m)"
using assms
proof (induct t rule: numgcdh.induct)
case (2 n c t)
let ?g = "numgcdh t m"
from 2 have th: "gcd c ?g > 1"
by simp
from zgcd_gt1[OF th] numgcdh_pos[OF mp, where t="t"]
consider "¦c¦ > 1" "?g > 1" | "¦c¦ = 0" "?g > 1" | "?g = 0"
by auto
then show ?case
proof cases
case 1
with 2 have th: "dvdnumcoeff t ?g"
by simp
have th': "gcd c ?g dvd ?g"
by simp
from dvdnumcoeff_trans[OF th' th] show ?thesis
by simp
next
case "2'": 2
with 2 have th: "dvdnumcoeff t ?g"
by simp
have th': "gcd c ?g dvd ?g"
by simp
from dvdnumcoeff_trans[OF th' th] show ?thesis
by simp
next
case 3
then have "m = 0" by (rule numgcdh0)
with 2 3 show ?thesis by simp
qed
qed auto

lemma dvdnumcoeff_aux2:
assumes "numgcd t > 1"
shows "dvdnumcoeff t (numgcd t) ∧ numgcd t > 0"
using assms
let ?mc = "maxcoeff t"
let ?g = "numgcdh t ?mc"
have th1: "ismaxcoeff t ?mc"
by (rule maxcoeff_ismaxcoeff)
have th2: "?mc ≥ 0"
by (rule maxcoeff_pos)
assume H: "numgcdh t ?mc > 1"
from dvdnumcoeff_aux[OF th1 th2 H] show "dvdnumcoeff t ?g" .
qed

lemma reducecoeff: "real_of_int (numgcd t) * (Inum bs (reducecoeff t)) = Inum bs t"
proof -
let ?g = "numgcd t"
have "?g ≥ 0"
then consider "?g = 0" | "?g = 1" | "?g > 1" by atomize_elim auto
then show ?thesis
proof cases
case 1
then show ?thesis by (simp add: numgcd0)
next
case 2
then show ?thesis by (simp add: reducecoeff_def)
next
case g1: 3
from dvdnumcoeff_aux2[OF g1] have th1: "dvdnumcoeff t ?g" and g0: "?g > 0"
by blast+
from reducecoeffh[OF th1 g0, where bs="bs"] g1 show ?thesis
qed
qed

lemma reducecoeffh_numbound0: "numbound0 t ⟹ numbound0 (reducecoeffh t g)"
by (induct t rule: reducecoeffh.induct) auto

lemma reducecoeff_numbound0: "numbound0 t ⟹ numbound0 (reducecoeff t)"
using reducecoeffh_numbound0 by (simp add: reducecoeff_def Let_def)

fun numadd:: "num ⇒ num ⇒ num"
where
"numadd (CN n1 c1 r1) (CN n2 c2 r2) =
(if n1 = n2 then
(let c = c1 + c2
in (if c = 0 then numadd r1 r2 else CN n1 c (numadd r1 r2)))
else if n1 ≤ n2 then (CN n1 c1 (numadd r1 (CN n2 c2 r2)))
else (CN n2 c2 (numadd (CN n1 c1 r1) r2)))"
| "numadd (CN n1 c1 r1) t = CN n1 c1 (numadd r1 t)"
| "numadd t (CN n2 c2 r2) = CN n2 c2 (numadd t r2)"
| "numadd (C b1) (C b2) = C (b1 + b2)"

lemma numadd_nb [simp]: "numbound0 t ⟹ numbound0 s ⟹ numbound0 (numadd t s)"

fun nummul:: "num ⇒ int ⇒ num"
where
"nummul (C j) = (λi. C (i * j))"
| "nummul (CN n c a) = (λi. CN n (i * c) (nummul a i))"
| "nummul t = (λi. Mul i t)"

lemma nummul[simp]: "⋀i. Inum bs (nummul t i) = Inum bs (Mul i t)"
by (induct t rule: nummul.induct) (auto simp add: algebra_simps)

lemma nummul_nb[simp]: "⋀i. numbound0 t ⟹ numbound0 (nummul t i)"
by (induct t rule: nummul.induct) auto

definition numneg :: "num ⇒ num"
where "numneg t = nummul t (- 1)"

definition numsub :: "num ⇒ num ⇒ num"
where "numsub s t = (if s = t then C 0 else numadd s (numneg t))"

lemma numneg[simp]: "Inum bs (numneg t) = Inum bs (Neg t)"
using numneg_def by simp

lemma numneg_nb[simp]: "numbound0 t ⟹ numbound0 (numneg t)"
using numneg_def by simp

lemma numsub[simp]: "Inum bs (numsub a b) = Inum bs (Sub a b)"
using numsub_def by simp

lemma numsub_nb[simp]: "⟦ numbound0 t ; numbound0 s⟧ ⟹ numbound0 (numsub t s)"
using numsub_def by simp

primrec simpnum:: "num ⇒ num"
where
"simpnum (C j) = C j"
| "simpnum (Bound n) = CN n 1 (C 0)"
| "simpnum (Neg t) = numneg (simpnum t)"
| "simpnum (Sub t s) = numsub (simpnum t) (simpnum s)"
| "simpnum (Mul i t) = (if i = 0 then C 0 else nummul (simpnum t) i)"
| "simpnum (CN n c t) = (if c = 0 then simpnum t else numadd (CN n c (C 0)) (simpnum t))"

lemma simpnum_ci[simp]: "Inum bs (simpnum t) = Inum bs t"
by (induct t) simp_all

lemma simpnum_numbound0[simp]: "numbound0 t ⟹ numbound0 (simpnum t)"
by (induct t) simp_all

fun nozerocoeff:: "num ⇒ bool"
where
"nozerocoeff (C c) = True"
| "nozerocoeff (CN n c t) = (c ≠ 0 ∧ nozerocoeff t)"
| "nozerocoeff t = True"

lemma numadd_nz : "nozerocoeff a ⟹ nozerocoeff b ⟹ nozerocoeff (numadd a b)"

lemma nummul_nz : "⋀i. i≠0 ⟹ nozerocoeff a ⟹ nozerocoeff (nummul a i)"

lemma numneg_nz : "nozerocoeff a ⟹ nozerocoeff (numneg a)"

lemma numsub_nz: "nozerocoeff a ⟹ nozerocoeff b ⟹ nozerocoeff (numsub a b)"

lemma simpnum_nz: "nozerocoeff (simpnum t)"

lemma maxcoeff_nz: "nozerocoeff t ⟹ maxcoeff t = 0 ⟹ t = C 0"
by (induction t rule: maxcoeff.induct) auto

lemma numgcd_nz:
assumes nz: "nozerocoeff t"
and g0: "numgcd t = 0"
shows "t = C 0"
proof -
from g0 have th:"numgcdh t (maxcoeff t) = 0"
from numgcdh0[OF th] have th:"maxcoeff t = 0" .
from maxcoeff_nz[OF nz th] show ?thesis .
qed

definition simp_num_pair :: "(num × int) ⇒ num × int"
where
"simp_num_pair =
(λ(t,n).
(if n = 0 then (C 0, 0)
else
(let t' = simpnum t ; g = numgcd t' in
if g > 1 then
(let g' = gcd n g
in if g' = 1 then (t', n) else (reducecoeffh t' g', n div g'))
else (t', n))))"

lemma simp_num_pair_ci:
shows "((λ(t,n). Inum bs t / real_of_int n) (simp_num_pair (t,n))) =
((λ(t,n). Inum bs t / real_of_int n) (t, n))"
(is "?lhs = ?rhs")
proof -
let ?t' = "simpnum t"
let ?g = "numgcd ?t'"
let ?g' = "gcd n ?g"
show ?thesis
proof (cases "n = 0")
case True
then show ?thesis
next
case nnz: False
show ?thesis
proof (cases "?g > 1")
case False
then show ?thesis by (simp add: Let_def simp_num_pair_def)
next
case g1: True
then have g0: "?g > 0"
by simp
from g1 nnz have gp0: "?g' ≠ 0"
by simp
then have g'p: "?g' > 0"
using gcd_ge_0_int[where x="n" and y="numgcd ?t'"] by arith
then consider "?g' = 1" | "?g' > 1" by arith
then show ?thesis
proof cases
case 1
then show ?thesis
next
case g'1: 2
from dvdnumcoeff_aux2[OF g1] have th1: "dvdnumcoeff ?t' ?g" ..
let ?tt = "reducecoeffh ?t' ?g'"
let ?t = "Inum bs ?tt"
have gpdg: "?g' dvd ?g" by simp
have gpdd: "?g' dvd n" by simp
have gpdgp: "?g' dvd ?g'" by simp
from reducecoeffh[OF dvdnumcoeff_trans[OF gpdg th1] g'p]
have th2:"real_of_int ?g' * ?t = Inum bs ?t'"
by simp
from g1 g'1 have "?lhs = ?t / real_of_int (n div ?g')"
also have "… = (real_of_int ?g' * ?t) / (real_of_int ?g' * (real_of_int (n div ?g')))"
by simp
also have "… = (Inum bs ?t' / real_of_int n)"
using real_of_int_div[OF gpdd] th2 gp0 by simp
finally have "?lhs = Inum bs t / real_of_int n"
by simp
then show ?thesis
qed
qed
qed
qed

lemma simp_num_pair_l:
assumes tnb: "numbound0 t"
and np: "n > 0"
and tn: "simp_num_pair (t, n) = (t', n')"
shows "numbound0 t' ∧ n' > 0"
proof -
let ?t' = "simpnum t"
let ?g = "numgcd ?t'"
let ?g' = "gcd n ?g"
show ?thesis
proof (cases "n = 0")
case True
then show ?thesis
using assms by (simp add: Let_def simp_num_pair_def)
next
case nnz: False
show ?thesis
proof (cases "?g > 1")
case False
then show ?thesis
using assms by (auto simp add: Let_def simp_num_pair_def)
next
case g1: True
then have g0: "?g > 0" by simp
from g1 nnz have gp0: "?g' ≠ 0" by simp
then have g'p: "?g' > 0" using gcd_ge_0_int[where x="n" and y="numgcd ?t'"]
by arith
then consider "?g'= 1" | "?g' > 1" by arith
then show ?thesis
proof cases
case 1
then show ?thesis
using assms g1 by (auto simp add: Let_def simp_num_pair_def)
next
case g'1: 2
have gpdg: "?g' dvd ?g" by simp
have gpdd: "?g' dvd n" by simp
have gpdgp: "?g' dvd ?g'" by simp
from zdvd_imp_le[OF gpdd np] have g'n: "?g' ≤ n" .
from zdiv_mono1[OF g'n g'p, simplified div_self[OF gp0]] have "n div ?g' > 0"
by simp
then show ?thesis
using assms g1 g'1
by (auto simp add: simp_num_pair_def Let_def reducecoeffh_numbound0)
qed
qed
qed
qed

fun simpfm :: "fm ⇒ fm"
where
"simpfm (And p q) = conj (simpfm p) (simpfm q)"
| "simpfm (Or p q) = disj (simpfm p) (simpfm q)"
| "simpfm (Imp p q) = imp (simpfm p) (simpfm q)"
| "simpfm (Iff p q) = iff (simpfm p) (simpfm q)"
| "simpfm (Not p) = not (simpfm p)"
| "simpfm (Lt a) = (let a' = simpnum a in case a' of C v ⇒ if (v < 0) then T else F | _ ⇒ Lt a')"
| "simpfm (Le a) = (let a' = simpnum a in case a' of C v ⇒ if (v ≤ 0)  then T else F | _ ⇒ Le a')"
| "simpfm (Gt a) = (let a' = simpnum a in case a' of C v ⇒ if (v > 0)  then T else F | _ ⇒ Gt a')"
| "simpfm (Ge a) = (let a' = simpnum a in case a' of C v ⇒ if (v ≥ 0)  then T else F | _ ⇒ Ge a')"
| "simpfm (Eq a) = (let a' = simpnum a in case a' of C v ⇒ if (v = 0)  then T else F | _ ⇒ Eq a')"
| "simpfm (NEq a) = (let a' = simpnum a in case a' of C v ⇒ if (v ≠ 0)  then T else F | _ ⇒ NEq a')"
| "simpfm p = p"

lemma simpfm: "Ifm bs (simpfm p) = Ifm bs p"
proof (induct p rule: simpfm.induct)
case (6 a)
let ?sa = "simpnum a"
from simpnum_ci have sa: "Inum bs ?sa = Inum bs a"
by simp
consider v where "?sa = C v" | "¬ (∃v. ?sa = C v)" by blast
then show ?case
proof cases
case 1
then show ?thesis using sa by simp
next
case 2
then show ?thesis using sa by (cases ?sa) (simp_all add: Let_def)
qed
next
case (7 a)
let ?sa = "simpnum a"
from simpnum_ci have sa: "Inum bs ?sa = Inum bs a"
by simp
consider v where "?sa = C v" | "¬ (∃v. ?sa = C v)" by blast
then show ?case
proof cases
case 1
then show ?thesis using sa by simp
next
case 2
then show ?thesis using sa by (cases ?sa) (simp_all add: Let_def)
qed
next
case (8 a)
let ?sa = "simpnum a"
from simpnum_ci have sa: "Inum bs ?sa = Inum bs a"
by simp
consider v where "?sa = C v" | "¬ (∃v. ?sa = C v)" by blast
then show ?case
proof cases
case 1
then show ?thesis using sa by simp
next
case 2
then show ?thesis using sa by (cases ?sa) (simp_all add: Let_def)
qed
next
case (9 a)
let ?sa = "simpnum a"
from simpnum_ci have sa: "Inum bs ?sa = Inum bs a"
by simp
consider v where "?sa = C v" | "¬ (∃v. ?sa = C v)" by blast
then show ?case
proof cases
case 1
then show ?thesis using sa by simp
next
case 2
then show ?thesis using sa by (cases ?sa) (simp_all add: Let_def)
qed
next
case (10 a)
let ?sa = "simpnum a"
from simpnum_ci have sa: "Inum bs ?sa = Inum bs a"
by simp
consider v where "?sa = C v" | "¬ (∃v. ?sa = C v)" by blast
then show ?case
proof cases
case 1
then show ?thesis using sa by simp
next
case 2
then show ?thesis using sa by (cases ?sa) (simp_all add: Let_def)
qed
next
case (11 a)
let ?sa = "simpnum a"
from simpnum_ci have sa: "Inum bs ?sa = Inum bs a"
by simp
consider v where "?sa = C v" | "¬ (∃v. ?sa = C v)" by blast
then show ?case
proof cases
case 1
then show ?thesis using sa by simp
next
case 2
then show ?thesis using sa by (cases ?sa) (simp_all add: Let_def)
qed
qed (induct p rule: simpfm.induct, simp_all)

lemma simpfm_bound0: "bound0 p ⟹ bound0 (simpfm p)"
proof (induct p rule: simpfm.induct)
case (6 a)
then have nb: "numbound0 a" by simp
then have "numbound0 (simpnum a)" by (simp only: simpnum_numbound0[OF nb])
then show ?case by (cases "simpnum a") (auto simp add: Let_def)
next
case (7 a)
then have nb: "numbound0 a" by simp
then have "numbound0 (simpnum a)" by (simp only: simpnum_numbound0[OF nb])
then show ?case by (cases "simpnum a") (auto simp add: Let_def)
next
case (8 a)
then have nb: "numbound0 a" by simp
then have "numbound0 (simpnum a)" by (simp only: simpnum_numbound0[OF nb])
then show ?case by (cases "simpnum a") (auto simp add: Let_def)
next
case (9 a)
then have nb: "numbound0 a" by simp
then have "numbound0 (simpnum a)" by (simp only: simpnum_numbound0[OF nb])
then show ?case by (cases "simpnum a") (auto simp add: Let_def)
next
case (10 a)
then have nb: "numbound0 a" by simp
then have "numbound0 (simpnum a)" by (simp only: simpnum_numbound0[OF nb])
then show ?case by (cases "simpnum a") (auto simp add: Let_def)
next
case (11 a)
then have nb: "numbound0 a" by simp
then have "numbound0 (simpnum a)" by (simp only: simpnum_numbound0[OF nb])
then show ?case by (cases "simpnum a") (auto simp add: Let_def)
qed (auto simp add: disj_def imp_def iff_def conj_def)

lemma simpfm_qf: "qfree p ⟹ qfree (simpfm p)"
apply (induct p rule: simpfm.induct)
apply (case_tac "simpnum a", auto)+
done

fun prep :: "fm ⇒ fm"
where
"prep (E T) = T"
| "prep (E F) = F"
| "prep (E (Or p q)) = disj (prep (E p)) (prep (E q))"
| "prep (E (Imp p q)) = disj (prep (E (Not p))) (prep (E q))"
| "prep (E (Iff p q)) = disj (prep (E (And p q))) (prep (E (And (Not p) (Not q))))"
| "prep (E (Not (And p q))) = disj (prep (E (Not p))) (prep (E(Not q)))"
| "prep (E (Not (Imp p q))) = prep (E (And p (Not q)))"
| "prep (E (Not (Iff p q))) = disj (prep (E (And p (Not q)))) (prep (E(And (Not p) q)))"
| "prep (E p) = E (prep p)"
| "prep (A (And p q)) = conj (prep (A p)) (prep (A q))"
| "prep (A p) = prep (Not (E (Not p)))"
| "prep (Not (Not p)) = prep p"
| "prep (Not (And p q)) = disj (prep (Not p)) (prep (Not q))"
| "prep (Not (A p)) = prep (E (Not p))"
| "prep (Not (Or p q)) = conj (prep (Not p)) (prep (Not q))"
| "prep (Not (Imp p q)) = conj (prep p) (prep (Not q))"
| "prep (Not (Iff p q)) = disj (prep (And p (Not q))) (prep (And (Not p) q))"
| "prep (Not p) = not (prep p)"
| "prep (Or p q) = disj (prep p) (prep q)"
| "prep (And p q) = conj (prep p) (prep q)"
| "prep (Imp p q) = prep (Or (Not p) q)"
| "prep (Iff p q) = disj (prep (And p q)) (prep (And (Not p) (Not q)))"
| "prep p = p"

lemma prep: "⋀bs. Ifm bs (prep p) = Ifm bs p"
by (induct p rule: prep.induct) auto

(* Generic quantifier elimination *)
fun qelim :: "fm ⇒ (fm ⇒ fm) ⇒ fm"
where
"qelim (E p) = (λqe. DJ qe (qelim p qe))"
| "qelim (A p) = (λqe. not (qe ((qelim (Not p) qe))))"
| "qelim (Not p) = (λqe. not (qelim p qe))"
| "qelim (And p q) = (λqe. conj (qelim p qe) (qelim q qe))"
| "qelim (Or  p q) = (λqe. disj (qelim p qe) (qelim q qe))"
| "qelim (Imp p q) = (λqe. imp (qelim p qe) (qelim q qe))"
| "qelim (Iff p q) = (λqe. iff (qelim p qe) (qelim q qe))"
| "qelim p = (λy. simpfm p)"

lemma qelim_ci:
assumes qe_inv: "∀bs p. qfree p ⟶ qfree (qe p) ∧ (Ifm bs (qe p) = Ifm bs (E p))"
shows "⋀bs. qfree (qelim p qe) ∧ (Ifm bs (qelim p qe) = Ifm bs p)"
using qe_inv DJ_qe[OF qe_inv]
by (induct p rule: qelim.induct)
(auto simp add: simpfm simpfm_qf simp del: simpfm.simps)

fun minusinf:: "fm ⇒ fm" (* Virtual substitution of -∞*)
where
"minusinf (And p q) = conj (minusinf p) (minusinf q)"
| "minusinf (Or p q) = disj (minusinf p) (minusinf q)"
| "minusinf (Eq  (CN 0 c e)) = F"
| "minusinf (NEq (CN 0 c e)) = T"
| "minusinf (Lt  (CN 0 c e)) = T"
| "minusinf (Le  (CN 0 c e)) = T"
| "minusinf (Gt  (CN 0 c e)) = F"
| "minusinf (Ge  (CN 0 c e)) = F"
| "minusinf p = p"

fun plusinf:: "fm ⇒ fm" (* Virtual substitution of +∞*)
where
"plusinf (And p q) = conj (plusinf p) (plusinf q)"
| "plusinf (Or p q) = disj (plusinf p) (plusinf q)"
| "plusinf (Eq  (CN 0 c e)) = F"
| "plusinf (NEq (CN 0 c e)) = T"
| "plusinf (Lt  (CN 0 c e)) = F"
| "plusinf (Le  (CN 0 c e)) = F"
| "plusinf (Gt  (CN 0 c e)) = T"
| "plusinf (Ge  (CN 0 c e)) = T"
| "plusinf p = p"

```