Gather all non-undefined values after addition - isabelle
I have the following addition in Isabelle:
function proj_add :: "(real × real) × bit ⇒ (real × real) × bit ⇒ (real × real) × bit" where
"proj_add ((x1,y1),l) ((x2,y2),j) = ((add (x1,y1) (x2,y2)), l+j)"
if "delta x1 y1 x2 y2 ≠ 0 ∧ (x1,y1) ∈ e_aff ∧ (x2,y2) ∈ e_aff"
| "proj_add ((x1,y1),l) ((x2,y2),j) = ((ext_add (x1,y1) (x2,y2)), l+j)"
if "delta' x1 y1 x2 y2 ≠ 0 ∧ (x1,y1) ∈ e_aff ∧ (x2,y2) ∈ e_aff"
| "proj_add ((x1,y1),l) ((x2,y2),j) = undefined"
if "delta x1 y1 x2 y2 = 0 ∧ delta' x1 y1 x2 y2 = 0 ∨ (x1,y1) ∉ e_aff ∨ (x2,y2) ∉ e_aff"
apply(fast,fastforce)
using coherence e_aff_def by auto
Now, I want to extract all defined values to simulate addition on classes instead of specific values:
function proj_add_class :: "((real × real) × bit) set ⇒ ((real × real) × bit) set ⇒ ((real × real) × bit) set" where
"proj_add_class c1 c2 =
(⋃ cr ∈ c1 × c2. proj_add cr.fst cr.snd)"
The above is just a template. Apparently, I cannot take the first element from cr and thus I'm getting an error. On the other hand, how can I remove undefined values?
See here for the complete theory.
Background
Having gained a certain level of understanding of the article upon which the formalisation is based, I decided to update the answer. The original answer is available through the revision history: I believe that everything that was stated in the original answer is sensible, but, possibly, less optimal from the perspective of the style of exposition than the revised answer.
Introduction
I use a slightly updated notation based on my own revision of a part of a draft of your formalisation associated with 4033cbf288. The following theories have been imported: Complex_Main "HOL-Algebra.Group" "HOL-Algebra.Bij" and "HOL-Library.Bit"
Definitions I
First, I restate some of the relevant definitions to ensure that the answer is self-contained:
locale curve_addition =
fixes c d :: real
begin
definition e :: "real ⇒ real ⇒ real"
where "e x y = x⇧2 + c*y⇧2 - 1 - d*x⇧2*y⇧2"
fun add :: "real × real ⇒ real × real ⇒ real × real" (infix ‹⊕⇩E› 65)
where
"(x1, y1) ⊕⇩E (x2, y2) =
(
(x1*x2 - c*y1*y2) div (1 - d*x1*y1*x2*y2),
(x1*y2 + y1*x2) div (1 + d*x1*y1*x2*y2)
)"
definition delta_plus :: "real ⇒ real ⇒ real ⇒ real ⇒ real" (‹δ⇩y›)
where "δ⇩y x1 y1 x2 y2 = 1 + d*x1*y1*x2*y2"
definition delta_minus :: "real ⇒ real ⇒ real ⇒ real ⇒ real" (‹δ⇩x›)
where "δ⇩x x1 y1 x2 y2 = 1 - d*x1*y1*x2*y2"
definition delta :: "real ⇒ real ⇒ real ⇒ real ⇒ real" (‹δ⇩E›)
where "δ⇩E x1 y1 x2 y2 = (δ⇩x x1 y1 x2 y2) * (δ⇩y x1 y1 x2 y2)"
end
locale ext_curve_addition = curve_addition +
fixes c' d' t
assumes c'_eq_1[simp]: "c' = 1"
assumes d'_neq_0[simp]: "d' ≠ 0"
assumes c_def: "c = c'⇧2"
assumes d_def: "d = d'⇧2"
assumes t_sq_def: "t⇧2 = d/c"
assumes t_sq_n1: "t⇧2 ≠ 1"
begin
fun add0 :: "real × real ⇒ real × real ⇒ real × real" (infix ‹⊕⇩0› 65)
where "(x1, y1) ⊕⇩0 (x2, y2) = (x1, y1/sqrt(c)) ⊕⇩E (x2, y2/sqrt(c))"
definition delta_plus_0 :: "real ⇒ real ⇒ real ⇒ real ⇒ real" (‹δ⇩0⇩y›)
where "δ⇩0⇩y x1 y1 x2 y2 = δ⇩y x1 (y1/sqrt(c)) x2 (y2/sqrt(c))"
definition delta_minus_0 :: "real ⇒ real ⇒ real ⇒ real ⇒ real" (‹δ⇩0⇩x›)
where "δ⇩0⇩x x1 y1 x2 y2 = δ⇩x x1 (y1/sqrt(c)) x2 (y2/sqrt(c))"
definition delta_0 :: "real ⇒ real ⇒ real ⇒ real ⇒ real" (‹δ⇩0›)
where "δ⇩0 x1 y1 x2 y2 = (δ⇩0⇩x x1 y1 x2 y2) * (δ⇩0⇩y x1 y1 x2 y2)"
definition delta_plus_1 :: "real ⇒ real ⇒ real ⇒ real ⇒ real" (‹δ⇩1⇩y›)
where "δ⇩1⇩y x1 y1 x2 y2 = x1*x2 + y1*y2"
definition delta_minus_1 :: "real ⇒ real ⇒ real ⇒ real ⇒ real" (‹δ⇩1⇩x›)
where "δ⇩1⇩x x1 y1 x2 y2 = x2*y1 - x1*y2"
definition delta_1 :: "real ⇒ real ⇒ real ⇒ real ⇒ real" (‹δ⇩1›)
where "δ⇩1 x1 y1 x2 y2 = (δ⇩1⇩x x1 y1 x2 y2) * (δ⇩1⇩y x1 y1 x2 y2)"
fun ρ :: "real × real ⇒ real × real"
where "ρ (x, y) = (-y, x)"
fun τ :: "real × real ⇒ real × real"
where "τ (x, y) = (1/(t*x), 1/(t*y))"
fun add1 :: "real × real ⇒ real × real ⇒ real × real" (infix ‹⊕⇩1› 65)
where
"(x1, y1) ⊕⇩1 (x2, y2) =
(
(x1*y1 - x2*y2) div (x2*y1 - x1*y2),
(x1*y1 + x2*y2) div (x1*x2 + y1*y2)
)"
definition e' :: "real ⇒ real ⇒ real"
where "e' x y = x⇧2 + y⇧2 - 1 - t⇧2*x⇧2*y⇧2"
end
locale projective_curve = ext_curve_addition
begin
definition "E⇩a⇩f⇩f = {(x, y). e' x y = 0}"
definition "E⇩O = {(x, y). x ≠ 0 ∧ y ≠ 0 ∧ (x, y) ∈ E⇩a⇩f⇩f}"
definition G where
"G ≡ {id, ρ, ρ ∘ ρ, ρ ∘ ρ ∘ ρ, τ, τ ∘ ρ, τ ∘ ρ ∘ ρ, τ ∘ ρ ∘ ρ ∘ ρ}"
definition symmetries where
"symmetries = {τ, τ ∘ ρ, τ ∘ ρ ∘ ρ, τ ∘ ρ ∘ ρ ∘ ρ}"
definition rotations where
"rotations = {id, ρ, ρ ∘ ρ, ρ ∘ ρ ∘ ρ}"
definition E⇩a⇩f⇩f⇩0 where
"E⇩a⇩f⇩f⇩0 =
{
((x1, y1), (x2, y2)).
(x1, y1) ∈ E⇩a⇩f⇩f ∧ (x2, y2) ∈ E⇩a⇩f⇩f ∧ δ⇩0 x1 y1 x2 y2 ≠ 0
}"
definition E⇩a⇩f⇩f⇩1 where
"E⇩a⇩f⇩f⇩1 =
{
((x1, y1), (x2, y2)).
(x1, y1) ∈ E⇩a⇩f⇩f ∧ (x2, y2) ∈ E⇩a⇩f⇩f ∧ δ⇩1 x1 y1 x2 y2 ≠ 0
}"
end
Definitions II
I use coherence without proof, but I have ported the proof in the repository to my notation before copying the statement of the theorem to this answer, i.e. the proof does exist but it is not part of the answer.
context projective_curve
begin
type_synonym repEPCT = ‹((real × real) × bit)›
type_synonym EPCT = ‹repEPCT set›
definition gluing :: "(repEPCT × repEPCT) set"
where
"gluing =
{
(((x0, y0), l), ((x1, y1), j)).
((x0, y0) ∈ E⇩a⇩f⇩f ∧ (x1, y1) ∈ E⇩a⇩f⇩f) ∧
(
((x0, y0) ∈ E⇩O ∧ (x1, y1) = τ (x0, y0) ∧ j = l + 1) ∨
(x0 = x1 ∧ y0 = y1 ∧ l = j)
)
}"
definition E where "E = (E⇩a⇩f⇩f × UNIV) // gluing"
lemma coherence:
assumes "δ⇩0 x1 y1 x2 y2 ≠ 0" "δ⇩1 x1 y1 x2 y2 ≠ 0"
assumes "e' x1 y1 = 0" "e' x2 y2 = 0"
shows "(x1, y1) ⊕⇩1 (x2, y2) = (x1, y1) ⊕⇩0 (x2, y2)"
sorry
end
proj_add
The definition of proj_add is almost identical to the one in the original question with the exception of the added option domintros (it is hardly possible to state anything meaningful about it without the domain theorems). I also show that it is equivalent to the plain definition that is currently used.
context projective_curve
begin
function (domintros) proj_add :: "repEPCT ⇒ repEPCT ⇒ repEPCT"
(infix ‹⊙› 65)
where
"((x1, y1), i) ⊙ ((x2, y2), j) = ((x1, y1) ⊕⇩0 (x2, y2), i + j)"
if "(x1, y1) ∈ E⇩a⇩f⇩f" and "(x2, y2) ∈ E⇩a⇩f⇩f" and "δ⇩0 x1 y1 x2 y2 ≠ 0"
| "((x1, y1), i) ⊙ ((x2, y2), j) = ((x1, y1) ⊕⇩1 (x2, y2), i + j)"
if "(x1, y1) ∈ E⇩a⇩f⇩f" and "(x2, y2) ∈ E⇩a⇩f⇩f" and "δ⇩1 x1 y1 x2 y2 ≠ 0"
| "((x1, y1), i) ⊙ ((x2, y2), j) = undefined"
if "(x1, y1) ∉ E⇩a⇩f⇩f ∨ (x2, y2) ∉ E⇩a⇩f⇩f ∨
(δ⇩0 x1 y1 x2 y2 = 0 ∧ δ⇩1 x1 y1 x2 y2 = 0)"
subgoal by (metis τ.cases surj_pair)
subgoal by auto
subgoal unfolding E⇩a⇩f⇩f_def using coherence by auto
by auto
termination proj_add using "termination" by blast
lemma proj_add_pred_undefined:
assumes "¬ ((x1, y1), (x2, y2)) ∈ E⇩a⇩f⇩f⇩0 ∪ E⇩a⇩f⇩f⇩1"
shows "((x1, y1), l) ⊙ ((x2, y2), j) = undefined"
using assms unfolding E⇩a⇩f⇩f⇩0_def E⇩a⇩f⇩f⇩1_def
by (auto simp: proj_add.domintros(3) proj_add.psimps(3))
lemma proj_add_def:
"(proj_add ((x1, y1), i) ((x2, y2), j)) =
(
if ((x1, y1) ∈ E⇩a⇩f⇩f ∧ (x2, y2) ∈ E⇩a⇩f⇩f ∧ δ⇩0 x1 y1 x2 y2 ≠ 0)
then ((x1, y1) ⊕⇩0 (x2, y2), i + j)
else
(
if ((x1, y1) ∈ E⇩a⇩f⇩f ∧ (x2, y2) ∈ E⇩a⇩f⇩f ∧ δ⇩1 x1 y1 x2 y2 ≠ 0)
then ((x1, y1) ⊕⇩1 (x2, y2), i + j)
else undefined
)
)"
(is "?lhs = ?rhs")
proof(cases ‹δ⇩0 x1 y1 x2 y2 ≠ 0 ∧ (x1, y1) ∈ E⇩a⇩f⇩f ∧ (x2, y2) ∈ E⇩a⇩f⇩f›)
case True
then have True_exp: "(x1, y1) ∈ E⇩a⇩f⇩f" "(x2, y2) ∈ E⇩a⇩f⇩f" "δ⇩0 x1 y1 x2 y2 ≠ 0"
by auto
then have rhs: "?rhs = ((x1, y1) ⊕⇩0 (x2, y2), i + j)" by simp
show ?thesis unfolding proj_add.simps(1)[OF True_exp, of i j] rhs ..
next
case n0: False show ?thesis
proof(cases ‹δ⇩1 x1 y1 x2 y2 ≠ 0 ∧ (x1, y1) ∈ E⇩a⇩f⇩f ∧ (x2, y2) ∈ E⇩a⇩f⇩f›)
case True show ?thesis
proof-
from True n0 have False_exp:
"(x1, y1) ∈ E⇩a⇩f⇩f" "(x2, y2) ∈ E⇩a⇩f⇩f" "δ⇩1 x1 y1 x2 y2 ≠ 0"
by auto
with n0 have rhs: "?rhs = ((x1, y1) ⊕⇩1 (x2, y2), i + j)" by auto
show ?thesis unfolding proj_add.simps(2)[OF False_exp, of i j] rhs ..
qed
next
case False then show ?thesis using n0 proj_add.simps(3) by auto
qed
qed
end
proj_add_class
I also provide what I would consider to be a natural solution (again, using the function infrastructure) for the statement of proj_add_class and show that it agrees with the definition that is used at the moment on the domain of interest.
context projective_curve
begin
function (domintros) proj_add_class :: "EPCT ⇒ EPCT ⇒ EPCT" (infix ‹⨀› 65)
where
"A ⨀ B =
the_elem
(
{
((x1, y1), i) ⊙ ((x2, y2), j) | x1 y1 i x2 y2 j.
((x1, y1), i) ∈ A ∧ ((x2, y2), j) ∈ B ∧
((x1, y1), (x2, y2)) ∈ E⇩a⇩f⇩f⇩0 ∪ E⇩a⇩f⇩f⇩1
} // gluing
)"
if "A ∈ E" and "B ∈ E"
| "A ⨀ B = undefined" if "A ∉ E ∨ B ∉ E"
by (meson surj_pair) auto
termination proj_add_class using "termination" by auto
definition proj_add_class' (infix ‹⨀''› 65) where
"proj_add_class' c1 c2 =
the_elem
(
(case_prod (⊙) `
({(x, y). x ∈ c1 ∧ y ∈ c2 ∧ (fst x, fst y) ∈ E⇩a⇩f⇩f⇩0 ∪ E⇩a⇩f⇩f⇩1})) // gluing
)"
lemma proj_add_class_eq:
assumes "A ∈ E" and "B ∈ E"
shows "A ⨀' B = A ⨀ B"
proof-
have
"(λ(x, y). x ⊙ y) `
{(x, y). x ∈ A ∧ y ∈ B ∧ (fst x, fst y) ∈ E⇩a⇩f⇩f⇩0 ∪ E⇩a⇩f⇩f⇩1} =
{
((x1, y1), i) ⊙ ((x2, y2), j) | x1 y1 i x2 y2 j.
((x1, y1), i) ∈ A ∧ ((x2, y2), j) ∈ B ∧ ((x1, y1), x2, y2) ∈ E⇩a⇩f⇩f⇩0 ∪ E⇩a⇩f⇩f⇩1
}"
apply (standard; standard)
subgoal unfolding image_def by clarsimp blast
subgoal unfolding image_def by clarsimp blast
done
then show ?thesis
unfolding proj_add_class'_def proj_add_class.simps(1)[OF assms]
by auto
qed
end
Conclusion
The appropriate choice of a definition is a subjective matter. Therefore, I can only express my personal opinion about what I believe to be the most suitable choice.
Related
Isabelle Failed to refine any pending goal during instantiation
datatype 'a list = Cons 'a "'a list" | Nil instantiation list :: (order) order begin fun less_eq_list :: "'a list ⇒ 'a list ⇒ bool" where "less_eq_list Nil Nil = True" | "less_eq_list (Cons _ _) Nil = True" | "less_eq_list Nil (Cons _ _) = False" | "less_eq_list (Cons _ a) (Cons _ b) = less_eq_list a b" instance proof fix x y:: "'a list" show "x ≤ x" apply(induct_tac x) apply(auto) done (* at this point the state is show x ≤ x Successful attempt to solve goal by exported rule: ?x2 ≤ ?x2 proof (state) this: x ≤ x goal (3 subgoals): 1. ⋀x y. (x < y) = (x ≤ y ∧ ¬ y ≤ x) 2. ⋀x y z. x ≤ y ⟹ y ≤ z ⟹ x ≤ z 3. ⋀x y. x ≤ y ⟹ y ≤ x ⟹ x = y *) show "(x < y) = (x ≤ y ∧ ¬ y ≤ x)" (* I get an error here Failed to refine any pending goal Local statement fails to refine any pending goal Failed attempt to solve goal by exported rule: (?x2 < ?y2) = (?x2 ≤ ?y2 ∧ ¬ ?y2 ≤ ?x2) *) qed end What is wrong with this? The proof of "x ≤ x" worked like a charm. Somehow "(x < y) = (x ≤ y ∧ ¬ y ≤ x)" doesn't match any subgoal.
Class order is a subclass of preorder, which in turn is a subclass of ord. Class ord requires you to define both less_eq (≤) and less (<). In your code, you have correctly defined less_eq_list but forgot to define less_list, and that's why you got an error when trying to prove (x < y) = (x ≤ y ∧ ¬ y ≤ x).
Isabelle equivalent definitions treated differently by auto
I'm trying to add some small improvements to Jacobson_Basic_Algebra. ORIGINAL DEFINITION: Their definition of monoid isomorphism is as follows. locale monoid_isomorphism = bijective_map η M M' + source: monoid M "(⋅)" 𝟭 + target: monoid M' "(⋅')" "𝟭'" for η and M and composition (infixl "⋅" 70) and unit ("𝟭") and M' and composition' (infixl "⋅''" 70) and unit' ("𝟭''") + assumes commutes_with_composition: "⟦ x ∈ M; y ∈ M ⟧ ⟹ η x ⋅' η y = η (x ⋅ y)" and commutes_with_unit: "η 𝟭 = 𝟭'" and then they have a theorem that the inverse mapping is also an isomorphism theorem inverse_monoid_isomorphism: "monoid_isomorphism (restrict (inv_into M η) M') M' (⋅') 𝟭' M (⋅) 𝟭" using commutes_with_composition commutes_with_unit surjective by unfold_locales auto MY DEFINITION 1: So I added my improvement by splitting the definition into two parts. First I define morphism as a function that satisfies f (a b) = f(a) f(b). locale monoid_morphism = (* This is like homomorphism but lacks the commutes_with_unit axiom *) map η M M'+ source: monoid M "(⋅)" 𝟭 + target: monoid M' "(⋅')" "𝟭'" for η and M and composition (infixl "⋅" 70) and unit ("𝟭") and M' and composition' (infixl "⋅''" 70) and unit' ("𝟭''") + assumes commutes_with_composition: "⟦ x ∈ M; y ∈ M ⟧ ⟹ η (x ⋅ y) = η x ⋅' η y" then I define isomorphism as a morphism that us bijective locale monoid_isomorphism = monoid_morphism + bijective_map η M M' and then I prove that neutral element must map to neutral element f(1)=1 begin monoid_isomorphism context theorem commutes_with_unit: "η 𝟭 = 𝟭'" proof - { fix y assume "y ∈ M'" then obtain x where nxy:"η x = y" "x ∈ M" by (metis image_iff surjective) then have "η x ⋅' η 𝟭 = η x" using commutes_with_composition[symmetric] by auto then have "y ⋅' η 𝟭 = y" using nxy by auto } then show "η 𝟭 = 𝟭'" by fastforce qed end so in this way, I can remove the superfluous axiom from the definition and make it into a theorem instead. THE PROBLEM: So all in all, the two locales are not only equivalent but actually look exactly the same from outside. But somehow the inverse_monoid_isomorphism proof fails now. theorem inverse_monoid_isomorphism: "monoid_isomorphism (restrict (inv_into M η) M') M' (⋅') 𝟭' M (⋅) 𝟭" using commutes_with_composition commutes_with_unit surjective apply(unfold_locales) apply(auto) yields goal (1 subgoal): 1. ⋀xa xb. (⋀x y. x ∈ M ⟹ y ∈ M ⟹ η (x ⋅ y) = η x ⋅' η y) ⟹ 𝟭' = η 𝟭 ⟹ M' = η ` M ⟹ xa ∈ M ⟹ xb ∈ M ⟹ inv_into M η (η xa ⋅' η xb) = xa ⋅ xb I tried to see what happens if I change surjective to bijective (among using requirements) and then I get slightly more simplified end result goal (1 subgoal): 1. ⋀x y. (⋀x y. x ∈ M ⟹ y ∈ M ⟹ η (x ⋅ y) = η x ⋅' η y) ⟹ x ∈ M' ⟹ y ∈ M' ⟹ 𝟭' = η 𝟭 ⟹ inv_into M η (x ⋅' y) = inv_into M η x ⋅ inv_into M η y But in the end auto can't do it. Interestingly, when I use bijective then the proof doesn't work even with the original definition of isomorphism. MY DEFINITION 2: I also get the same outcome if I define locale monoid_homomorphism = monoid_morphism η M "(⋅)" 𝟭 M' "(⋅')" "𝟭'" for η and M and composition (infixl "⋅" 70) and unit ("𝟭") and M' and composition' (infixl "⋅''" 70) and unit' ("𝟭''") + assumes commutes_with_unit: "η 𝟭 = 𝟭'" locale monoid_isomorphism = bijective_map η M M' + monoid_homomorphism MY DEFINITION 3: It also doesn't work if I just split the definition into locale monoid_homomorphism = source: monoid M "(⋅)" 𝟭 + target: monoid M' "(⋅')" "𝟭'" for η and M and composition (infixl "⋅" 70) and unit ("𝟭") and M' and composition' (infixl "⋅''" 70) and unit' ("𝟭''") + assumes commutes_with_composition: "⟦ x ∈ M; y ∈ M ⟧ ⟹ η x ⋅' η y = η (x ⋅ y)" and commutes_with_unit: "η 𝟭 = 𝟭'" text ‹Def 1.3› text ‹p 37, ll 7--11› locale monoid_isomorphism = bijective_map η M M' + monoid_homomorphism Now it is not only logically equivalent, but it's actually syntactically equivalent if you just paste monoid_homomorphism into the definition of monoid_isomorphism (which I tried to do and it works). locale monoid_isomorphism fixes η :: "'a ⇒ 'b" and M :: "'a set" and composition :: "'a ⇒ 'a ⇒ 'a" (infixl ‹⋅› 70) and unit :: "'a" (‹𝟭›) and M' :: "'b set" and composition' :: "'b ⇒ 'b ⇒ 'b" (infixl ‹⋅''› 70) and unit' :: "'b" (‹𝟭''›) assumes "monoid_isomorphism η M (⋅) 𝟭 M' (⋅') 𝟭'" I tried to use Query > Print Context tab with all boxes ticked and the resulting contexts for the two definitions of this locale are exactly the same (syntactically). I can't understand why such seemingly benign change would completely derail a proof. I have uploaded the full code to https://github.com/aleksander-mendoza/Isabelle
The answer turned out to be very simple. One definition was assumes commutes_with_composition: "⟦ x ∈ M; y ∈ M ⟧ ⟹ η (x ⋅ y) = η x ⋅' η y" while the other was assumes commutes_with_composition: "⟦ x ∈ M; y ∈ M ⟧ ⟹ η x ⋅' η y = η (x ⋅ y)" This has an important impact on auto and simp because they always try to match left side and replace the matched terms with right side. In order to make the proof work it was enough to add [symmetric] using commutes_with_composition[symmetric] commutes_with_unit surjective
Rewrite with implications in Isabelle
I am looking for a method to do rewriting, but with implications instead of equalities. For example I know that x = 3 ∧ y = 4 implies Q x y and now I want to replace a positive occurrence of Q x y in my current subgoal with x = 3 ∧ y = 4. Is there an existing method in Isabelle to do this? For example I would like to do somthing like this (where implication_subst is the name of the method I am looking for): lemma assumes a1: "⋀x y. x = 3 ∧ y = 4 ⟹ Q x y" shows "(∃x y. A x ∧ Q x y ∧ B y)" proof (implication_subst a1) show "∃x y. A x ∧ (x = 3 ∧ y = 4) ∧ B y" sorry qed Below is my (incomplete) attempt to implement such a method using Eisbach, maybe this gives a better idea of what I am looking for: named_theorems pos_cong lemma implication_subst_exists[pos_cong]: assumes "⋀x. P x ⟹ Q x" and "∃x. P x" shows "∃x. Q x" using assms by blast lemma implication_subst_conjl[pos_cong]: assumes "P ⟹ Q" and "P ∧ A" shows "Q ∧ A" using assms by blast lemma implication_subst_conjr[pos_cong]: assumes "P ⟹ Q" and "A ∧ P" shows "A ∧ Q" using assms by blast lemma implication_subst_neg[pos_cong]: assumes "P ⟹ Q" and "P" shows "¬¬Q" using assms by auto lemma implication_subst_impl[pos_cong]: assumes "P ⟹ ¬Q" and "¬P ⟶ A" shows "Q ⟶ A" using assms by auto lemma implication_subst_impr[pos_cong]: assumes "P ⟹ Q" and "A ⟶ P" shows "A ⟶ Q" using assms by auto lemma implication_subst_neg_disj_l[pos_cong]: assumes "P ⟹ ¬Q" and "¬(¬P ∨ A)" shows "¬(Q ∨ A)" using assms by auto lemma implication_subst_neg_disj_r[pos_cong]: assumes "P ⟹ ¬Q" and "¬(A ∨ ¬P)" shows "¬(A ∨ Q)" using assms by auto method implication_subst_h uses r declares pos_cong = ( rule r | (rule pos_cong, implication_subst_h r: r, assumption)) method implication_subst uses r declares pos_cong = (implication_subst_h r: r pos_cong: pos_cong, (unfold not_not)?) lemma example1: assumes a1: "⋀x y. x = 3 ∧ y = 4 ⟹ Q x y" shows "∃x y. A x ∧ Q x y ∧ B y" proof (implication_subst r: a1) show "∃x y. A x ∧ (x = 3 ∧ y = 4) ∧ B y" sorry qed lemma example2: assumes a1: "⋀x y. x = 3 ∧ y = 4 ⟹ Q x y" shows "(∃x y. ¬(¬A x ∨ ¬Q x y ∨ ¬B y))" proof (implication_subst r: a1) show "∃x y. ¬ (¬ A x ∨ ¬ (x = 3 ∧ y = 4) ∨ ¬ B y)" sorry qed
A quick way to arrive to the abelian group of order eight in Isabelle
I'm formalizing this article in Isabelle. In section 4.1 it describes the following setting: context fixes c d :: real assumes "c ≠ 0" "∃ b. c = b^2" "∃ b'. d = b'^2" begin definition t where "t = sqrt(d/c)" definition e' where "e' x y = x^2 + y^2 - 1 - t^2 * x^2 * y^2" definition ρ where "ρ x y = (-y,x)" definition τ where "τ x y = (1/(t*x),1/(t*y))" It then defines G to be the abelian group of order eight generated by ρ and τ. Is there an easy way of: Stating that ρ and τ generate a group. Since ρ and τ have order 2 and commute I think that all the rest commute and maybe there is a built-in theorem saying that this has to correspond to an abelian group of order 8?
I did make an attempt to solve the problem and came up with a slightly forceful method for its solution: context fixes c d :: real assumes "c ≠ 0" "∃b. c = b^2" "∃b'. d = b'^2" begin definition t where "t = sqrt(d/c)" definition e' where "e' x y = x^2 + y^2 - 1 - t^2 * x^2 * y^2" context assumes nz_t: "t ≠ 0" begin definition ρ :: "real × real ⇒ real × real" where "ρ z = (-snd z, fst z)" definition τ :: "real × real ⇒ real × real" where "τ z = (1/(t*fst z), 1/(t*snd z))" definition S where "S ≡ { id, (λz. (-snd z, fst z)), (λz. (-fst z, -snd z)), (λz. (snd z, -fst z)), (λz. (1/(t*fst z), 1/(t*snd z))), (λz. (-1/(t*snd z), 1/(t*fst z))), (λz. (-1/(t*fst z), -1/(t*snd z))), (λz. (1/(t*snd z), -1/(t*fst z))) }" definition ρS where "ρS ≡ {id, (λz. (-snd z, fst z)), (λz. (-fst z, -snd z)), (λz. (snd z, -fst z))}" definition τS where "τS ≡ {id, (λz. (1/(t*fst z), 1/(t*snd z)))}" definition BIJ where "BIJ = ⦇carrier = {f. bij f}, mult = comp, one = id⦈" interpretation bij: group BIJ unfolding BIJ_def apply unfold_locales subgoal by (simp add: bij_comp) subgoal by (simp add: comp_assoc) subgoal by simp subgoal by simp subgoal by simp subgoal unfolding Units_def by clarsimp (metis inj_iff bij_betw_def bij_betw_inv_into inv_o_cancel surj_iff) done (*the proof may take quite a few seconds*) lemma comp_S: "x ∈ S ⟹ y ∈ S ⟹ x ∘ y ∈ S" unfolding comp_apply S_def Set.insert_iff by (elim disjE) fastforce+ lemma comm_S: "x ∈ S ⟹ y ∈ S ⟹ x ∘ y = y ∘ x" unfolding comp_apply S_def Set.insert_iff by (elim disjE) fastforce+ lemma bij_ρ: "bij ρ" unfolding bij_def inj_def surj_def ρ_def by clarsimp (metis add.inverse_inverse) lemma bij_τ: "bij τ" unfolding bij_def inj_def surj_def τ_def proof(simp add: nz_t, intro allI, intro exI) fix a show "a = 1 / (t * (1/(a*t)))" using nz_t by simp qed lemma generate_ρτ: "generate BIJ {ρ, τ} = S" proof(standard; intro subsetI) have inv_τ: "inv⇘BIJ⇙ τ = τ" unfolding m_inv_def proof(standard) show "τ ∈ carrier BIJ ∧ τ ⊗⇘BIJ⇙ τ = 𝟭⇘BIJ⇙ ∧ τ ⊗⇘BIJ⇙ τ = 𝟭⇘BIJ⇙" unfolding BIJ_def apply(intro conjI) subgoal using bij_τ by simp subgoal unfolding τ_def using nz_t by auto subgoal unfolding τ_def using nz_t by auto done then show "y ∈ carrier BIJ ∧ τ ⊗⇘BIJ⇙ y = 𝟭⇘BIJ⇙ ∧ y ⊗⇘BIJ⇙ τ = 𝟭⇘BIJ⇙ ⟹ y = τ" for y unfolding BIJ_def by (auto intro: left_right_inverse_eq) qed define ρ' :: "real × real ⇒ real × real" where "ρ' = (λz. (snd z, -fst z))" have bij_ρ': "bij ρ'" unfolding bij_def inj_def surj_def ρ'_def by simp (metis add.inverse_inverse) have inv_ρ: "inv⇘BIJ⇙ ρ = ρ'" unfolding m_inv_def proof(standard) show "ρ' ∈ carrier BIJ ∧ ρ ⊗⇘BIJ⇙ ρ' = 𝟭⇘BIJ⇙ ∧ ρ' ⊗⇘BIJ⇙ ρ = 𝟭⇘BIJ⇙" unfolding BIJ_def apply(intro conjI) subgoal using bij_ρ' by auto subgoal unfolding ρ_def ρ'_def by auto subgoal unfolding ρ_def ρ'_def by auto done then show "y ∈ carrier BIJ ∧ ρ ⊗⇘BIJ⇙ y = 𝟭⇘BIJ⇙ ∧ y ⊗⇘BIJ⇙ ρ = 𝟭⇘BIJ⇙ ⟹ y = ρ'" for y unfolding BIJ_def by (auto intro: left_right_inverse_eq) qed have ττ: "τ ⊗⇘BIJ⇙ τ = 𝟭⇘BIJ⇙" unfolding BIJ_def τ_def comp_def by (auto simp: nz_t) show "x ∈ generate BIJ {ρ, τ} ⟹ x ∈ S" for x apply(induction rule: generate.induct) subgoal unfolding BIJ_def S_def by auto subgoal unfolding BIJ_def S_def ρ_def τ_def by auto subgoal unfolding Set.insert_iff apply(elim disjE) subgoal using inv_ρ unfolding BIJ_def S_def ρ_def ρ'_def by simp subgoal using inv_τ unfolding BIJ_def S_def τ_def by simp subgoal by simp done subgoal unfolding BIJ_def by (metis monoid.select_convs(1) comp_S) done show "x ∈ S ⟹ x ∈ generate BIJ {ρ, τ}" for x unfolding S_def Set.insert_iff proof(elim disjE; clarsimp) show "id ∈ generate BIJ {ρ, τ}" unfolding BIJ_def using generate.simps by fastforce show ρ_gen: "(λz. (- snd z, fst z)) ∈ generate BIJ {ρ, τ}" by (fold ρ_def, rule generate.simps[THEN iffD2]) simp show τ_gen: "(λz. (1 / (t * fst z), 1 / (t * snd z))) ∈ generate BIJ {ρ, τ}" by (fold τ_def) (simp add: generate.incl) from inv_ρ show inv_ρ_gen: "(λz. (snd z, - fst z)) ∈ generate BIJ {ρ, τ}" by (fold ρ'_def) (auto simp: generate.inv insertI1) show ρρ_gen: "(λz. (- fst z, - snd z)) ∈ generate BIJ {ρ, τ}" proof- have ρρ: "(λz. (- fst z, - snd z)) = ρ ⊗⇘BIJ⇙ ρ" unfolding ρ_def BIJ_def by auto show ?thesis apply(rule generate.simps[THEN iffD2]) using ρρ ρ_gen[folded ρ_def] by auto qed show "(λz. (- (1 / (t * snd z)), 1 / (t * fst z))) ∈ generate BIJ {ρ, τ}" proof- have ρτ: "(λz. (- (1 / (t * snd z)), 1 / (t * fst z))) = ρ ⊗⇘BIJ⇙ τ" unfolding ρ_def τ_def BIJ_def by auto show ?thesis apply(rule generate.simps[THEN iffD2]) using ρτ ρ_gen[folded ρ_def] τ_gen[folded τ_def] by auto qed show "(λz. (- (1 / (t * fst z)), - (1 / (t * snd z)))) ∈ generate BIJ {ρ, τ}" proof- have ρρτ: "(λz. (- (1 / (t * fst z)), - (1 / (t * snd z)))) = (λz. (- fst z, - snd z)) ⊗⇘BIJ⇙ τ" unfolding τ_def BIJ_def by auto show ?thesis apply(rule generate.simps[THEN iffD2]) using ρρτ ρρ_gen τ_gen[folded τ_def] by auto qed show "(λz. (1 / (t * snd z), - (1 / (t * fst z)))) ∈ generate BIJ {ρ, τ}" proof- have inv_ρ_τ: "(λz. (1 / (t * snd z), - (1 / (t * fst z)))) = (λz. (snd z, - fst z)) ⊗⇘BIJ⇙ τ" unfolding τ_def BIJ_def by auto show ?thesis apply(rule generate.simps[THEN iffD2]) using inv_ρ_τ inv_ρ_gen τ_gen[folded τ_def] by auto qed qed qed lemma "comm_group (BIJ⦇carrier := (generate BIJ {ρ, τ})⦈)" proof- have ρτ_ss_BIJ: "{ρ, τ} ⊆ carrier BIJ" using bij_ρ bij_τ unfolding BIJ_def by simp interpret ρτ_sg: subgroup "(generate BIJ {ρ, τ})" BIJ using ρτ_ss_BIJ by (rule bij.generate_is_subgroup) interpret ρτ_g: group "BIJ⦇carrier := (generate BIJ {ρ, τ})⦈" by (rule ρτ_sg.subgroup_is_group[OF bij.group_axioms]) have car_S: "carrier (BIJ⦇carrier := S⦈) = S" by simp have BIJ_comp: "x ⊗⇘BIJ⦇carrier := S⦈⇙ y = x ∘ y" for x y unfolding BIJ_def by auto from ρτ_g.group_comm_groupI[ unfolded generate_ρτ car_S BIJ_comp, OF comm_S, simplified ] show ?thesis unfolding generate_ρτ by assumption qed lemma id_pair_def: "(λx. x) = (λz. (fst z, snd z))" by simp lemma distinct_single: "distinct [x] = True" by simp lemma ne_ff'_gg'_imp_ne_fgf'g': assumes "f ≠ f' ∨ g ≠ g'" shows "(λz. (f (fst z) (snd z), g (fst z) (snd z))) ≠ (λz. (f' (fst z) (snd z), g' (fst z) (snd z)))" using assms proof(rule disjE) assume "f ≠ f'" then obtain x y where "f x y ≠ f' x y" by blast then show ?thesis by (metis (hide_lams) fst_eqD snd_eqD) next assume "g ≠ g'" then obtain x y where "g x y ≠ g' x y" by blast then show ?thesis by (metis (hide_lams) fst_eqD snd_eqD) qed lemma id_ne_hyp: "(λa. a) ≠ (λa. 1/(t*a))" proof(rule ccontr, simp) assume id_eq_hyp: "(λa. a) = (λa. 1/(t*a))" { fix a :: real assume "a > 0" define b where "b = sqrt(a)" from ‹a > 0› have "a = b*b" and "b > 0" unfolding b_def by auto from id_eq_hyp have "b = 1/(t*b)" by metis with ‹b > 0› have "b div b =(1/(t*b)) div b" by simp with ‹b > 0› have "1 = (1/(t*a))" unfolding ‹a = b*b› by simp with ‹a > 0› nz_t have "t*a = 1" by simp } note ta_eq_one = this define t2 where "t2 = (if t > 0 then 2/t else -2/t)" with nz_t have "t2 > 0" unfolding t2_def by auto from nz_t have "t*t2 = 2 ∨ t*t2 = -2" unfolding t2_def by auto from ta_eq_one ‹t2 > 0› this show False by auto qed lemma id_ne_mhyp: "(λa. a) ≠ (λa. -1/(t*a))" proof(rule ccontr, simp) assume id_eq_hyp: "(λa. a) = (λa. -(1/(t*a)))" { fix a :: real assume "a > 0" define b where "b = sqrt(a)" from ‹a > 0› have "a = b*b" and "b > 0" unfolding b_def by auto from id_eq_hyp have "b = -(1/(t*b))" by metis with ‹b > 0› have "b div b =-1/(t*b) div b" by simp with ‹b > 0› have "1 = -1/(t*a)" unfolding ‹a = b*b› by simp with ‹a > 0› nz_t have "t*a = -1" by (metis divide_eq_1_iff) } note ta_eq_one = this define t2 where "t2 = (if t > 0 then 2/t else -2/t)" with nz_t have "t2 > 0" unfolding t2_def by auto from nz_t have "t*t2 = 2 ∨ t*t2 = -2" unfolding t2_def by auto from ta_eq_one ‹t2 > 0› this show False by auto qed lemma mid_ne_hyp: "(λa. -a) ≠ (λa. 1 / (t*a))" using id_ne_mhyp by (metis minus_divide_left minus_equation_iff) lemma mid_ne_mhyp: "(λa. -a) ≠ (λa. -1 / (t*a))" using id_ne_hyp by (metis divide_minus_left minus_equation_iff) lemma hyp_neq_hyp_1: "(λa. - 1/(t*a)) ≠ (λa. 1/(t*a))" using nz_t by (metis divide_cancel_right id_ne_mhyp mult_cancel_right1 mult_left_cancel one_neq_neg_one) lemma distinct: "distinct [ id, (λz. (-snd z, fst z)), (λz. (-fst z, -snd z)), (λz. (snd z, -fst z)), (λz. (1/(t*fst z), 1/(t*snd z))), (λz. (-1/(t*snd z), 1/(t*fst z))), (λz. (-1/(t*fst z), -1/(t*snd z))), (λz. (1/(t*snd z), -1/(t*fst z))) ]" apply(unfold distinct_length_2_or_more)+ unfolding distinct_length_2_or_more distinct_single id_def id_pair_def HOL.simp_thms(21) by (intro conjI) ( rule ne_ff'_gg'_imp_ne_fgf'g', metis one_neq_neg_one id_ne_hyp id_ne_mhyp mid_ne_hyp mid_ne_mhyp hyp_neq_hyp_1 )+ lemma "card S = 8" using distinct unfolding S_def using card_empty card_insert_disjoint by auto end end Remarks I relied on sledgehammer for many parts of the proofs and there is some unnecessary code duplication. Therefore, just like most of my answers on SO, this answer is far from perfect from the perspective of the coding style. I would be interested to know if there is a better overall approach for the solution. Somehow, I came to believe that most of the more thoughtful approaches (e.g. using theorems about cyclic groups to determine the order of ρ and τ and then using |HK|=|H||K|/|H∩K| to determine the order of G) would require proving quite a number of additional theorems for HOL-Algebra, but I did not check with the AFP before making this remark and I do not use HOL-Algebra on a regular basis. Therefore, I may have missed something.
What kind of functions preserve properties of closure?
I'm trying to prove the following lemmas: lemma tranclp_fun_preserve: "(⋀x y. x ≠ y ⟹ f x ≠ f y) ⟹ (⋀x y. f x ≠ f y ⟹ x ≠ y) ⟹ (⋀x y. f x = f y ⟹ x = y) ⟹ (λ x y. P x y)⇧+⇧+ (f x) (f y) ⟹ (λ x y. P (f x) (f y))⇧+⇧+ x y" apply (erule tranclp.cases) apply blast lemma tranclp_fun_preserve2: "(⋀x y. x ≠ y ⟹ f x ≠ f y) ⟹ (⋀x y. f x ≠ f y ⟹ x ≠ y) ⟹ (⋀x y. f x = f y ⟹ x = y) ⟹ (λ x y. P (f x) (f y))⇧+⇧+ x y ⟹ (λ x y. P x y)⇧+⇧+ (f x) (f y)" apply (erule tranclp.cases) apply blast However, I'm stuck. Should I choose another set of assumptions for the function f? Could you suggest how to prove the lemmas tranclp_fun_preserve and tranclp_fun_preserve2? UPDATE My function is injective with a special property described at the end. I'm afraid that the following example is too long. However, I want to make it a little bit more realistic. Here are two auxiliary types errorable and nullable: (*** errorable ***) notation bot ("⊥") typedef 'a errorable ("_⇩⊥" [21] 21) = "UNIV :: 'a option set" .. definition errorable :: "'a ⇒ 'a errorable" ("_⇩⊥" [1000] 1000) where "errorable x = Abs_errorable (Some x)" instantiation errorable :: (type) bot begin definition "⊥ ≡ Abs_errorable None" instance .. end free_constructors case_errorable for errorable | "⊥ :: 'a errorable" apply (metis Rep_errorable_inverse bot_errorable_def errorable_def not_Some_eq) apply (metis Abs_errorable_inverse UNIV_I errorable_def option.inject) by (simp add: Abs_errorable_inject bot_errorable_def errorable_def) (*** nullable ***) class opt = fixes null :: "'a" ("ε") typedef 'a nullable ("_⇩□" [21] 21) = "UNIV :: 'a option set" .. definition nullable :: "'a ⇒ 'a nullable" ("_⇩□" [1000] 1000) where "nullable x = Abs_nullable (Some x)" instantiation nullable :: (type) opt begin definition "ε ≡ Abs_nullable None" instance .. end free_constructors case_nullable for nullable | "ε :: 'a nullable" apply (metis Rep_nullable_inverse null_nullable_def nullable_def option.collapse) apply (simp add: Abs_nullable_inject nullable_def) by (metis Abs_nullable_inverse UNIV_I null_nullable_def nullable_def option.distinct(1)) Two kinds of values: datatype any = BoolVal "bool⇩⊥" | NatVal "nat⇩⊥" | RealVal "real⇩⊥" | InvalidAny unit datatype oany = OBoolVal "bool⇩⊥⇩□" | ONatVal "nat⇩⊥⇩□" | ORealVal "real⇩⊥⇩□" | OInvalidAny "unit⇩□" Here is a concrete example of the function f (any_to_oany), it's injective: inductive any_oany :: "any ⇒ oany ⇒ bool" where "any_oany (BoolVal x) (OBoolVal x⇩□)" | "any_oany (NatVal x) (ONatVal x⇩□)" | "any_oany (RealVal x) (ORealVal x⇩□)" | "any_oany (InvalidAny x) (OInvalidAny x⇩□)" fun any_to_oany :: "any ⇒ oany" where "any_to_oany (BoolVal x) = (OBoolVal x⇩□)" | "any_to_oany (NatVal x) = (ONatVal x⇩□)" | "any_to_oany (RealVal x) = (ORealVal x⇩□)" | "any_to_oany (InvalidAny x) = (OInvalidAny x⇩□)" lemma any_oany_eq_fun: "any_oany x y ⟷ any_to_oany x = y" by (cases x; cases y; auto simp: any_oany.simps) Here is a concrete example of the relation P (cast_oany): inductive cast_any :: "any ⇒ any ⇒ bool" where "cast_any (BoolVal ⊥) (InvalidAny ())" | "cast_any (NatVal ⊥) (RealVal ⊥)" | "cast_any (NatVal x⇩⊥) (RealVal (real x)⇩⊥)" | "cast_any (RealVal ⊥) (InvalidAny ())" inductive cast_oany :: "oany ⇒ oany ⇒ bool" where "cast_any x y ⟹ any_oany x ox ⟹ any_oany y oy ⟹ cast_oany ox oy" | "cast_oany (OBoolVal ε) (OInvalidAny ε)" | "cast_oany (ONatVal ε) (ORealVal ε)" | "cast_oany (ORealVal ε) (OInvalidAny ε)" I proved equivalence of cast_any and cast_oany on any: lemma cast_any_implies_cast_oany: "cast_any x y ⟹ cast_oany (any_to_oany x) (any_to_oany y)" by (simp add: any_oany_eq_fun cast_oany.intros(1)) lemma cast_oany_implies_cast_any: "cast_oany (any_to_oany x) (any_to_oany y) ⟹ cast_any x y" by (cases x; cases y; simp add: any_oany.simps cast_oany.simps) And my final goal is to prove similar lemmas for the transitive closures of these relations: lemma trancl_cast_oany_implies_cast_any: "cast_oany⇧+⇧+ (any_to_oany x) (any_to_oany y) ⟹ cast_any⇧+⇧+ x y" lemma trancl_cast_any_implies_cast_oany: "cast_any⇧+⇧+ x y ⟹ cast_oany⇧+⇧+ (any_to_oany x) (any_to_oany y)" I proved the following intermediate lemmas: lemma trancl_cast_oany_implies_cast_any': "(λx y. cast_oany (any_to_oany x) (any_to_oany y))⇧+⇧+ x y ⟹ cast_any⇧+⇧+ x y" apply (erule tranclp_trans_induct) apply (simp add: cast_oany_implies_cast_any tranclp.r_into_trancl) by auto lemma trancl_cast_any_implies_cast_oany': "cast_any⇧+⇧+ x y ⟹ (λx y. cast_oany (any_to_oany x) (any_to_oany y))⇧+⇧+ x y" apply (erule tranclp_trans_induct) apply (simp add: cast_any_implies_cast_oany tranclp.r_into_trancl) by auto At last, if I could prove the following lemmas from the original question, then I will able to prove my goal lemmas. lemma tranclp_fun_preserve: "cast_oany⇧+⇧+ (any_to_oany x) (any_to_oany y) ⟹ (λx y. cast_oany (any_to_oany x) (any_to_oany y))⇧+⇧+ x y" lemma tranclp_fun_preserve2: "(λx y. cast_oany (any_to_oany x) (any_to_oany y))⇧+⇧+ x y ⟹ cast_oany⇧+⇧+ (any_to_oany x) (any_to_oany y)" In this paragraph I provide an important property of the function any_to_oany. The set of oany values consists of two parts: nulls (OBoolVal ε, ONatVal ε, ORealVal ε, OInvalidAny ε) all other values. The relation cast_oany relates the values inside the first part and inside the second part separately. There is no relation between the values from different parts. The function any_to_oany maps values only to the second part. I don't know what is the right name of this property: subsets 1 and 2 are "closed" with respect to the relation cast_oany. And the function any_to_oany maps values only to one subset, and it's bijective on this subset.
The answer presented below is a substantial revision of the original answer. The original answer is available through the revision history. Effectively, in the course of the initial revisions it was established that the question comes down to merely proving that bijective functions between two sets preserve the properties of closure. The solution below presents the relevant proofs without the application-specific context (the answer also combines some of the amendments to the original answer that were made by the author of the thread): section ‹Extension of the theory #{text Transitive_Closure}› theory Transitive_Closure_Ext imports Complex_Main "HOL-Library.FuncSet" begin lemma trancl_subset_trancl: "r ⊆ s⇧+ ⟹ r⇧+ ⊆ s⇧+" by (metis subsetI trancl_id trancl_mono trans_trancl) lemma mono_tranclp[mono]: "(⋀a b. R a b ⟶ S a b) ⟹ R⇧+⇧+ a b ⟶ S⇧+⇧+ a b" apply(rule) using trancl_mono[to_pred] by blast lemma tranclp_mono: "R ≤ S ⟹ R⇧+⇧+ ≤ S⇧+⇧+" by (metis (full_types) mono_tranclp predicate2D predicate2I) lemma preserve_tranclp: assumes "⋀x y. R x y ⟹ S (f x) (f y)" shows "R⇧+⇧+ x y ⟹ S⇧+⇧+ (f x) (f y)" proof - assume Rpp: "R⇧+⇧+ x y" define P where P: "P = (λx y. S⇧+⇧+ (f x) (f y))" define r where r: "r = (λx y. S (f x) (f y))" have major: "r⇧+⇧+ x y" by (insert assms Rpp r; erule tranclp_trans_induct; auto) have cases_1: "r x y ⟹ P x y" for x y unfolding r P by simp have cases_2: "r⇧+⇧+ x y ⟹ P x y ⟹ r⇧+⇧+ y z ⟹ P y z ⟹ P x z" for x y z unfolding P by simp from major cases_1 cases_2 have "P x y" by (rule tranclp_trans_induct) thus "S⇧+⇧+ (f x) (f y)" unfolding P . qed lemma preserve_trancl: assumes "map_prod f f ` r ⊆ s" shows "map_prod f f ` r⇧+ ⊆ s⇧+" proof - from assms have "(x, y) ∈ r ⟶ (f x, f y) ∈ s" for x y by auto then have "(x, y) ∈ r⇧+ ⟶ (f x, f y) ∈ s⇧+" for x y by (metis preserve_tranclp[to_set]) thus "map_prod f f ` r⇧+ ⊆ s⇧+" by clarsimp qed lemma preserve_tranclp_inv: assumes bij_f: "bij_betw f a b" and R: "⋀x y. R x y ⟹ (x, y) ∈ a × a" and S: "⋀x y. S x y ⟹ (x, y) ∈ b × b" and S_R: "⋀x y. (x, y) ∈ a × a ⟹ S (f x) (f y) ⟹ R x y" shows "(x, y) ∈ a × a ⟹ S⇧+⇧+ (f x) (f y) ⟹ R⇧+⇧+ x y" proof - assume x_y_in_aa: "(x, y) ∈ a × a" assume Spp: "S⇧+⇧+ (f x) (f y)" define g where g: "g = the_inv_into a f" define gr where gr: "gr = restrict g b" define P where P: "P = (λx y. (x, y) ∈ b × b ⟶ R⇧+⇧+ (gr x) (gr y))" from Spp have fx_fy_in_bb: "(f x, f y) ∈ b × b" using S by (metis converse_tranclpE mem_Sigma_iff tranclp.cases) have cases_1: "S x y ⟹ P x y" for x y unfolding P proof(rule impI) assume Sxy: "S x y" and xy_in_bb: "(x, y) ∈ b × b" with bij_f have gr_in_aa: "(gr x, gr y) ∈ a × a" unfolding gr g apply(auto) using bij_betwE bij_betw_the_inv_into by blast+ from bij_f xy_in_bb have "x = f (gr x)" and "y = f (gr y)" unfolding gr g using f_the_inv_into_f_bij_betw by fastforce+ with Sxy have S_fgrx_fgry: "S (f (gr x)) (f (gr y))" by simp from gr_in_aa S_fgrx_fgry have "R (gr x) (gr y)" by (rule S_R) thus "R⇧+⇧+ (gr x) (gr y)" .. qed with bij_f S have "S⇧+⇧+ x y ⟹ S⇧+⇧+ y z ⟹ x ∈ b ⟹ z ∈ b ⟹ y ∈ b" for x y z by (auto dest: SigmaD1 tranclpD) with P have cases_2: "S⇧+⇧+ x y ⟹ P x y ⟹ S⇧+⇧+ y z ⟹ P y z ⟹ P x z" for x y z by auto from Spp cases_1 cases_2 have "P (f x) (f y)" by (rule tranclp_trans_induct) with bij_f fx_fy_in_bb x_y_in_aa show "R⇧+⇧+ x y" unfolding P gr g restrict_def bij_betw_def by (simp add: the_inv_into_f_f) qed lemma preserve_trancl_inv: assumes bij_f: "bij_betw f a b" and r_in_aa: "r ⊆ a × a" and s_in_bb: "s ⊆ b × b" and s_r: "(map_prod f f -` s) ∩ (a × a) ⊆ r ∩ (a × a)" shows "(map_prod f f -` s⇧+) ∩ (a × a) ⊆ r⇧+ ∩ (a × a)" proof - from r_in_aa have r_in_aa_set: "(x, y) ∈ r ⟹ (x, y) ∈ a × a" for x y by auto from s_in_bb have s_in_bb_set: "⋀x y. (x, y) ∈ s ⟹ (x, y) ∈ b × b" by auto from s_r have s_r_set: "(x, y) ∈ a × a ⟹ (f x, f y) ∈ s ⟹ (x, y) ∈ r" for x y unfolding map_prod_def by auto from bij_f r_in_aa_set s_in_bb_set s_r_set have "(x, y) ∈ a × a ⟹ (f x, f y) ∈ s⇧+ ⟹ (x, y) ∈ r⇧+" for x y by (rule preserve_tranclp_inv[to_set]) thus ?thesis unfolding map_prod_def by clarsimp qed lemma preserve_rtranclp: assumes "⋀x y. R x y ⟹ S (f x) (f y)" shows "R⇧*⇧* x y ⟹ S⇧*⇧* (f x) (f y)" by (insert assms, metis Nitpick.rtranclp_unfold preserve_tranclp) lemma preserve_rtrancl: assumes "map_prod f f ` r ⊆ s" shows "map_prod f f ` r⇧* ⊆ s⇧*" proof - from assms have "(x, y) ∈ r ⟶ (f x, f y) ∈ s" for x y by auto then have "(x, y) ∈ r⇧* ⟶ (f x, f y) ∈ s⇧*" for x y by (metis preserve_rtranclp[to_set]) thus "map_prod f f ` r⇧* ⊆ s⇧*" by clarsimp qed lemma preserve_rtranclp_inv: assumes bij_f: "bij_betw f a b" and "⋀x y. R x y ⟹ (x, y) ∈ a × a" and "⋀x y. S x y ⟹ (x, y) ∈ b × b" and "⋀x y. (x, y) ∈ a × a ⟹ S (f x) (f y) ⟹ R x y" shows "(x, y) ∈ a × a ⟹ S⇧*⇧* (f x) (f y) ⟹ R⇧*⇧* x y" proof - assume xy_in_aa: "(x, y) ∈ a × a" and Spp: "S⇧*⇧* (f x) (f y)" show "R⇧*⇧* x y" proof(cases "f x ≠ f y") case True show ?thesis proof - from True Spp obtain z where "S⇧*⇧* (f x) z" and "S z (f y)" by (auto elim: rtranclp.cases) then have "S⇧+⇧+ (f x) (f y)" by (rule rtranclp_into_tranclp1) with assms xy_in_aa have "R⇧+⇧+ x y" by (rule preserve_tranclp_inv) thus ?thesis by simp qed next case False show ?thesis proof - from False xy_in_aa bij_f have "x = y" unfolding bij_betw_def by (auto dest: SigmaD1 SigmaD2 inj_onD) thus "R⇧*⇧* x y" by simp qed qed qed lemma preserve_rtrancl_inv: assumes bij_f: "bij_betw f a b" and r_in_aa: "r ⊆ a × a" and s_in_bb: "s ⊆ b × b" and as_s_r: "(map_prod f f -` s) ∩ (a × a) ⊆ r ∩ (a × a)" shows "(map_prod f f -` s⇧*) ∩ (a × a) ⊆ r⇧* ∩ (a × a)" proof - from r_in_aa have r_in_aa_set: "(x, y) ∈ r ⟹ (x, y) ∈ a × a" for x y by auto from s_in_bb have s_in_bb_set: "(x, y) ∈ s ⟹ (x, y) ∈ b × b" for x y by auto from as_s_r have s_r: "(x, y) ∈ a × a ⟹ (f x, f y) ∈ s ⟹ (x, y) ∈ r" for x y unfolding map_prod_def by auto from bij_f r_in_aa_set s_in_bb_set s_r have "(x, y) ∈ a × a ⟹ (f x, f y) ∈ s⇧* ⟹ (x, y) ∈ r⇧*" for x y by (rule preserve_rtranclp_inv[to_set]) thus ?thesis unfolding map_prod_def by clarsimp qed end