how to make an example to test the rev_app immediately after lemma proved. an starting example for custom lemma - isabelle

expect to use the subgoal to run the list which defined by let? aa = [1,2]
and run rev_app on this aa and show the value as [2,1]
theory Scratch2
imports Datatype
begin
datatype 'a list = Nil ("[]")
| Cons 'a "'a list" (infixr "#" 65)
(* This is the append function: *)
primrec app :: "'a list => 'a list => 'a list" (infixr "#" 65)
where
"[] # ys = ys" |
"(x # xs) # ys = x # (xs # ys)"
primrec rev :: "'a list => 'a list" where
"rev [] = []" |
"rev (x # xs) = (rev xs) # (x # [])"
primrec itrev :: "'a list => 'a list => 'a list" where
"itrev [] ys = ys" |
"itrev (x#xs) ys = itrev xs (x#ys)"
value "rev (True # False # [])"
lemma app_Nil2 [simp]: "xs # [] = xs"
apply(induct_tac xs)
apply(auto)
done
lemma app_assoc [simp]: "(xs # ys) # zs = xs # (ys # zs)"
apply(induct_tac xs)
apply(auto)
done
(1 st trial)
lemma rev_app [simp]: "rev(xs # ys) = (rev ys) # (rev xs)"
apply(induct_tac xs)
thus ?aa by rev_app
show "rev_app [1; 2]"
(2nd trial)
value "rev_app [1,2]"
(3 rd trial)
fun ff :: "'a list ⇒ 'a list"
where "rev(xs # ys) = (rev ys) # (rev xs)"
value "ff [1,2]"
thus ?aa by rev_app
show "rev_app [1; 2]"
end

