Theory SMT_Tests

theory SMT_Tests
imports Complex_Main
(*  Title:      HOL/SMT_Examples/SMT_Tests.thy
    Author:     Sascha Boehme, TU Muenchen
*)

section ‹Tests for the SMT binding›

theory SMT_Tests
imports Complex_Main
begin

smt_status

text ‹Most examples are taken from various Isabelle theories and from HOL4.›


section ‹Propositional logic›

lemma
  "True"
  "¬ False"
  "¬ ¬ True"
  "True ∧ True"
  "True ∨ False"
  "False ⟶ True"
  "¬ (False ⟷ True)"
  by smt+

lemma
  "P ∨ ¬ P"
  "¬ (P ∧ ¬ P)"
  "(True ∧ P) ∨ ¬ P ∨ (False ∧ P) ∨ P"
  "P ⟶ P"
  "P ∧ ¬ P ⟶ False"
  "P ∧ Q ⟶ Q ∧ P"
  "P ∨ Q ⟶ Q ∨ P"
  "P ∧ Q ⟶ P ∨ Q"
  "¬ (P ∨ Q) ⟶ ¬ P"
  "¬ (P ∨ Q) ⟶ ¬ Q"
  "¬ P ⟶ ¬ (P ∧ Q)"
  "¬ Q ⟶ ¬ (P ∧ Q)"
  "(P ∧ Q) ⟷ (¬ (¬ P ∨ ¬ Q))"
  "(P ∧ Q) ∧ R ⟶ P ∧ (Q ∧ R)"
  "(P ∨ Q) ∨ R ⟶ P ∨ (Q ∨ R)"
  "(P ∧ Q) ∨ R  ⟶ (P ∨ R) ∧ (Q ∨ R)"
  "(P ∨ R) ∧ (Q ∨ R) ⟶ (P ∧ Q) ∨ R"
  "(P ∨ Q) ∧ R ⟶ (P ∧ R) ∨ (Q ∧ R)"
  "(P ∧ R) ∨ (Q ∧ R) ⟶ (P ∨ Q) ∧ R"
  "((P ⟶ Q) ⟶ P) ⟶ P"
  "(P ⟶ R) ∧ (Q ⟶ R) ⟷ (P ∨ Q ⟶ R)"
  "(P ∧ Q ⟶ R) ⟷ (P ⟶ (Q ⟶ R))"
  "((P ⟶ R) ⟶ R) ⟶  ((Q ⟶ R) ⟶ R) ⟶ (P ∧ Q ⟶ R) ⟶ R"
  "¬ (P ⟶ R) ⟶  ¬ (Q ⟶ R) ⟶ ¬ (P ∧ Q ⟶ R)"
  "(P ⟶ Q ∧ R) ⟷ (P ⟶ Q) ∧ (P ⟶ R)"
  "P ⟶ (Q ⟶ P)"
  "(P ⟶ Q ⟶ R) ⟶ (P ⟶ Q)⟶ (P ⟶ R)"
  "(P ⟶ Q) ∨ (P ⟶ R) ⟶ (P ⟶ Q ∨ R)"
  "((((P ⟶ Q) ⟶ P) ⟶ P) ⟶ Q) ⟶ Q"
  "(P ⟶ Q) ⟶ (¬ Q ⟶ ¬ P)"
  "(P ⟶ Q ∨ R) ⟶ (P ⟶ Q) ∨ (P ⟶ R)"
  "(P ⟶ Q) ∧ (Q  ⟶ P) ⟶ (P ⟷ Q)"
  "(P ⟷ Q) ⟷ (Q ⟷ P)"
  "¬ (P ⟷ ¬ P)"
  "(P ⟶ Q) ⟷ (¬ Q ⟶ ¬ P)"
  "P ⟷ P ⟷ P ⟷ P ⟷ P ⟷ P ⟷ P ⟷ P ⟷ P ⟷ P"
  by smt+

lemma
  "(if P then Q1 else Q2) ⟷ ((P ⟶ Q1) ∧ (¬ P ⟶ Q2))"
  "if P then (Q ⟶ P) else (P ⟶ Q)"
  "(if P1 ∨ P2 then Q1 else Q2) ⟷ (if P1 then Q1 else if P2 then Q1 else Q2)"
  "(if P1 ∧ P2 then Q1 else Q2) ⟷ (if P1 then if P2 then Q1 else Q2 else Q2)"
  "(P1 ⟶ (if P2 then Q1 else Q2)) ⟷
   (if P1 ⟶ P2 then P1 ⟶ Q1 else P1 ⟶ Q2)"
  by smt+

lemma
  "case P of True ⇒ P | False ⇒ ¬ P"
  "case P of False ⇒ ¬ P | True ⇒ P"
  "case ¬ P of True ⇒ ¬ P | False ⇒ P"
  "case P of True ⇒ (Q ⟶ P) | False ⇒ (P ⟶ Q)"
  by smt+


section ‹First-order logic with equality›

