Isabelle multiply both sides of an equation (equational reasoning in Isar) - isabelle

I want to prove that inverse element is unique in a monoid M
theorem inverse_unique:
assumes "u β‹… v' = 𝟭"
assumes "v β‹… u = 𝟭"
assumes "u ∈ M"
assumes "v ∈ M"
assumes "v' ∈ M"
shows "v = v'"
proof -
have "v β‹… u β‹… v' = v β‹… 𝟭"
apply (rule arg_cong[of "u β‹… v'" 𝟭 "Ξ» x. vβ‹…x"])
The idea is to show the following steps
vβ‹…uβ‹…v'=πŸ­β‹…v' by congruence (multiplying both sides)
vβ‹…πŸ­=πŸ­β‹…v' by monoid neutral element axiom
vβ‹…πŸ­=v' by monoid neutral element axiom
v=v' done
Unfortunately I am stuck on the very first step. I don't want to use auto or any other automatic approach. I want to do it by hand to learn how to do it.
I've been trying with apply (subst) and apply (rule arg_cong) and many variations thereof. Nothing really works.
This is the definition of monoid that I am using
locale monoid =
fixes M and composition (infixl "β‹…" 70) and unit ("𝟭")
assumes composition_closed [intro, simp]: "⟦ a ∈ M; b ∈ M ⟧ ⟹ a β‹… b ∈ M"
and unit_closed [intro, simp]: "𝟭 ∈ M"
and associative [intro]: "⟦ a ∈ M; b ∈ M; c ∈ M ⟧ ⟹ (a β‹… b) β‹… c = a β‹… (b β‹… c)"
and left_unit [intro, simp]: "a ∈ M ⟹ 𝟭 β‹… a = a"
and right_unit [intro, simp]: "a ∈ M ⟹ a β‹… 𝟭 = a"
and the theorem is in context monoid begin
Other thing I've tried is this
theorem inverse_unique:
assumes uv1:"u β‹… v' = 𝟭"
assumes vu1:"v β‹… u = 𝟭"
assumes um:"u ∈ M"
assumes vm:"v ∈ M"
assumes v'm:"v' ∈ M"
shows "v = v'"
proof -
from uv1 have "v β‹… u β‹… v' = v β‹… 𝟭"
apply(rule subst)
apply(rule associative)
which gets me quite far but the associative rule requires now
1. v ∈ M
2. u ∈ M
3. v' ∈ M
However, if I add those to from
from uv1 um vm v'm have "v β‹… u β‹… v' = v β‹… 𝟭"
then apply(rule subst) yields Failed to apply proof methodβŒ‚.
Another thing I've tried is this
theorem inverse_unique:
assumes uv1:"u β‹… v' = 𝟭"
assumes vu1:"v β‹… u = 𝟭"
assumes um:"u ∈ M"
assumes vm:"v ∈ M"
assumes v'm:"v' ∈ M"
shows "v = v'"
proof -
from uv1 have "v β‹… (u β‹… v') = v β‹… 𝟭"
apply (rule subst)
apply (rule refl)
done
from this um vm v'm have "v β‹… u β‹… v' = v β‹… 𝟭"
apply (subst associative)
apply (assumption)
apply (assumption)
apply (assumption)
apply (assumption)
done
from this vu1 have "𝟭 β‹… v' = v β‹… 𝟭"
which actually works, but then again I get stuck at the last from this vu1 have "𝟭 β‹… v' = v β‹… 𝟭" because I still don't know how to substitute 𝟭 for vu1.

