Existance proofs with polymorphic types - isabelle

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.

Related

To prove a lemma of labeled transtion in Isabelle

The labeled transition of Isballe is defined below, which contains the prior node and the successor node, the set represents the condition.
type_synonym ('q,'a) LTS = "('q * 'a set * 'q) set"
After the LTS, we need to define a function of the reachable from Node a to Node b. The definition of LTS_is_reachable like:
inductive LTS_is_reachable :: "('q, 'a) LTS β‡’ ('q * 'q) set β‡’ 'q β‡’ 'a list β‡’ 'q β‡’ bool" for Ξ” and Ξ”' where
LTS_Empty[intro!]: "LTS_is_reachable Ξ” Ξ”' q [] q" |
LTS_Step1: "LTS_is_reachable Ξ” Ξ”' q l q'" if "(q, q'') ∈ Ξ”'" and "LTS_is_reachable Ξ” Ξ”' q'' l q'" |
LTS_Step2[intro!]: "LTS_is_reachable Ξ” Ξ”' q (a # w) q'" if "a ∈ Οƒ" and "(q, Οƒ, q'') ∈ Ξ”" and "LTS_is_reachable Ξ” Ξ”' q'' w q'"
where the LTS_empty denotes node q could arrive at self by empty list, LTS_Step1 denotes if there exists node q and p in Delta', then q could reach p no condition, and LTS_Step2 denotes that node q could reach node q'' by the alphbet sigma.
Finally, I try to prove a lemma
lemma removeFromAtoEndTrans:"LTS_is_reachable Ξ” (insert (ini, end) Ξ”') ini l end ⟹ l β‰  [] ⟹ βˆ€(q, Οƒ, p) ∈ Ξ”. q β‰  ini ∧ q β‰  end ⟹ βˆ€(end, p) ∈ Ξ”'. p = end ⟹ LTS_is_reachable Ξ” Ξ”' ini l end"
This lemma said that if the list l isn't empty, we could remove ini-> end from Delta2. It obviously holds. Through the tool nitpick, it can not find any counter-examples. But I could think about any ideas to prove it. Any helps would be appreciated.

Topological filters in Isabelle

I'm studying topological filters in Filter.thy
theory Filter
imports Set_Interval Lifting_Set
begin
subsection β€ΉFiltersβ€Ί
text β€Ή
This definition also allows non-proper filters.
β€Ί
locale is_filter =
fixes F :: "('a β‡’ bool) β‡’ bool"
assumes True: "F (Ξ»x. True)"
assumes conj: "F (λx. P x) ⟹ F (λx. Q x) ⟹ F (λx. P x ∧ Q x)"
assumes mono: "βˆ€x. P x ⟢ Q x ⟹ F (Ξ»x. P x) ⟹ F (Ξ»x. Q x)"
typedef 'a filter = "{F :: ('a β‡’ bool) β‡’ bool. is_filter F}"
proof
show "(λx. True) ∈ ?filter" by (auto intro: is_filter.intro)
qed
I don't get this definition. It's quite convoluted so I'll simplify it first
The expression
F (Ξ»x. P x) could be simplified to F P (using eta reduction of lambda calculus). The predicate 'a β‡’ bool is really just a set 'a set. Similarly ('a β‡’ bool) β‡’ bool should be 'a set set. Then we could rewrite the axioms as
assumes conj: "P ∈ F ∧ Q ∈ F ⟹ Q ∩ P ∈ F"
assumes mono: "P βŠ† Q ∧ P ∈ F ⟹ Q ∈ F"
Now my question is about the True axiom. It is equivalent to
assumes True: "UNIV ∈ F"
This does not match with the definitions of filters that I ever saw.
The axiom should be instead
assumes True: "{} βˆ‰ F" (* the name True is not very fitting anymore *)
The statement UNIV ∈ F is unnecessary because it follows from axiom mono.
So what's up with this definition that Isabelle provides?
The link provided by Javier Diaz has lots of explanations.
Turns out this is a definition of improper filter. The axiom True is necessary and does not follow from mono. If this axiom was missing then F could be defined as
F P = False
or in set-theory notation, F could be an empty set and mono and conj would then be satisfied vacuously.

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

The lemma defined in fun can work, but can not work in inductive predicate

type_synonym ('q,'a) LTS = "('q * 'a set * 'q) set"
primrec LTS_is_reachable :: "('q, 'a) LTS \<Rightarrow> 'q \<Rightarrow> 'a list \<Rightarrow> 'q \<Rightarrow> bool" where
"LTS_is_reachable \<Delta> q [] q' = (q = q')"|
"LTS_is_reachable \<Delta> q (a # w) q' =
(\<exists>q'' \<sigma>. a \<in> \<sigma> \<and> (q, \<sigma>, q'') \<in> \<Delta> \<and> LTS_is_reachable \<Delta> q'' w q')"
lemma DeltLTSlemma:"LTS_is_reachable Ξ” q x y \<Longrightarrow>LTS_is_reachable {(f a, b, f c)| a b c. (a,b,c)\<in> Ξ” } (f q) x (f y)"
apply(induct x arbitrary:q)
apply auto
done
I've defined a fun LTS_is_reachable as above, and give a lemma to prove it. But for introduce a new relation in the LTS system, i change the form into the inductive predivate below. This lemma can not work, and I am not able to handle this.
type_synonym ('q,'a) LTS = "('q * 'a set * 'q) set"
inductive LTS_is_reachable :: "('q, 'a) LTS \<Rightarrow> 'q \<Rightarrow> 'a list \<Rightarrow> 'q \<Rightarrow> bool" where
LTS_Empty:"LTS_is_reachable \<Delta> q [] q"|
LTS_Step:"(\<exists>q'' \<sigma>. a \<in> \<sigma> \<and> (q, \<sigma>, q'') \<in> \<Delta> \<and> LTS_is_reachable \<Delta> q'' w q') \<Longrightarrow> LTS_is_reachable \<Delta> q (a # w) q'"|
LTS_Epi:"(\<exists>q''. (q,{},q'') \<in> \<Delta> \<and> LTS_is_reachable \<Delta> q'' l q') \<Longrightarrow> LTS_is_reachable \<Delta> q l q'"
inductive_cases LTS_Step_cases[elim!]:"LTS_is_reachable \<Delta> q (a # w) q'"
inductive_cases LTS_Epi_cases[elim!]:"LTS_is_reachable \<Delta> q l q'"
inductive_cases LTS_Empty_cases[elim!]:"LTS_is_reachable \<Delta> q [] q"
lemma "LTS_is_reachable {(q, v, y)} q x y ⟹ LTS_is_reachable {(f q, v, f y)} (f q) x (f y)"
proof(induct x arbitrary:q)
case Nil
then show ?case
by (metis (no_types, lifting) LTS_Empty LTS_Epi LTS_Epi_cases Pair_inject list.distinct(1) singletonD singletonI)
next
case (Cons a x)
then show ?case
qed
Thank you very much for your help.
Using your inductive definition of LTS_is_reachable, you can prove your original lemma DeltLTSlemma by rule induction, that is, by using proof (induction rule: LTS_is_reachable.induct). You can learn more about rule induction in Section 3.5 of Programming and Proving in
Isabelle/HOL. As a side remark, note that you can avoid using inductive_cases since nowadays structured proofs (i.e., Isar proofs) are strongly preferred over unstructured proofs (i.e., apply-scripts).

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