lemma
  "x = x"
  "x = y ⟶ y = x"
  "x = y ∧ y = z ⟶ x = z"
  "x = y ⟶ f x = f y"
  "x = y ⟶ g x y = g y x"
  "f (f x) = x ∧ f (f (f (f (f x)))) = x ⟶ f x = x"
  "((if a then b else c) = d) = ((a ⟶ (b = d)) ∧ (¬ a ⟶ (c = d)))"
  by smt+

lemma
  "∀x. x = x"
  "(∀x. P x) ⟷ (∀y. P y)"
  "∀x. P x ⟶ (∀y. P x ∨ P y)"
  "(∀x. P x ∧ Q x) ⟷ (∀x. P x) ∧ (∀x. Q x)"
  "(∀x. P x) ∨ R ⟷ (∀x. P x ∨ R)"
  "(∀x y z. S x z) ⟷ (∀x z. S x z)"
  "(∀x y. S x y ⟶ S y x) ⟶ (∀x. S x y) ⟶ S y x"
  "(∀x. P x ⟶ P (f x)) ∧ P d ⟶ P (f(f(f(d))))"
  "(∀x y. s x y = s y x) ⟶ a = a ∧ s a b = s b a"
  "(∀s. q s ⟶ r s) ∧ ¬ r s ∧ (∀s. ¬ r s ∧ ¬ q s ⟶ p t ∨ q t) ⟶ p t ∨ r t"
  by smt+

lemma
  "(∀x. P x) ∧ R ⟷ (∀x. P x ∧ R)"
  by smt

lemma
  "∃x. x = x"
  "(∃x. P x) ⟷ (∃y. P y)"
  "(∃x. P x ∨ Q x) ⟷ (∃x. P x) ∨ (∃x. Q x)"
  "(∃x. P x) ∧ R ⟷ (∃x. P x ∧ R)"
  "(∃x y z. S x z) ⟷ (∃x z. S x z)"
  "¬ ((∃x. ¬ P x) ∧ ((∃x. P x) ∨ (∃x. P x ∧ Q x)) ∧ ¬ (∃x. P x))"
  by smt+

lemma
  "∃x y. x = y"
  "∃x. P x ⟶ (∃y. P x ∧ P y)"
  "(∃x. P x) ∨ R ⟷ (∃x. P x ∨ R)"
  "∃x. P x ⟶ P a ∧ P b"
  "∃x. (∃y. P y) ⟶ P x"
  "(∃x. Q ⟶ P x) ⟷ (Q ⟶ (∃x. P x))"
  by smt+

lemma
  "(¬ (∃x. P x)) ⟷ (∀x. ¬ P x)"
  "(∃x. P x ⟶ Q) ⟷ (∀x. P x) ⟶ Q"
  "(∀x y. R x y = x) ⟶ (∃y. R x y) = R x c"
  "(if P x then ¬ (∃y. P y) else (∀y. ¬ P y)) ⟶ P x ⟶ P y"
  "(∀x y. R x y = x) ∧ (∀x. ∃y. R x y) = (∀x. R x c) ⟶ (∃y. R x y) = R x c"
  by smt+

lemma
  "∀x. ∃y. f x y = f x (g x)"
  "(¬ ¬ (∃x. P x)) ⟷ (¬ (∀x. ¬ P x))"
  "∀u. ∃v. ∀w. ∃x. f u v w x = f u (g u) w (h u w)"
  "∃x. if x = y then (∀y. y = x ∨ y ≠ x) else (∀y. y = (x, x) ∨ y ≠ (x, x))"
  "∃x. if x = y then (∃y. y = x ∨ y ≠ x) else (∃y. y = (x, x) ∨ y ≠ (x, x))"
  "(∃x. ∀y. P x ⟷ P y) ⟶ ((∃x. P x) ⟷ (∀y. P y))"
  "∃z. P z ⟶ (∀x. P x)"
  "(∃y. ∀x. R x y) ⟶ (∀x. ∃y. R x y)"
  by smt+

lemma
  "(∃!x. P x) ⟶ (∃x. P x)"
  "(∃!x. P x) ⟷ (∃x. P x ∧ (∀y. y ≠ x ⟶ ¬ P y))"
  "P a ⟶ (∀x. P x ⟶ x = a) ⟶ (∃!x. P x)"
  "(∃x. P x) ∧ (∀x y. P x ∧ P y ⟶ x = y) ⟶ (∃!x. P x)"
  "(∃!x. P x) ∧ (∀x. P x ∧ (∀y. P y ⟶ y = x) ⟶ R) ⟶ R"
  by smt+

lemma
  "(∀x∈M. P x) ∧ c ∈ M ⟶ P c"
  "(∃x∈M. P x) ∨ ¬ (P c ∧ c ∈ M)"
  by smt+

lemma
  "let P = True in P"
  "let P = P1 ∨ P2 in P ∨ ¬ P"
  "let P1 = True; P2 = False in P1 ∧ P2 ⟶ P2 ∨ P1"
  "(let x = y in x) = y"
  "(let x = y in Q x) ⟷ (let z = y in Q z)"
  "(let x = y1; z = y2 in R x z) ⟷ (let z = y2; x = y1 in R x z)"
  "(let x = y1; z = y2 in R x z) ⟷ (let z = y1; x = y2 in R z x)"
  "let P = (∀x. Q x) in if P then P else ¬ P"
  by smt+