Firstly, you need the syntax for list enumeration (I just picked it up in the src/HOL/List.thy file):
syntax
-- {* list Enumeration *}
"_list" :: "args => 'a list" ("[(_)]")
translations
"[x, xs]" == "x#[xs]"
"[x]" == "x#[]"
Then, is one of the following what you're searching for ?
Proposition 1:
lemma example1: "rev [a, b] = [b, a]"
by simp
This lemma is proved by applying the definition rules of rev that are used by the method simp to rewrite the left-hand term and prove that the two sides of the equality are equal. This is the solution I prefer because you can see the example is satisfied even without evaluating it with Isabelle.
Proposition 2:
value "rev [a, b]" (* return "[b, a]" *)
Here and in Proposition 3, we just uses the command value to evaluate rev.
Proposition 3:
value "rev [a, b] = [b, a]" (* returns "True" *)
This lemma is not used by the previous propositions:
lemma rev_app [simp]: "rev(xs # ys) = (rev ys) # (rev xs)"
apply (induct_tac xs)
by simp_all
Notes:
As a general principle, you shouldn't import the "Datatype" package alone, but import "Main" instead.
In your 1st attempt you're mixing the "apply" (apply ...) and the "structured proof" (thus ...) styles
"thus ?aa" makes no sense if "?aa" is "[1,2]" as the argument of "thus" should be a subgoal, ie. a proposition with a boolean value.
To evaluate, the command "value" uses ML execution or if this fails, normalisation by evaluation.
In example1, you can use a custom proof and thus lemmas (for example: by (simp add:rev_app)

Related

How to value quantifiers in Isabelle?

definition A_list ::"char list"
where "A_list = [CHR ''#'',CHR ''a'',CHR ''b'',CHR ''c'',CHR ''b'',CHR ''d'',CHR ''a'',CHR ''b'']"
definition B_list ::"char list"
where "B_list = [CHR ''#'',CHR ''b'',CHR ''d'',CHR ''c'',CHR ''a'',CHR ''b'',CHR ''a'']"
definition "OPT i j = Max {length xs | xs. subseq xs (take i A_list) ∧ subseq xs (take j B_list)}"
Value the OPT function to see why the error occurs?
value "OPT 7 6"
Wellsortedness error
(in code equation OPT ?i ?j ≡
Max (size_list_inst.size_list `
inf_set_inst.inf_set ((λxs. xs) ` {xs. list_emb equal_char_inst.equal_char xs (take ?i A_list)})
((λxs. xs) ` {xs. list_emb equal_char_inst.equal_char xs (take ?j B_list)})),
with dependency "Pure.dummy_pattern" -> "OPT"):
Type char list not of sort enum
No type arity list :: enum

How to create appropriate lemmas to prove this lemma in Isabelle?

fun intersperse :: " 'a list ⇒ 'a ⇒ 'a list" where
"intersperse (x#y#xs) a = x#(a#(intersperse (y#xs) a))"|
"intersperse xs _ = xs"
lemma target:"map f (intersperse xs a) = intersperse (map f xs) (f a)"
The lemma seems very intuitive, but I can't get Isabelle to prove the lemma. I tried induction on xs, but the sledgehammer still can't find a proof. Then I tried adding auxiliary lemmas, all of them are easy to prove but don't help much proving target. I will list my attempts below though:
lemma intersp_1: "interspserse (xs#[y,x]) a = (intersperse (xs#[y]) a) # [a,x]"
...done
lemma intersp_2:"map f (intersperse (xs#[b,x]) a) = (map f (intersperse (xs#[b]) a)) # [(f a),(f x)]"
...done
lemma intersp_3: "map f (intersperse (x#y#xs) a) = (f x)#(f a)#(map f (intersperse (y#xs) a))"
...done
As a new learner of Isabelle I'm kind of stuck here. The only solution that I can currently think of is to come up with an appropriate lemma that provides enough hint to the solver. However I don't know how to "appropriately" dispart the induction step of target (after applying induction on xs) into a supplementary lemma. The induction step is
goal (1 subgoal):
1. ⋀aa xs.
map f (intersperse xs a) = intersperse (map f xs) (f a) ⟹
map f (intersperse (aa # xs) a) = intersperse (map f (aa # xs)) (f a)
Any help is appreciated!
Here's a proof:
lemma target: "map f (intersperse xs a) = intersperse (map f xs) (f a)"
proof (induct xs)
case Nil
then show ?case by simp
next
case (Cons x xs)
consider "xs = []" | "∃y ys. xs = y # ys" by (meson list.exhaust)
then show ?case using Cons by (cases; auto)
qed
The key here is that intersperse (x # []) a and intersperse (x # y # ys) a match different patterns, so by considering each case separately sledgehammer can easily find a proof.
Here is another option: Use the specialized induction rule for intersperse:
lemma target:"map f (intersperse xs a) = intersperse (map f xs) (f a)"
by (induct "(map f xs)" "f a" arbitrary: xs rule: intersperse.induct) auto
The rule intersperse.induct contains three cases:
x#y#xs
[]
[v]
These can then be solved by auto since they fit the simplification rules available for the function.
Since the parameters of intersperse in the lemma are not variables, it is necessary to give them explicitly to the induct method and use arbitrary to state what the variable parts are.

How to prove in HOLCF that double reversion of a list doesn't change it

Here is a simple theory written on the plain HOL:
theory ToyList
imports Main
begin
no_notation Nil ("[]") and Cons (infixr "#" 65) and append (infixr "#" 65)
hide_type list
hide_const rev
datatype 'a list = Nil ("[]") | Cons 'a "'a list" (infixr "#" 65)
primrec snoc :: "'a list => 'a => 'a list" (infixr "#>" 65)
where
"[] #> y = y # []" |
"(x # xs) #> y = x # (xs #> y)"
primrec rev :: "'a list => 'a list"
where
"rev [] = []" |
"rev (x # xs) = (rev xs) #> x"
lemma rev_snoc [simp]: "rev(xs #> y) = y # (rev xs)"
apply(induct_tac xs)
apply(auto)
done
theorem rev_rev [simp]: "rev(rev xs) = xs"
apply(induct_tac xs)
apply(auto)
done
end
snoc is an opposite of cons. It adds an item to the end of the list.
I want to prove a similar lemma via HOLCF. At a first stage I consider only strict lists. I declared the domain of strict lists in HOLCF. Also I declared two recursive functions:
ssnoc - appends an item to the end of a list
srev - reverses a list
Prefix s means "strict".
theory Test
imports HOLCF
begin
domain 'a SList = SNil | SCons "'a" "'a SList"
fixrec ssnoc :: "'a SList → 'a → 'a SList"
where
"ssnoc ⋅ SNil ⋅ x = SCons ⋅ x ⋅ SNil" |
"ssnoc ⋅ ⊥ ⋅ x = ⊥" |
"x ≠ ⊥ ∧ xs ≠ ⊥ ⟹ ssnoc ⋅ (SCons ⋅ x ⋅ xs) ⋅ y = SCons ⋅ x ⋅ (ssnoc ⋅ xs ⋅ y)"
fixrec srev :: "'a SList → 'a SList"
where
"srev ⋅ ⊥ = ⊥" |
"srev ⋅ SNil = SNil" |
"x ≠ ⊥ ∧ xs ≠ ⊥ ⟹ srev ⋅ (SCons ⋅ x ⋅ xs) = ssnoc ⋅ (srev ⋅ xs) ⋅ x"
lemma srev_singleton [simp]:
"srev ⋅ (SCons ⋅ a ⋅ SNil) = SCons ⋅ a ⋅ SNil"
apply(induct)
apply(simp_all)
done
lemma srev_ssnoc [simp]:
"srev ⋅ (ssnoc ⋅ xs ⋅ a) = SCons ⋅ a ⋅ (srev ⋅ xs)"
apply(induct xs)
apply(simp_all)
done
lemma srev_srev [simp]:
"srev ⋅ (srev ⋅ xs) = xs"
apply(induct xs)
apply(simp_all)
done
end
I'm trying to prove that double reversion of the list equals to the original list (srev_srev lemma). I have declared two helper lemmas:
srev_singleton - reverse of the singleton list is the original singleton list
srev_ssnoc - reversion of the list equals to the list starting from the last item of the original list appending reversion of the rest items of the original list
But I can't prove any of the lemmas. Could you point out the errors?
Also why the precondition "x ≠ ⊥ ∧ xs ≠ ⊥" is necessary in the function definitions? And why should I declare "srev ⋅ ⊥ = ⊥" and "ssnoc ⋅ ⊥ ⋅ x = ⊥" explicitly. I guess that in HOLCF by default functions are undefined if any of the arguments is undefined.
If your intention is to model lists a la Haskell (aka "lazy lists"), then you should use something like:
domain 'a list = Nil ("[]") | Cons (lazy 'a) (lazy "'a list") (infix ":" 65)
(note the "lazy" annotations for Cons). Then you do not need the assumptions on your third equation. E.g.,
fixrec append :: "'a list → 'a list → 'a list"
where
"append $ [] $ ys = ys"
| "append $ (x : xs) $ ys = x : (append $ xs $ ys)"
for what you called ssnoc and
fixrec reverse :: "'a list → 'a list"
where
"reverse $ [] = []"
| "reverse $ (x : xs) = append $ xs $ (x : [])"
for reverse.
However, since this type of lists allows for "infinite" values, you will not be able to prove that reverse $ (reverse $ xs) = xs hold in general (because it doesn't). This only holds for finite lists, which can be characterized inductively. (See, e.g., https://arxiv.org/abs/1306.1340 for a more detailed discussion.)
If, however, you do not want to model lazy lists (i.e., really don't want the "lazy" annotations in your datatype), then your equations might not hold without the assumptions. Now if the equations have those assumptions, they can only be applied in cases where the assumptions are satisfied. So gain, you will not be able to proof (without additional assumptions) that reverse $ (reverse $ xs) = xs. It might again be possible to obtain the appropriate assumptions by an inductive predicate, but I did not investigate further.
Update: After playing a bit with strict lists in HOLCF, I have some more comments:
First, my guess is that the preconditions in the fixrec specifications are necessary due to the internal construction, but we are able to get rid of them afterwards.
I managed to prove your lemma as follows. For completeness I give the whole content of my theory file. First make sure that notation doesn't clash with existing one:
no_notation
List.Nil ("[]") and
Set.member ("op :") and
Set.member ("(_/ : _)" [51, 51] 50)
Then define the type of strict lists
domain 'a list = Nil ("[]") | Cons 'a "'a list" (infixr ":" 65)
and the function snoc.
fixrec snoc :: "'a list → 'a → 'a list"
where
"snoc $ [] $ y = y : []"
| "x ≠ ⊥ ⟹ xs ≠ ⊥ ⟹ snoc $ (x:xs) $ y = x : snoc $ xs $ y"
Now, we obtain an unconditional variant of the second equation by:
Showing that snoc is strict in its first argument (note the usage of fixrec_simp).
Showing that snoc is strict in its second argument (here induction is needed).
And finally, obtaining the equation by case analysis on all three variables.
lemma snoc_bot1 [simp]: "snoc $ ⊥ $ y = ⊥" by fixrec_simp
lemma snoc_bot2 [simp]: "snoc $ xs $ ⊥ = ⊥" by (induct xs) simp_all
lemma snoc_Cons [simp]: "snoc $ (x:xs) $ y = x : snoc $ xs $ y"
by (cases "x = ⊥"; cases "xs = ⊥"; cases "y = ⊥";simp)
Then the function reverse
fixrec reverse :: "'a list → 'a list"
where
"reverse $ [] = []"
| "x ≠ ⊥ ⟹ xs ≠ ⊥ ⟹ reverse $ (x : xs) = snoc $ (reverse $ xs) $ x"
and again an unconditional variant of its second equation:
lemma reverse_bot [simp]: "reverse $ ⊥ = ⊥" by fixrec_simp
lemma reverse_Cons [simp]: "reverse $ (x : xs) = snoc $ (reverse $ xs) $ x"
by (cases "x = ⊥"; cases "xs = ⊥"; simp)
Now the lemma about reverse and snoc you also had:
lemma reverse_snoc [simp]: "reverse $ (snoc $ xs $ y) = y : reverse $ xs"
by (induct xs) simp_all
And finally the desired lemma:
lemma reverse_reverse [simp]:
"reverse $ (reverse $ xs) = xs"
by (induct xs) simp_all
The way I obtained this solution was by just looking into the remaining subgoals of your failed attempts, then get more failed attempts, look into the remaining subgoals, repeat, ...

How to invoke functions in Isabelle/HOL?

Here is a theory I've taken from Isabelle Tutorial. It has ways to prove theorems but I was wondering how one would call the app function below with two lists.
theory ToyList
imports Main
begin
datatype 'a list = Nil | Cons 'a "'a list"
fun app :: "'a list ⇒ 'a list ⇒ 'a list" where
"app Nil ys = ys" |
"app (Cons x xs) ys = Cons x (app xs ys)"
I tried theorem app_test[simp] : "app (xs # ys ) # zs = xs # ys # zs" and other ways but didn't work.

How to prove the reversion of a doubling function equals the doubling of a reversion function in Isabelle?

I have a function that doubles the elements of a list in the form
double [x1, x2, ...] = [x1, x1, x2, x2, ...]
namely
fun double :: " 'a list ⇒ 'a list"
where
"double [] = []" |
"double (x#xs) = x # x # double xs"
and a function that reverses the elements of a list with the help of another function snoc that adds an element to the right side of a list:
fun snoc :: "'a list ⇒ 'a ⇒ 'a list"
where
"snoc [] x = [x]" |
"snoc (y # ys) x = y # (snoc ys x)"
fun reverse :: "'a list ⇒ 'a list"
where
"reverse [] = []" |
"reverse (x # xs) = snoc (reverse xs) x"
Now I want to prove that
lemma rev_double: "rev (double xs) = double (rev xs)"
is true.
I tried to apply induction on xs
lemma rev_double: "rev (double xs) = double (rev xs)"
by (induction xs)
and I wrote an auxiliary lemma double_snoc that ensures that doubling a list is the same as doubling its first element and the rest of the list (which uses the function snocleft which inserts an element at the left end of a list)
fun snocleft::"'a list ⇒ 'a ⇒ 'a list "
where
"snocleft [] x = [x]" |
"snocleft (y # ys) x = x # (y # ys)"
lemma double_snoc: "double (snocleft xs y) = y # y # double xs"
by (induction xs) auto
I still haven't made any progress in proving the lemma. Do you have some solutions or hints on how to set up the prove?
You define your function as reverse, but in all of your lemmas, you use rev, referring to the pre-defined list reversal function rev.
What you mean is probably this:
lemma reverse_double: "reverse (double xs) = double (reverse xs)"
If you attempt to prove this by induction (with apply (induction xs)), you will get stuck in the induction case with the following goal:
snoc (snoc (double (reverse xs)) a) a =
double (snoc (reverse xs) a)
This should be intuitively obvious: if you first snoc and then double, it is the same as first doubling and then snoc-ing twice. So let's prove this as an auxiliary lemma:
lemma double_snoc: "double (snoc xs x) = snoc (snoc (double xs) x) x"
by (induction xs) auto
Now the proof of reverse_double goes through automatically:
lemma reverse_double: "reverse (double xs) = double (reverse xs)"
by (induction xs) (auto simp: double_snoc)

Resources