theory Demo07 imports Main begin section \Inductive Definitions\ subsection \Early examples\ definition injective :: "('a \ 'b) \ bool" where "injective f \ (\x y. f x = f y \ x = y)" lemma injectiveI[intro]: "(\ x y. f x = f y \ x = y) \ injective f" unfolding injective_def by auto lemma injectiveD[dest]: "injective f \ f x = f y \ x = y" unfolding injective_def by auto text \We might hide the internal definition of @{const injective} at this point. Advantage: add abstraction-layer (use @{thm injectiveI} and @{thm injectiveD} to reason about injectivity, but not internal definition.)\ hide_fact injective_def thm injective_def (* no longer available *) text \Example of Function-Definition via Non-Recursive-Definitions\ fun len1 :: "'a list \ nat" where "len1 [] = 0" | "len1 (x # xs) = Suc (len1 xs)" thm len1_def (* does not exists, i.e., hidden from user *) text \Tell Isabelle to make internal definitions visible to the user.\ declare [[function_internals = true, inductive_internals = true]] fun len2 :: "'a list \ nat" where "len2 [] = 0" | "len2 (x # xs) = Suc (len2 xs)" text \The recursive definition of @{const len2} is internally modeled via three non-recursive definitions.\ thm len2_def thm len2_sumC_def thm len2_graph_def declare [[function_internals = false, inductive_internals = false]] subsection \Examples of Inductive Definitions\ type_synonym var = string type_synonym val = nat type_synonym state = "var \ val" datatype prog = Skip | Update "state \ state" | Sequence prog prog | While "state \ bool" prog text \Attempt 1: model as function\ function eval_1 :: "prog \ state \ state" where "eval_1 Skip s = s" | "eval_1 (Update f) s = f s" | "eval_1 (Sequence p q) s = (eval_1 q (eval_1 p s))" | "eval_1 (While c p) s = (if c s then eval_1 (While c p) (eval_1 p s) else s)" by pat_completeness auto termination oops (* does not terminate *) text \Attempt 2: model via auxiliary fuel-argument, here: number of allowed loop-iterations\ fun eval_2_b :: "nat \ prog \ state \ state option" where "eval_2_b n Skip s = Some s" | "eval_2_b n (Update f) s = Some (f s)" | "eval_2_b n (Sequence p q) s = (Option.bind (eval_2_b n p s) (eval_2_b n q))" | "eval_2_b n (While c p) s = (if c s then if n = 0 then None \ \out of iterations\ else Option.bind (eval_2_b n p s) (eval_2_b (n - 1) (While c p)) else Some s)" definition eval_2 :: "prog \ state \ state option" where "eval_2 p s = (if \ n. eval_2_b n p s \ None then eval_2_b (SOME n. eval_2_b n p s \ None) p s else None)" text \Natural modeling via inductive predicate\ inductive eval :: "prog \ state \ state \ bool" where skip: "eval Skip s s" | update: "eval (Update f) s (f s)" | sequence: "eval p s t \ eval q t u \ eval (Sequence p q) s u" | while_false: "\ c s \ eval (While c p) s s" | while_true: "c s \ eval p s t \ eval (While c p) t u \ eval (While c p) s u" inductive is_odd :: "nat \ bool" where "is_odd 1" | "is_odd n \ is_odd (n + 2)" print_theorems section \Rule Inversion and Rule Induction\ text \Rule Inversion\ lemma is_odd0: "is_odd 0 = False" proof - { assume "is_odd 0" hence False by cases auto text \since @{thm \is_odd 0\} is first assumed fact, rule inversion using @{thm is_odd.cases} is done implicitly by @{method cases}\ text \same proof where cases are listed explicitly\ from \is_odd 0\ have False proof cases case 1 then show ?thesis by auto next case (2 n) then show ?thesis by auto qed } have "is_odd 0 \ False" by (cases rule: is_odd.cases) auto text \here @{term \is_odd 0\} is not explicitly assumed, so @{method cases} must be parametrized by correct rule inversion rule, i.e., @{thm is_odd.cases}\ then show ?thesis by auto qed text \Rule Induction\ text \similar observation as in rule inversion: one has to provide induction rule, but not if predicate is assumed first\ lemma is_odd_odd1: "is_odd x \ odd x" by (induction rule: is_odd.induct) auto lemma is_odd_odd2: "is_odd x \ odd x" proof - assume "is_odd x" thus "odd x" by induction auto qed text \A version which uses new Isar-elements: \assumes\ and \shows\ and \assms\\ lemma is_odd_odd3: assumes "is_odd x" shows "odd x" using assms by induction auto inductive_set star :: "('a \ 'a) set \ ('a \ 'a) set" for R where refl [simp]: "(x, x) \ star R" | step: "(x, y) \ R \ (y, z) \ star R \ (x, z) \ star R" print_theorems (* implicitly also the predicate starp is created, and you have access to that *) lemma star_trans1: assumes xy: "(x, y) \ star R" and yz: "(y, z) \ star R" shows "(x, z) \ star R" using xy yz proof induction case (step x y' y) from step.hyps (* the hypothesis, i.e., preconditions in inference rule step *) have "(x, y') \ R" "(y', y) \ star R" . from step.prems (* premises in the goal statement; here the fact yz *) have "(y,z) \ star R" . from step.IH (* the induction hypotheses *) have "(y, z) \ star R \ (y', z) \ star R" . from this[OF \(y, z) \ star R\] have "(y', z) \ star R" by auto from star.step[OF \(x, y') \ R\ this] show ?case . next case (refl x) from refl.prems show ?case . qed lemma star_trans2: "(x, y) \ star R \ (y, z) \ star R \ (x, z) \ star R" by (induction x y rule: star.induct, auto intro: star.step) section \Sets in Isabelle\ term "(\)" (* membership *) term "(\)" (* subset *) term "(\)" (* strict subset *) term Ball (* all elements satisfy predicate *) term Bex (* at least one element satisfies predicate *) term "(\)" (* union *) term "(\)" (* intersection *) term "\" (* big-union *) term "\" (* big-intersection *) term "- (A :: 'a set)" (* complement *) term "A - (B :: 'a set)" (* difference *) term "{}" (* empty set *) term "UNIV :: 'a set" (* all elements (of a specific type) *) term "{x}" (* singleton *) term insert (* add single element *) term finite (* is set finite? *) term card (* cardinality (0 for infinite sets *) term "(`)" (* image, apply function to all set elements *) term Collect (* convert predicate to set *) term "{x . P x}" (* basic set comprehension *) term "{ (x,y + z) | x y z u . x - y = u \ u \ 5 \ P z}" (* more complex set comprehension *) term "sum f A" (* sum_{a in A} f(a) *) term "prod" (* product, similar to sum *) lemma "A \ (B \ C) \ (A \ B) \ (A \ C)" by auto lemma "A \ (B \ C) \ (A \ B) \ (A \ C)" proof fix x assume "x \ A \ (B \ C)" hence xA: "x \ A" and choice: "x \ B \ x \ C" by auto from choice show "x \ (A \ B) \ (A \ C)" proof assume "x \ B" from xA this have "x \ A \ B" .. thus ?thesis .. qed (insert xA, auto) (* other case similar *) qed section \Binary Search Trees\ datatype 'a tree = Leaf | Node "'a tree" 'a "'a tree" fun set_t :: "'a tree \ 'a set" where "set_t Leaf = {}" | "set_t (Node l x r) = set_t l \ {x} \ set_t r" inductive ordered :: "'a :: linorder tree \ bool" where oLeaf: "ordered Leaf" | oNode: "ordered l \ ordered r \ Ball (set_t l) (\ y. y < x) \ Ball (set_t r) (\ y. y > x) \ ordered (Node l x r)" fun member:: "'a :: linorder \ 'a tree \ bool" where "member x Leaf = False" | "member y (Node l x r) = (if x = y then True else if y < x then member y l else member y r)" lemma member_correct: "ordered t \ member x t = (x \ set_t t)" by (induction rule: ordered.induct, auto) end