lemma
  "a ≠ b ∧ a ≠ c ∧ b ≠ c ∧ (∀x y. f x = f y ⟶ y = x) ⟶ f a ≠ f b"
  by smt

lemma
  "(∀x y z. f x y = f x z ⟶ y = z) ∧ b ≠ c ⟶ f a b ≠ f a c"
  "(∀x y z. f x y = f z y ⟶ x = z) ∧ a ≠ d ⟶ f a b ≠ f d b"
  by smt+


section ‹Guidance for quantifier heuristics: patterns›

lemma
  assumes "∀x.
    SMT.trigger (SMT.Symb_Cons (SMT.Symb_Cons (SMT.pat (f x)) SMT.Symb_Nil) SMT.Symb_Nil)
    (f x = x)"
  shows "f 1 = 1"
  using assms using [[smt_trace]] by smt

lemma
  assumes "∀x y.
    SMT.trigger (SMT.Symb_Cons (SMT.Symb_Cons (SMT.pat (f x))
      (SMT.Symb_Cons (SMT.pat (g y)) SMT.Symb_Nil)) SMT.Symb_Nil) (f x = g y)"
  shows "f a = g b"
  using assms by smt


section ‹Meta-logical connectives›

lemma
  "True ⟹ True"
  "False ⟹ True"
  "False ⟹ False"
  "P' x ⟹ P' x"
  "P ⟹ P ∨ Q"
  "Q ⟹ P ∨ Q"
  "¬ P ⟹ P ⟶ Q"
  "Q ⟹ P ⟶ Q"
  "⟦P; ¬ Q⟧ ⟹ ¬ (P ⟶ Q)"
  "P' x ≡ P' x"
  "P' x ≡ Q' x ⟹ P' x = Q' x"
  "P' x = Q' x ⟹ P' x ≡ Q' x"
  "x ≡ y ⟹ y ≡ z ⟹ x ≡ (z::'a::type)"
  "x ≡ y ⟹ (f x :: 'b::type) ≡ f y"
  "(⋀x. g x) ⟹ g a ∨ a"
  "(⋀x y. h x y ∧ h y x) ⟹ ∀x. h x x"
  "(p ∨ q) ∧ ¬ p ⟹ q"
  "(a ∧ b) ∨ (c ∧ d) ⟹ (a ∧ b) ∨ (c ∧ d)"
  by smt+


section {* Natural numbers *}

declare [[smt_nat_as_int]]

lemma
  "(0::nat) = 0"
  "(1::nat) = 1"
  "(0::nat) < 1"
  "(0::nat) ≤ 1"
  "(123456789::nat) < 2345678901"
  by smt+

lemma
  "Suc 0 = 1"
  "Suc x = x + 1"
  "x < Suc x"
  "(Suc x = Suc y) = (x = y)"
  "Suc (x + y) < Suc x + Suc y"
  by smt+

lemma
  "(x::nat) + 0 = x"
  "0 + x = x"
  "x + y = y + x"
  "x + (y + z) = (x + y) + z"
  "(x + y = 0) = (x = 0 ∧ y = 0)"
  by smt+

lemma
  "(x::nat) - 0 = x"
  "x < y ⟶ x - y = 0"
  "x - y = 0 ∨ y - x = 0"
  "(x - y) + y = (if x < y then y else x)"
  "x - y - z = x - (y + z)"
  by smt+

lemma
  "(x::nat) * 0 = 0"
  "0 * x = 0"
  "x * 1 = x"
  "1 * x = x"
  "3 * x = x * 3"
  by smt+

lemma
  "(0::nat) div 0 = 0"
  "(x::nat) div 0 = 0"
  "(0::nat) div 1 = 0"
  "(1::nat) div 1 = 1"
  "(3::nat) div 1 = 3"
  "(x::nat) div 1 = x"
  "(0::nat) div 3 = 0"
  "(1::nat) div 3 = 0"
  "(3::nat) div 3 = 1"
  "(x::nat) div 3 ≤ x"
  "(x div 3 = x) = (x = 0)"
  using [[z3_extensions]]
  by smt+

lemma
  "(0::nat) mod 0 = 0"
  "(x::nat) mod 0 = x"
  "(0::nat) mod 1 = 0"
  "(1::nat) mod 1 = 0"
  "(3::nat) mod 1 = 0"
  "(x::nat) mod 1 = 0"
  "(0::nat) mod 3 = 0"
  "(1::nat) mod 3 = 1"
  "(3::nat) mod 3 = 0"
  "x mod 3 < 3"
  "(x mod 3 = x) = (x < 3)"
  using [[z3_extensions]]
  by smt+

lemma
  "(x::nat) = x div 1 * 1 + x mod 1"
  "x = x div 3 * 3 + x mod 3"
  using [[z3_extensions]]
  by smt+