If substitution rules require assumptions, it's often convenient to supply these through the [OF ...] modifier behind the equality fact. Also, rewriting in Isar proofs usually makes more fun using the unfolding keyword. Your proof from https://stackoverflow.com/a/75362601/5158425 would then read:
theorem inverse_unique:
assumes uv1: "u β‹… v' = 𝟭"
assumes vu1: "v β‹… u = 𝟭"
assumes um: "u ∈ M"
assumes vm: "v ∈ M"
assumes v'm: "v' ∈ M"
shows "v = v'"
proof -
have "v β‹… (u β‹… v') = v β‹… 𝟭" unfolding uv1 by (rule refl)
from this have "v β‹… u β‹… v' = v β‹… 𝟭" unfolding associative[OF vm um v'm] by assumption
from this have "𝟭 β‹… v' = v β‹… 𝟭" unfolding vu1 by assumption
from this have "v' = v β‹… 𝟭" unfolding left_unit[OF v'm] by assumption
from this show "v = v'" unfolding right_unit[OF vm] by (rule sym)
qed
We can make this even simpler by use of the also have ... keywords to chain equalities:
proof -
have β€Ήv = v β‹… πŸ­β€Ί using right_unit[OF vm, symmetric] .
also have β€Ή... = v β‹… (u β‹… v')β€Ί unfolding uv1 ..
also have β€Ή... = v β‹… u β‹… v'β€Ί using associative[OF vm um v'm, symmetric] .
also have β€Ή... = 𝟭 β‹… v'β€Ί unfolding vu1 ..
finally show ?thesis unfolding left_unit[OF v'm] .
qed
Here, the ... on the left-hand sides abbreviate the right-hand sides of the preceding lines. Moreover, the proof is elementar to a level that we can use the proof methods for immediate proof . and default proof ... They do roughly the same ”by assumption” and β€œby rule” would.

I found a full proof
theorem inverse_unique:
assumes uv1:"u β‹… v' = 𝟭"
assumes vu1:"v β‹… u = 𝟭"
assumes um:"u ∈ M"
assumes vm:"v ∈ M"
assumes v'm:"v' ∈ M"
shows "v = v'"
proof -
from uv1 have "v β‹… (u β‹… v') = v β‹… 𝟭"
apply (rule subst)
apply (rule refl)
done
from this um vm v'm have "v β‹… u β‹… v' = v β‹… 𝟭"
apply (subst associative)
apply (assumption)
apply (assumption)
apply (assumption)
apply (assumption)
done
from this vu1 have "𝟭 β‹… v' = v β‹… 𝟭"
apply(subst vu1[symmetric])
apply(assumption)
done
from v'm this have "v' = v β‹… 𝟭"
apply(subst left_unit[symmetric])
apply(assumption)
apply(assumption)
done
from vm this show "v = v'"
apply(subst right_unit[symmetric])
apply(assumption)
apply(rule sym)
apply(assumption)
done
qed
but it is quite long and ugly. I feel like this could have been done better (without resorting to auto).

Related

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

Existance proofs with polymorphic types

I am trying to formalize the proof that DFA are closed under union, and I have got so far as proving "βˆ€ π’œ ℬ. language π’œ βˆͺ language ℬ = language (DFA_union π’œ ℬ)", but what I would actually like to prove is βˆ€ π’œ ℬ. βˆƒ π’ž. language π’œ βˆͺ language ℬ = language π’ž. I belive the issue has something to do with polymorphic types, but I am not sure.
Here is what I have:
declare [[show_types]]
declare [[show_sorts]]
declare [[show_consts]]
record ('q, 'a)DFA =
Q0 :: 'q
F :: "'q set"
Ξ΄ :: "'q β‡’ 'a β‡’ 'q"
primrec Ξ΄_iter :: "('q, 'a)DFA β‡’ 'a list β‡’ 'q β‡’ 'q" where
"Ξ΄_iter π’œ [] q = q" |
"Ξ΄_iter π’œ (a # as) q = Ξ΄_iter π’œ as (Ξ΄ π’œ q a)"
definition Ξ΄0_iter :: "('q, 'a)DFA β‡’ 'a list β‡’ 'q" where
"Ξ΄0_iter π’œ as = Ξ΄_iter π’œ as (Q0 π’œ)"
definition language :: "('q, 'a)DFA β‡’ ('a list) set" where
"language π’œ = {w . Ξ΄0_iter π’œ w ∈ (F π’œ)}"
fun DFA_union :: "('p, 'a)DFA β‡’ ('q, 'a)DFA β‡’ ('p Γ— 'q, 'a)DFA" where
"DFA_union π’œ ℬ =
⦇ Q0 = (Q0 π’œ, Q0 ℬ)
, F = {(q, r) . q ∈ F π’œ ∨ r ∈ F ℬ}
, Ξ΄ = Ξ» (q, r). Ξ» a. (Ξ΄ π’œ q a, Ξ΄ ℬ r a)
⦈"
lemma extract_fst: "βˆ€ π’œ ℬ p q. fst (Ξ΄_iter (DFA_union π’œ ℬ) ws (p, q)) = Ξ΄_iter π’œ ws p"
by (induct ws; simp)
lemma extract_snd: "βˆ€ π’œ ℬ p q. snd (Ξ΄_iter (DFA_union π’œ ℬ) ws (p, q)) = Ξ΄_iter ℬ ws q"
by (induct ws; simp)
lemma "βˆ€ π’œ ℬ. language π’œ βˆͺ language ℬ = language (DFA_union π’œ ℬ)"
proof((rule allI)+)
fix π’œ ℬ
let ?π’ž = "DFA_union π’œ ℬ"
have "language ?π’ž = {w . Ξ΄0_iter ?π’ž w ∈ F ?π’ž}"
by (simp add: language_def)
also have "... = {w . fst (Ξ΄0_iter ?π’ž w) ∈ (F π’œ) ∨ snd (Ξ΄0_iter ?π’ž w) ∈ (F ℬ)}"
by auto
also have "... = {w . Ξ΄0_iter π’œ w ∈ F π’œ ∨ Ξ΄0_iter ℬ w ∈ F ℬ}"
using DFA.select_convs(1) DFA_union.simps Ξ΄0_iter_def extract_fst extract_snd
by (metis (no_types, lifting))
also have "... = {w . Ξ΄0_iter π’œ w ∈ F π’œ} βˆͺ {w. Ξ΄0_iter ℬ w ∈ F ℬ}"
by blast
also have "... = language π’œ βˆͺ language ℬ"
by (simp add: language_def)
finally show "language π’œ βˆͺ language ℬ = language ?π’ž"
by simp
qed
lemma DFA_union_closed: "βˆ€ π’œ ℬ. βˆƒ π’ž. language π’œ βˆͺ language ℬ = language π’ž"
sorry
If I add types to π’œ or ℬ in the main lemma I get "Failed to refine any pending goal".
the problem is indeed because of implicit types. In your last statement Isabelle implicitly infers state-types 'p, 'q, 'r for the three automata A, B, C,
whereas your DFA_union lemma fixes the state type of C to 'p * 'q. Therefore, if you have to explicitly provide type-annotations. Moreover, it is usually not required to state your lemmas with explicit βˆ€-quantifiers.
So, you can continue like this:
lemma DFA_union: "language π’œ βˆͺ language ℬ = language (DFA_union π’œ ℬ)"
(is "_ = language ?π’ž")
proof -
have "language ?π’ž = {w . Ξ΄0_iter ?π’ž w ∈ F ?π’ž}"
...
qed
lemma DFA_union_closed: fixes π’œ :: "('q,'a)DFA" and ℬ :: "('p,'a)DFA"
shows "βˆƒ π’ž :: ('q Γ— 'p, 'a)DFA. language π’œ βˆͺ language ℬ = language π’ž"
by (intro exI, rule DFA_union)
Note that these type-annotations are also essential in the following sense.
A lemma like the following (where all state-types are the same) is just not true.
lemma fixes π’œ :: "('q,'a)DFA" and ℬ :: "('q,'a)DFA"
shows "βˆƒ π’ž :: ('q, 'a)DFA. language π’œ βˆͺ language ℬ = language π’ž"
The problem is, plug in the bool-type for 'q, then you have automata which
have at most two states. And then you cannot always find an automaton for the union that also has at most two states.

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.

How to lift a transitive relation from elements to lists?

I'm trying to prove that a transitive relation on elements of lists is equivalent to a transitive relation on lists (under some conditions).
Here is a first lemma:
lemma list_all2_rtrancl1:
"(list_all2 P)⇧*⇧* xs ys ⟹
list_all2 P⇧*⇧* xs ys"
apply (induct rule: rtranclp_induct)
apply (simp add: list.rel_refl)
by (smt list_all2_trans rtranclp.rtrancl_into_rtrancl)
And here is a symmetric lemma:
lemma list_all2_rtrancl2:
"(β‹€x. P x x) ⟹
list_all2 P⇧*⇧* xs ys ⟹
(list_all2 P)⇧*⇧* xs ys"
apply (erule list_all2_induct)
apply simp
I guess that a relation should be reflexive. But maybe I should use another assumptions. The lemma could be proven given the assumption that P is transitive, however P is not transitive. I'm stuck. Could you suggest what assumptions to choose and how to prove this lemma?
It seems that nitpick gives me a wrong counterexample for the specific case of the last lemma (xs = [0] and ys = [2]):
lemma list_all2_rtrancl2_example:
"list_all2 (Ξ»x y. x = y ∨ Suc x = y)⇧*⇧* xs ys ⟹
(list_all2 (Ξ»x y. x = y ∨ Suc x = y))⇧*⇧* xs ys"
nitpick
I can prove that the lemma holds for this example:
lemma list_all2_rtrancl2_example_0_2:
"list_all2 (Ξ»x y. x = y ∨ Suc x = y)⇧*⇧* [0] [2] ⟹
(list_all2 (Ξ»x y. x = y ∨ Suc x = y))⇧*⇧* [0] [2]"
apply (rule_tac ?b="[1]" in converse_rtranclp_into_rtranclp; simp)
apply (rule_tac ?b="[2]" in converse_rtranclp_into_rtranclp; simp)
done
It may be feasible to use listrel instead of list_all2. Indeed, as shown below, they are equivalent (see set_listrel_eq_list_all2). However, there are several theorems in the standard library about listrel that do not have their equivalents for list_all2.
lemma set_listrel_eq_list_all2:
"listrel {(x, y). r x y} = {(xs, ys). list_all2 r xs ys}"
using list_all2_conv_all_nth listrel_iff_nth by fastforce
lemma listrel_tclosure_1: "(listrel r)⇧* βŠ† listrel (r⇧*)"
by
(
simp add:
listrel_rtrancl_eq_rtrancl_listrel1
listrel_subset_rtrancl_listrel1
rtrancl_subset_rtrancl
)
lemma listrel_tclosure_2: "refl r ⟹ listrel (r⇧*) βŠ† (listrel r)⇧*"
by
(
simp add:
listrel1_subset_listrel
listrel_rtrancl_eq_rtrancl_listrel1
rtrancl_mono
)
context
includes lifting_syntax
begin
lemma listrel_list_all2_transfer[transfer_rule]:
"((=) ===> (=) ===> (=) ===> (=))
(λr xs ys. (xs, ys) ∈ listrel {(x, y). r x y}) list_all2"
unfolding rel_fun_def using set_listrel_eq_list_all2 listrel_iff_nth by blast
end
lemma list_all2_rtrancl_1:
"(list_all2 r)⇧*⇧* xs ys ⟹ list_all2 r⇧*⇧* xs ys"
proof transfer
fix r :: "'a β‡’ 'a β‡’ bool" and xs :: "'a list" and ys:: "'a list"
assume "(Ξ»xs ys. (xs, ys) ∈ listrel {(x, y). r x y})⇧*⇧* xs ys"
then have "(xs, ys) ∈ (listrel {(x, y). r x y})⇧*"
unfolding rtranclp_def rtrancl_def by auto
then have "(xs, ys) ∈ listrel ({(x, y). r x y}⇧*)"
using listrel_tclosure_1 by auto
then show "(xs, ys) ∈ listrel {(x, y). r⇧*⇧* x y}"
unfolding rtranclp_def rtrancl_def by auto
qed
lemma list_all2_rtrancl_2:
"reflp r ⟹ list_all2 r⇧*⇧* xs ys ⟹ (list_all2 r)⇧*⇧* xs ys"
proof transfer
fix r :: "'a β‡’ 'a β‡’ bool" and xs :: "'a list" and ys :: "'a list"
assume as_reflp: "reflp r" and p_in_lr: "(xs, ys) ∈ listrel {(x, y). r⇧*⇧* x y}"
from as_reflp have refl: "refl {(x, y). r x y}"
using reflp_refl_eq by fastforce
from p_in_lr have "(xs, ys) ∈ listrel ({(x, y). r x y}⇧*)"
unfolding rtranclp_def rtrancl_def by auto
with refl have "(xs, ys) ∈ (listrel {(x, y). r x y})⇧*"
using listrel_tclosure_2 by auto
then show "(Ξ»xs ys. (xs, ys) ∈ listrel {(x, y). r x y})⇧*⇧* xs ys"
unfolding rtranclp_def rtrancl_def by auto
qed
A direct proof for list_all2 is also provided (legacy):
list_all2_induct is applied to the lists; the base case is trivial. Thence, it remains to show that (L P)* x#xs y#ys if (L (P*)) xs ys, (L P)* xs ys and P* x y.
The idea is that it is possible to find zs (e.g. xs) such that (L P) xs zs and (L P)+ zs ys.
Then, given that P* x y and P x x, by induction based on the transitive properties of P*, (L P) x#xs y#zs. Therefore, also, (L P)* x#xs y#zs.
Also, given that (L P)+ zs ys and P y y, by induction, (L P)+ y#zs y#ys. Thus, also, (L P)* y#zs y#ys.
From 3 and 4 conclude (L P)* x#xs y#ys.
lemma list_all2_rtrancl2:
assumes as_r: "(β‹€x. P x x)"
shows "(list_all2 P⇧*⇧*) xs ys ⟹ (list_all2 P)⇧*⇧* xs ys"
proof(induction rule: list_all2_induct)
case Nil then show ?case by simp
next
case (Cons x xs y ys) show ?case
proof -
from as_r have lp_xs_xs: "list_all2 P xs xs" by (rule list_all2_refl)
from Cons.hyps(1) have x_xs_y_zs: "(list_all2 P)⇧*⇧* (x#xs) (y#xs)"
proof(induction rule: rtranclp_induct)
case base then show ?case by simp
next
case (step y z) then show ?case
proof -
have rt_step_2: "(list_all2 P)⇧*⇧* (y#xs) (z#xs)"
by (rule r_into_rtranclp, rule list_all2_Cons[THEN iffD2])
(simp add: step.hyps(2) lp_xs_xs)
from step.IH rt_step_2 show ?thesis by (rule rtranclp_trans)
qed
qed
from Cons.IH have "(list_all2 P)⇧*⇧* (y#xs) (y#ys)"
proof(induction rule: rtranclp_induct)
case base then show ?case by simp
next
case (step ya za) show ?case
proof -
have rt_step_2: "(list_all2 P)⇧*⇧* (y#ya) (y#za)"
by (rule r_into_rtranclp, rule list_all2_Cons[THEN iffD2])
(simp add: step.hyps(2) as_r)
from step.IH rt_step_2 show ?thesis by (rule rtranclp_trans)
qed
qed
with x_xs_y_zs show ?thesis by simp
qed
qed
As a side note, in my view (I know very little about nitpick), nitpick should not provide invalid counterexamples without any warning. I believe, usually, when nitpick 'suspects' that a counterexample may be invalid it notifies the user that the example is 'potentially spurious'. It may be useful to submit a bug report if this issue has not been recorded elsewhere.
Isabelle version: Isabelle2020

Proving a theorem about parser combinators

I've written some simple parser combinators (without backtracking etc.). Here are the important definitions for my problem.
type_synonym ('a, 's) parser = "'s list β‡’ ('a * 's list) option"
definition sequenceP :: "('a, 's) parser
β‡’ ('b, 's) parser
β‡’ ('b, 's) parser" (infixl ">>P" 60) where
"sequenceP p q ≑ Ξ» i .
(case p i of
None β‡’ None
| Some v β‡’ q (snd v))"
definition consumerP :: "('a, 's) parser β‡’ bool" where
"consumerP p ≑ (βˆ€ i . (case p i of
None β‡’ True |
Some v β‡’ length (snd v) ≀ length i))"
I do want to proof the following lemma.
lemma consumerPI: "consumerP p ⟹ consumerP q ⟹ consumerP (p >>P q)"
apply (unfold sequenceP_def)
apply (simp (no_asm) add:consumerP_def)
apply clarsimp
apply (case_tac "case p i of None β‡’ None | Some v β‡’ q (snd v)")
apply simp
apply clarsimp
apply (case_tac "p i")
apply simp
apply clarsimp
apply (unfold consumerP_def)
I arrive at this proof state, at which I fail to continue.
goal (1 subgoal):
1. β‹€i a b aa ba.
βŸ¦βˆ€i. case p i of None β‡’ True | Some v β‡’ length (snd v) ≀ length i;
βˆ€i. case q i of None β‡’ True | Some v β‡’ length (snd v) ≀ length i; q ba = Some (a, b); p i = Some (aa, ba)⟧
⟹ length b ≀ length i
Can anybody give me a tip how to solve this goal?
Thanks in advance!
It turns out that if you just want to prove the lemma, without further insight, then
lemma consumerPI: "consumerP p ⟹ consumerP q ⟹ consumerP (p >>P q)"
by (smt consumerP_def le_trans option.case_eq_if sequenceP_def)
does the job.
If you want to have insight, you want to go for a structured proof. First identify some useful lemmas about consumerP, and then write a Isar proof that details the necessary steps.
lemma consumerPI[intro!]:
assumes "β‹€ i x r . p i = Some (x,r) ⟹ length r ≀ length i"
shows "consumerP p"
unfolding consumerP_def by (auto split: option.split elim: assms)
lemma consumerPE[elim, consumes 1]:
assumes "consumerP p"
assumes "p i = Some (x,r)"
shows "length r ≀ length i"
using assms by (auto simp add: consumerP_def split: option.split_asm)
lemma consumerP_sequencePI: "consumerP p ⟹ consumerP q ⟹ consumerP (p >>P q)"
proof-
assume "consumerP p"
assume "consumerP q"
show "consumerP (p >>P q)"
proof(rule consumerPI)
fix i x r
assume "(p >>P q) i = Some (x, r)"
then obtain x' r' where "p i = Some (x', r')" and "q r' = Some (x,r)"
by (auto simp add: sequenceP_def split:option.split_asm)
from `consumerP q` and `q r' = Some (x, r)`
have "length r ≀ length r'" by (rule consumerPE)
also
from `consumerP p` and `p i = Some (x', r')`
have "length r' ≀ length i" by (rule consumerPE)
finally
show "length r ≀ length i".
qed
qed
In fact, for this definition you can very nicely use the inductive command, and get intro and elim rules for free:
inductive consumerP where
consumerPI: "(β‹€ i x r . p i = Some (x,r) ⟹ length r ≀ length i) ⟹ consumerP p"
In the above proof, you can replace by (rule consumerPE) by by cases and it works.

Resources