lemma
  "min (x::nat) y ≤ x"
  "min x y ≤ y"
  "min x y ≤ x + y"
  "z < x ∧ z < y ⟶ z < min x y"
  "min x y = min y x"
  "min x 0 = 0"
  by smt+

lemma
  "max (x::nat) y ≥ x"
  "max x y ≥ y"
  "max x y ≥ (x - y) + (y - x)"
  "z > x ∧ z > y ⟶ z > max x y"
  "max x y = max y x"
  "max x 0 = x"
  by smt+

lemma
  "0 ≤ (x::nat)"
  "0 < x ∧ x ≤ 1 ⟶ x = 1"
  "x ≤ x"
  "x ≤ y ⟶ 3 * x ≤ 3 * y"
  "x < y ⟶ 3 * x < 3 * y"
  "x < y ⟶ x ≤ y"
  "(x < y) = (x + 1 ≤ y)"
  "¬ (x < x)"
  "x ≤ y ⟶ y ≤ z ⟶ x ≤ z"
  "x < y ⟶ y ≤ z ⟶ x ≤ z"
  "x ≤ y ⟶ y < z ⟶ x ≤ z"
  "x < y ⟶ y < z ⟶ x < z"
  "x < y ∧ y < z ⟶ ¬ (z < x)"
  by smt+

declare [[smt_nat_as_int = false]]


section ‹Integers›

lemma
  "(0::int) = 0"
  "(0::int) = (- 0)"
  "(1::int) = 1"
  "¬ (-1 = (1::int))"
  "(0::int) < 1"
  "(0::int) ≤ 1"
  "-123 + 345 < (567::int)"
  "(123456789::int) < 2345678901"
  "(-123456789::int) < 2345678901"
  by smt+

lemma
  "(x::int) + 0 = x"
  "0 + x = x"
  "x + y = y + x"
  "x + (y + z) = (x + y) + z"
  "(x + y = 0) = (x = -y)"
  by smt+

lemma
  "(-1::int) = - 1"
  "(-3::int) = - 3"
  "-(x::int) < 0 ⟷ x > 0"
  "x > 0 ⟶ -x < 0"
  "x < 0 ⟶ -x > 0"
  by smt+

lemma
  "(x::int) - 0 = x"
  "0 - x = -x"
  "x < y ⟶ x - y < 0"
  "x - y = -(y - x)"
  "x - y = -y + x"
  "x - y - z = x - (y + z)"
  by smt+

lemma
  "(x::int) * 0 = 0"
  "0 * x = 0"
  "x * 1 = x"
  "1 * x = x"
  "x * -1 = -x"
  "-1 * x = -x"
  "3 * x = x * 3"
  by smt+

lemma
  "(0::int) div 0 = 0"
  "(x::int) div 0 = 0"
  "(0::int) div 1 = 0"
  "(1::int) div 1 = 1"
  "(3::int) div 1 = 3"
  "(x::int) div 1 = x"
  "(0::int) div -1 = 0"
  "(1::int) div -1 = -1"
  "(3::int) div -1 = -3"
  "(x::int) div -1 = -x"
  "(0::int) div 3 = 0"
  "(0::int) div -3 = 0"
  "(1::int) div 3 = 0"
  "(3::int) div 3 = 1"
  "(5::int) div 3 = 1"
  "(1::int) div -3 = -1"
  "(3::int) div -3 = -1"
  "(5::int) div -3 = -2"
  "(-1::int) div 3 = -1"
  "(-3::int) div 3 = -1"
  "(-5::int) div 3 = -2"
  "(-1::int) div -3 = 0"
  "(-3::int) div -3 = 1"
  "(-5::int) div -3 = 1"
  using [[z3_extensions]]
  by smt+

lemma
  "(0::int) mod 0 = 0"
  "(x::int) mod 0 = x"
  "(0::int) mod 1 = 0"
  "(1::int) mod 1 = 0"
  "(3::int) mod 1 = 0"
  "(x::int) mod 1 = 0"
  "(0::int) mod -1 = 0"
  "(1::int) mod -1 = 0"
  "(3::int) mod -1 = 0"
  "(x::int) mod -1 = 0"
  "(0::int) mod 3 = 0"
  "(0::int) mod -3 = 0"
  "(1::int) mod 3 = 1"
  "(3::int) mod 3 = 0"
  "(5::int) mod 3 = 2"
  "(1::int) mod -3 = -2"
  "(3::int) mod -3 = 0"
  "(5::int) mod -3 = -1"
  "(-1::int) mod 3 = 2"
  "(-3::int) mod 3 = 0"
  "(-5::int) mod 3 = 1"
  "(-1::int) mod -3 = -1"
  "(-3::int) mod -3 = 0"
  "(-5::int) mod -3 = -2"
  "x mod 3 < 3"
  "(x mod 3 = x) ⟶ (x < 3)"
  using [[z3_extensions]]
  by smt+

lemma
  "(x::int) = x div 1 * 1 + x mod 1"
  "x = x div 3 * 3 + x mod 3"
  using [[z3_extensions]]
  by smt+

lemma
  "¦x::int¦ ≥ 0"
  "(¦x¦ = 0) = (x = 0)"
  "(x ≥ 0) = (¦x¦ = x)"
  "(x ≤ 0) = (¦x¦ = -x)"
  "¦¦x¦¦ = ¦x¦"
  by smt+

lemma
  "min (x::int) y ≤ x"
  "min x y ≤ y"
  "z < x ∧ z < y ⟶ z < min x y"
  "min x y = min y x"
  "x ≥ 0 ⟶ min x 0 = 0"
  "min x y ≤ ¦x + y¦"
  by smt+

lemma
  "max (x::int) y ≥ x"
  "max x y ≥ y"
  "z > x ∧ z > y ⟶ z > max x y"
  "max x y = max y x"
  "x ≥ 0 ⟶ max x 0 = x"
  "max x y ≥ - ¦x¦ - ¦y¦"
  by smt+

lemma
  "0 < (x::int) ∧ x ≤ 1 ⟶ x = 1"
  "x ≤ x"
  "x ≤ y ⟶ 3 * x ≤ 3 * y"
  "x < y ⟶ 3 * x < 3 * y"
  "x < y ⟶ x ≤ y"
  "(x < y) = (x + 1 ≤ y)"
  "¬ (x < x)"
  "x ≤ y ⟶ y ≤ z ⟶ x ≤ z"
  "x < y ⟶ y ≤ z ⟶ x ≤ z"
  "x ≤ y ⟶ y < z ⟶ x ≤ z"
  "x < y ⟶ y < z ⟶ x < z"
  "x < y ∧ y < z ⟶ ¬ (z < x)"
  by smt+


section ‹Reals›

lemma
  "(0::real) = 0"
  "(0::real) = -0"
  "(0::real) = (- 0)"
  "(1::real) = 1"
  "¬ (-1 = (1::real))"
  "(0::real) < 1"
  "(0::real) ≤ 1"
  "-123 + 345 < (567::real)"
  "(123456789::real) < 2345678901"
  "(-123456789::real) < 2345678901"
  by smt+

lemma
  "(x::real) + 0 = x"
  "0 + x = x"
  "x + y = y + x"
  "x + (y + z) = (x + y) + z"
  "(x + y = 0) = (x = -y)"
  by smt+

lemma
  "(-1::real) = - 1"
  "(-3::real) = - 3"
  "-(x::real) < 0 ⟷ x > 0"
  "x > 0 ⟶ -x < 0"
  "x < 0 ⟶ -x > 0"
  by smt+

lemma
  "(x::real) - 0 = x"
  "0 - x = -x"
  "x < y ⟶ x - y < 0"
  "x - y = -(y - x)"
  "x - y = -y + x"
  "x - y - z = x - (y + z)"
  by smt+

lemma
  "(x::real) * 0 = 0"
  "0 * x = 0"
  "x * 1 = x"
  "1 * x = x"
  "x * -1 = -x"
  "-1 * x = -x"
  "3 * x = x * 3"
  by smt+

lemma
  "(1/2 :: real) < 1"
  "(1::real) / 3 = 1 / 3"
  "(1::real) / -3 = - 1 / 3"
  "(-1::real) / 3 = - 1 / 3"
  "(-1::real) / -3 = 1 / 3"
  "(x::real) / 1 = x"
  "x > 0 ⟶ x / 3 < x"
  "x < 0 ⟶ x / 3 > x"
  using [[z3_extensions]]
  by smt+

lemma
  "(3::real) * (x / 3) = x"
  "(x * 3) / 3 = x"
  "x > 0 ⟶ 2 * x / 3 < x"
  "x < 0 ⟶ 2 * x / 3 > x"
  using [[z3_extensions]]
  by smt+

lemma
  "¦x::real¦ ≥ 0"
  "(¦x¦ = 0) = (x = 0)"
  "(x ≥ 0) = (¦x¦ = x)"
  "(x ≤ 0) = (¦x¦ = -x)"
  "¦¦x¦¦ = ¦x¦"
  by smt+

lemma
  "min (x::real) y ≤ x"
  "min x y ≤ y"
  "z < x ∧ z < y ⟶ z < min x y"
  "min x y = min y x"
  "x ≥ 0 ⟶ min x 0 = 0"
  "min x y ≤ ¦x + y¦"
  by smt+

lemma
  "max (x::real) y ≥ x"
  "max x y ≥ y"
  "z > x ∧ z > y ⟶ z > max x y"
  "max x y = max y x"
  "x ≥ 0 ⟶ max x 0 = x"
  "max x y ≥ - ¦x¦ - ¦y¦"
  by smt+

lemma
  "x ≤ (x::real)"
  "x ≤ y ⟶ 3 * x ≤ 3 * y"
  "x < y ⟶ 3 * x < 3 * y"
  "x < y ⟶ x ≤ y"
  "¬ (x < x)"
  "x ≤ y ⟶ y ≤ z ⟶ x ≤ z"
  "x < y ⟶ y ≤ z ⟶ x ≤ z"
  "x ≤ y ⟶ y < z ⟶ x ≤ z"
  "x < y ⟶ y < z ⟶ x < z"
  "x < y ∧ y < z ⟶ ¬ (z < x)"
  by smt+


section ‹Datatypes, Records, and Typedefs›

subsection ‹Without support by the SMT solver›

subsubsection ‹Algebraic datatypes›

lemma
  "x = fst (x, y)"
  "y = snd (x, y)"
  "((x, y) = (y, x)) = (x = y)"
  "((x, y) = (u, v)) = (x = u ∧ y = v)"
  "(fst (x, y, z) = fst (u, v, w)) = (x = u)"
  "(snd (x, y, z) = snd (u, v, w)) = (y = v ∧ z = w)"
  "(fst (snd (x, y, z)) = fst (snd (u, v, w))) = (y = v)"
  "(snd (snd (x, y, z)) = snd (snd (u, v, w))) = (z = w)"
  "(fst (x, y) = snd (x, y)) = (x = y)"
  "p1 = (x, y) ∧ p2 = (y, x) ⟶ fst p1 = snd p2"
  "(fst (x, y) = snd (x, y)) = (x = y)"
  "(fst p = snd p) = (p = (snd p, fst p))"
  using fst_conv snd_conv prod.collapse
  by smt+

lemma
  "[x] ≠ Nil"
  "[x, y] ≠ Nil"
  "x ≠ y ⟶ [x] ≠ [y]"
  "hd (x # xs) = x"
  "tl (x # xs) = xs"
  "hd [x, y, z] = x"
  "tl [x, y, z] = [y, z]"
  "hd (tl [x, y, z]) = y"
  "tl (tl [x, y, z]) = [z]"
  using list.sel(1,3) list.simps
  by smt+

lemma
  "fst (hd [(a, b)]) = a"
  "snd (hd [(a, b)]) = b"
  using fst_conv snd_conv prod.collapse list.sel(1,3) list.simps
  by smt+


subsubsection ‹Records›

record point =
  cx :: int
  cy :: int

record bw_point = point +
  black :: bool

lemma
  "⦇cx = x, cy = y⦈ = ⦇cx = x', cy = y'⦈ ⟹ x = x' ∧ y = y'"
  using point.simps
  by smt

lemma
  "cx ⦇ cx = 3, cy = 4 ⦈ = 3"
  "cy ⦇ cx = 3, cy = 4 ⦈ = 4"
  "cx ⦇ cx = 3, cy = 4 ⦈ ≠ cy ⦇ cx = 3, cy = 4 ⦈"
  "⦇ cx = 3, cy = 4 ⦈ ⦇ cx := 5 ⦈ = ⦇ cx = 5, cy = 4 ⦈"
  "⦇ cx = 3, cy = 4 ⦈ ⦇ cy := 6 ⦈ = ⦇ cx = 3, cy = 6 ⦈"
  "p = ⦇ cx = 3, cy = 4 ⦈ ⟶ p ⦇ cx := 3 ⦈ ⦇ cy := 4 ⦈ = p"
  "p = ⦇ cx = 3, cy = 4 ⦈ ⟶ p ⦇ cy := 4 ⦈ ⦇ cx := 3 ⦈ = p"
  using point.simps
  by smt+

lemma
  "cy (p ⦇ cx := a ⦈) = cy p"
  "cx (p ⦇ cy := a ⦈) = cx p"
  "p ⦇ cx := 3 ⦈ ⦇ cy := 4 ⦈ = p ⦇ cy := 4 ⦈ ⦇ cx := 3 ⦈"
  sorry

lemma
  "⦇cx = x, cy = y, black = b⦈ = ⦇cx = x', cy = y', black = b'⦈ ⟹ x = x' ∧ y = y' ∧ b = b'"
  using point.simps bw_point.simps
  by smt

lemma
  "cx ⦇ cx = 3, cy = 4, black = b ⦈ = 3"
  "cy ⦇ cx = 3, cy = 4, black = b ⦈ = 4"
  "black ⦇ cx = 3, cy = 4, black = b ⦈ = b"
  "cx ⦇ cx = 3, cy = 4, black = b ⦈ ≠ cy ⦇ cx = 3, cy = 4, black = b ⦈"
  "⦇ cx = 3, cy = 4, black = b ⦈ ⦇ cx := 5 ⦈ = ⦇ cx = 5, cy = 4, black = b ⦈"
  "⦇ cx = 3, cy = 4, black = b ⦈ ⦇ cy := 6 ⦈ = ⦇ cx = 3, cy = 6, black = b ⦈"
  "p = ⦇ cx = 3, cy = 4, black = True ⦈ ⟶
     p ⦇ cx := 3 ⦈ ⦇ cy := 4 ⦈ ⦇ black := True ⦈ = p"
  "p = ⦇ cx = 3, cy = 4, black = True ⦈ ⟶
     p ⦇ cy := 4 ⦈ ⦇ black := True ⦈ ⦇ cx := 3 ⦈ = p"
  "p = ⦇ cx = 3, cy = 4, black = True ⦈ ⟶
     p ⦇ black := True ⦈ ⦇ cx := 3 ⦈ ⦇ cy := 4 ⦈ = p"
  using point.simps bw_point.simps
  by smt+

lemma
  "⦇ cx = 3, cy = 4, black = b ⦈ ⦇ black := w ⦈ = ⦇ cx = 3, cy = 4, black = w ⦈"
  "⦇ cx = 3, cy = 4, black = True ⦈ ⦇ black := False ⦈ =
     ⦇ cx = 3, cy = 4, black = False ⦈"
  "p ⦇ cx := 3 ⦈ ⦇ cy := 4 ⦈ ⦇ black := True ⦈ =
     p ⦇ black := True ⦈ ⦇ cy := 4 ⦈ ⦇ cx := 3 ⦈"
    apply (smt add_One add_inc bw_point.update_convs(1) default_unit_def inc.simps(2) one_plus_BitM
      semiring_norm(6,26))
   apply (smt bw_point.update_convs(1))
  apply (smt bw_point.cases_scheme bw_point.update_convs(1) point.update_convs(1,2))
  done


subsubsection ‹Type definitions›

typedef int' = "UNIV::int set" by (rule UNIV_witness)

definition n0 where "n0 = Abs_int' 0"
definition n1 where "n1 = Abs_int' 1"
definition n2 where "n2 = Abs_int' 2"
definition plus' where "plus' n m = Abs_int' (Rep_int' n + Rep_int' m)"

lemma
  "n0 ≠ n1"
  "plus' n1 n1 = n2"
  "plus' n0 n2 = n2"
  by (smt n0_def n1_def n2_def plus'_def Abs_int'_inverse Rep_int'_inverse UNIV_I)+


subsection ‹With support by the SMT solver (but without proofs)›

subsubsection ‹Algebraic datatypes›

lemma
  "x = fst (x, y)"
  "y = snd (x, y)"
  "((x, y) = (y, x)) = (x = y)"
  "((x, y) = (u, v)) = (x = u ∧ y = v)"
  "(fst (x, y, z) = fst (u, v, w)) = (x = u)"
  "(snd (x, y, z) = snd (u, v, w)) = (y = v ∧ z = w)"
  "(fst (snd (x, y, z)) = fst (snd (u, v, w))) = (y = v)"
  "(snd (snd (x, y, z)) = snd (snd (u, v, w))) = (z = w)"
  "(fst (x, y) = snd (x, y)) = (x = y)"
  "p1 = (x, y) ∧ p2 = (y, x) ⟶ fst p1 = snd p2"
  "(fst (x, y) = snd (x, y)) = (x = y)"
  "(fst p = snd p) = (p = (snd p, fst p))"
  using fst_conv snd_conv prod.collapse
  using [[smt_oracle, z3_extensions]]
  by smt+

lemma
  "[x] ≠ Nil"
  "[x, y] ≠ Nil"
  "x ≠ y ⟶ [x] ≠ [y]"
  "hd (x # xs) = x"
  "tl (x # xs) = xs"
  "hd [x, y, z] = x"
  "tl [x, y, z] = [y, z]"
  "hd (tl [x, y, z]) = y"
  "tl (tl [x, y, z]) = [z]"
  using list.sel(1,3)
  using [[smt_oracle, z3_extensions]]
  by smt+

lemma
  "fst (hd [(a, b)]) = a"
  "snd (hd [(a, b)]) = b"
  using fst_conv snd_conv prod.collapse list.sel(1,3)
  using [[smt_oracle, z3_extensions]]
  by smt+


subsubsection ‹Records›

lemma
  "⦇cx = x, cy = y⦈ = ⦇cx = x', cy = y'⦈ ⟹ x = x' ∧ y = y'"
  using [[smt_oracle, z3_extensions]]
  by smt+

lemma
  "cx ⦇ cx = 3, cy = 4 ⦈ = 3"
  "cy ⦇ cx = 3, cy = 4 ⦈ = 4"
  "cx ⦇ cx = 3, cy = 4 ⦈ ≠ cy ⦇ cx = 3, cy = 4 ⦈"
  "⦇ cx = 3, cy = 4 ⦈ ⦇ cx := 5 ⦈ = ⦇ cx = 5, cy = 4 ⦈"
  "⦇ cx = 3, cy = 4 ⦈ ⦇ cy := 6 ⦈ = ⦇ cx = 3, cy = 6 ⦈"
  "p = ⦇ cx = 3, cy = 4 ⦈ ⟶ p ⦇ cx := 3 ⦈ ⦇ cy := 4 ⦈ = p"
  "p = ⦇ cx = 3, cy = 4 ⦈ ⟶ p ⦇ cy := 4 ⦈ ⦇ cx := 3 ⦈ = p"
  using point.simps
  using [[smt_oracle, z3_extensions]]
  by smt+

lemma
  "cy (p ⦇ cx := a ⦈) = cy p"
  "cx (p ⦇ cy := a ⦈) = cx p"
  "p ⦇ cx := 3 ⦈ ⦇ cy := 4 ⦈ = p ⦇ cy := 4 ⦈ ⦇ cx := 3 ⦈"
  using point.simps
  using [[smt_oracle, z3_extensions]]
  by smt+

lemma
  "⦇cx = x, cy = y, black = b⦈ = ⦇cx = x', cy = y', black = b'⦈ ⟹ x = x' ∧ y = y' ∧ b = b'"
  using [[smt_oracle, z3_extensions]]
  by smt

lemma
  "cx ⦇ cx = 3, cy = 4, black = b ⦈ = 3"
  "cy ⦇ cx = 3, cy = 4, black = b ⦈ = 4"
  "black ⦇ cx = 3, cy = 4, black = b ⦈ = b"
  "cx ⦇ cx = 3, cy = 4, black = b ⦈ ≠ cy ⦇ cx = 3, cy = 4, black = b ⦈"
  "⦇ cx = 3, cy = 4, black = b ⦈ ⦇ cx := 5 ⦈ = ⦇ cx = 5, cy = 4, black = b ⦈"
  "⦇ cx = 3, cy = 4, black = b ⦈ ⦇ cy := 6 ⦈ = ⦇ cx = 3, cy = 6, black = b ⦈"
  "p = ⦇ cx = 3, cy = 4, black = True ⦈ ⟶
     p ⦇ cx := 3 ⦈ ⦇ cy := 4 ⦈ ⦇ black := True ⦈ = p"
  "p = ⦇ cx = 3, cy = 4, black = True ⦈ ⟶
     p ⦇ cy := 4 ⦈ ⦇ black := True ⦈ ⦇ cx := 3 ⦈ = p"
  "p = ⦇ cx = 3, cy = 4, black = True ⦈ ⟶
     p ⦇ black := True ⦈ ⦇ cx := 3 ⦈ ⦇ cy := 4 ⦈ = p"
  using point.simps bw_point.simps
  using [[smt_oracle, z3_extensions]]
  by smt+

lemma
  "⦇ cx = 3, cy = 4, black = b ⦈ ⦇ black := w ⦈ = ⦇ cx = 3, cy = 4, black = w ⦈"
  "⦇ cx = 3, cy = 4, black = True ⦈ ⦇ black := False ⦈ =
     ⦇ cx = 3, cy = 4, black = False ⦈"
  sorry

lemma
  "p ⦇ cx := 3 ⦈ ⦇ cy := 4 ⦈ ⦇ black := True ⦈ =
     p ⦇ black := True ⦈ ⦇ cy := 4 ⦈ ⦇ cx := 3 ⦈"
  using point.simps bw_point.simps
  using [[smt_oracle, z3_extensions]]
  by smt


subsubsection ‹Type definitions›

lemma
  "n0 ≠ n1"
  "plus' n1 n1 = n2"
  "plus' n0 n2 = n2"
  using [[smt_oracle, z3_extensions]]
  by (smt n0_def n1_def n2_def plus'_def)+


section ‹Function updates›

lemma
  "(f (i := v)) i = v"
  "i1 ≠ i2 ⟶ (f (i1 := v)) i2 = f i2"
  "i1 ≠ i2 ⟶ (f (i1 := v1, i2 := v2)) i1 = v1"
  "i1 ≠ i2 ⟶ (f (i1 := v1, i2 := v2)) i2 = v2"
  "i1 = i2 ⟶ (f (i1 := v1, i2 := v2)) i1 = v2"
  "i1 = i2 ⟶ (f (i1 := v1, i2 := v2)) i1 = v2"
  "i1 ≠ i2 ∧i1 ≠ i3 ∧  i2 ≠ i3 ⟶ (f (i1 := v1, i2 := v2)) i3 = f i3"
  using fun_upd_same fun_upd_apply
  by smt+


section ‹Sets›

lemma Empty: "x ∉ {}" by simp

lemmas smt_sets = Empty UNIV_I Un_iff Int_iff

lemma
  "x ∉ {}"
  "x ∈ UNIV"
  "x ∈ A ∪ B ⟷ x ∈ A ∨ x ∈ B"
  "x ∈ P ∪ {} ⟷ x ∈ P"
  "x ∈ P ∪ UNIV"
  "x ∈ P ∪ Q ⟷ x ∈ Q ∪ P"
  "x ∈ P ∪ P ⟷ x ∈ P"
  "x ∈ P ∪ (Q ∪ R) ⟷ x ∈ (P ∪ Q) ∪ R"
  "x ∈ A ∩ B ⟷ x ∈ A ∧ x ∈ B"
  "x ∉ P ∩ {}"
  "x ∈ P ∩ UNIV ⟷ x ∈ P"
  "x ∈ P ∩ Q ⟷ x ∈ Q ∩ P"
  "x ∈ P ∩ P ⟷ x ∈ P"
  "x ∈ P ∩ (Q ∩ R) ⟷ x ∈ (P ∩ Q) ∩ R"
  "{x. x ∈ P} = {y. y ∈ P}"
  by (smt smt_sets)+

end