Using the value of a computed function for a proof in agda - tic-tac-toe

I'm still trying to wrap my head around agda, so I wrote a little tic-tac-toe game Type
data Game : Player -> Vec Square 9 -> Set where
start : Game x ( - ∷ - ∷ - ∷
- ∷ - ∷ - ∷
- ∷ - ∷ - ∷ [] )
xturn : {gs : Vec Square 9} -> (n : ℕ) -> Game x gs -> n < (#ofMoves gs) -> Game o (makeMove gs x n )
oturn : {gs : Vec Square 9} -> (n : ℕ) -> Game o gs -> n < (#ofMoves gs) -> Game x (makeMove gs o n )
Which will hold a valid game path.
Here #ofMoves gs would return the number of empty Squares,
n < (#ofMoves gs) would prove that the nth move is valid,
and makeMove gs x n replaces the nth empty Square in the game state vector.
After a few stimulating games against myself, I decided to shoot for something more awesome. The goal was to create a function that would take an x player and an o player and pit them against each other in an epic battle to the death.
--two programs enter, one program leaves
gameMaster : {p : Player } -> {gs : Vec Square 9} --FOR ALL
-> ({gs : Vec Square 9} -> Game x gs -> (0 < (#ofMoves gs)) -> Game o (makeMove gs x _ )) --take an x player
-> ({gs : Vec Square 9} -> Game o gs -> (0 < (#ofMoves gs)) -> Game x (makeMove gs o _ )) --take an o player
-> ( Game p gs) --Take an initial configuration
-> GameCondition --return a winner
gameMaster {_} {gs} _ _ game with (gameCondition gs)
... | xWin = xWin
... | oWin = oWin
... | draw = draw
... | ongoing with #ofMoves gs
... | 0 = draw --TODO: really just prove this state doesn't exist, it will always be covered by gameCondition gs = draw
gameMaster {x} {gs} fx fo game | ongoing | suc nn = gameMaster (fx) (fo) (fx game (s≤s z≤n)) -- x move
gameMaster {o} {gs} fx fo game | ongoing | suc nn = gameMaster (fx) (fo) (fo game (s≤s z≤n)) -- o move
Here (0 < (#ofMoves gs)) is "short hand" for a proof that that the game is ongoing,
gameCondition gs will return the game state as you would expect (one of xWin, oWin, draw, or ongoing)
I want to prove that there are valid moves (the s≤s z≤n part). This should be possible since suc nn <= #ofMoves gs. I have no idea how how to make this work in agda.

I'll try to answer some of your questions, but I don't think you're apporaching this from the right angle. While you certainly can work with bounded numbers using explicit proofs, you'll most likely be more successful with data type instead.
For your makeMove (I've renamed it to move in the rest of the answer), you need a number bounded by the available free squares. That is, when you have 4 free squares, you want to be able to call move only with 0, 1, 2 and 3. There's one very nice way to achieve that.
Looking at Data.Fin, we find this interesting data type:
data Fin : ℕ → Set where
zero : {n : ℕ} → Fin (suc n)
suc : {n : ℕ} (i : Fin n) → Fin (suc n)
Fin 0 is empty (both zero and suc construct Fin n for n greater or equal than 1). Fin 1 only has zero, Fin 2 has zero and suc zero, and so on. This represents exactly what we need: a number bounded by n. You might have seen this used in the implementation of safe vector lookup:
lookup : ∀ {a n} {A : Set a} → Fin n → Vec A n → A
lookup zero (x ∷ xs) = x
lookup (suc i) (x ∷ xs) = lookup i xs
The lookup _ [] case is impossible, because Fin 0 has no elements!
How to apply this nicely to your problem? Firstly, we'll have to track how many empty squares we have. This allows us to prove that gameMaster is indeed a terminating function (the number of empty squares is always decreasing). Let's write a variant of Vec which tracks not only length, but also the empty squares:
data Player : Set where
x o : Player
data SquareVec : (len : ℕ) (empty : ℕ) → Set where
[] : SquareVec 0 0
-∷_ : ∀ {l e} → SquareVec l e → SquareVec (suc l) (suc e)
_∷_ : ∀ {l e} (p : Player) → SquareVec l e → SquareVec (suc l) e
Notice that I got rid of the Square data type; instead, the empty square is baked directly into the -∷_ constructor. Instead of - ∷ rest we have -∷ rest.
We can now write the move function. What should its type be? Well, it'll take a SquareVec with at least one empty square, a Fin e (where e is the number of empty squares) and a Player. The Fin e guarantees us that this function can always find the appropriate empty square:
move : ∀ {l e} → Player → SquareVec l (suc e) → Fin (suc e) → SquareVec l e
move p ( -∷ sqs) zero = p ∷ sqs
move {e = zero} p ( -∷ sqs) (suc ())
move {e = suc e} p ( -∷ sqs) (suc fe) = -∷ move p sqs fe
move p (p′ ∷ sqs) fe = p′ ∷ move p sqs fe
Notice that this function gives us a SquareVec with exactly one empty square filled. This function couldn't have filled more than one or no empty squares at all!
We walk down the vector looking for an empty square; once we find it, the Fin argument tells us whether it's the square we want to fill in. If it's zero, we fill in the player; if it isn't, we continue searching the rest of the vector but with a smaller number.
Now, the game representation. Thanks to the extra work we did earlier, we can simplify the Game data type. The move-p constructor just tells us where the move happened and that's it! I got rid of the Player index for simplicity; but it would work just fine with it.
data Game : ∀ {e} → SquareVec 9 e → Set where
start : Game empty
move-p : ∀ {e} {gs} p (fe : Fin (suc e)) → Game gs → Game (move p gs fe)
Oh, what's empty? It's shortcut for your - ∷ - ∷ ...:
empty : ∀ {n} → SquareVec n n
empty {zero} = []
empty {suc _} = -∷ empty
Now, the states. I separated the states into a state of a possibly running game and a state of an ended game. Again, you can use your original GameCondition:
data State : Set where
win : Player → State
draw : State
going : State
data FinalState : Set where
win : Player → FinalState
draw : FinalState
For the following code, we'll need these imports:
open import Data.Empty
open import Data.Product
open import Relation.Binary.PropositionalEquality
And a function to determine the game state. Fill in with your actual implementation; this one just lets players play until the board is completly full.
-- Dummy implementation.
state : ∀ {e} {gs : SquareVec 9 e} → Game gs → State
state {zero} gs = draw
state {suc _} gs = going
Next, we need to prove that the State cannot be going when there are no empty squares:
zero-no-going : ∀ {gs : SquareVec 9 0} (g : Game gs) → state g ≢ going
zero-no-going g ()
Again, this is the proof for the dummy state, the proof for your actual implementation will be very different.
Now, we have all the tools we need to implement gameMaster. Firstly, we'll have to decide what its type is. Much like your version, we'll take two functions that represent the AI, one for o and other for x. Then we'll take the game state and produce FinalState. In this version, I'm actually returning the final board so we can see how the game progressed.
Now, the AI functions will return just the turn they want to make instead of returning whole new game state. This is easier to work with.
Brace yourself, here's the type signature I conjured up:
AI : Set
AI = ∀ {e} {sqv : SquareVec 9 (suc e)} → Game sqv → Fin (suc e)
gameMaster : ∀ {e} {sqv : SquareVec 9 e} (sp : Player)
(x-move o-move : AI) → Game sqv →
FinalState × (Σ[ e′ ∈ ℕ ] Σ[ sqv′ ∈ SquareVec 9 e′ ] Game sqv′)
Notice that the AI functions take a game state with at least one empty square and return a move. Now for the implementation.
gameMaster sp xm om g with state g
... | win p = win p , _ , _ , g
... | draw = draw , _ , _ , g
... | going = ?
So, if the current state is win or draw, we'll return the corresponding FinalState and the current board. Now, we have to deal with the going case. We'll pattern match on e (the number of empty squares) to figure out whether the game is at the end or not:
gameMaster {zero} sp xm om g | going = ?
gameMaster {suc e} x xm om g | going = ?
gameMaster {suc e} o xm om g | going = ?
The zero case cannot happen, we proved earlier that state cannot return going when the number of empty squares is zero. How to apply that proof here?
We have pattern matched on state g and we now know that state g ≡ going; but sadly Agda already forgot this information. This is what Dominique Devriese was hinting at: the inspect machinery allows us to retain the proof!
Instead of pattern matching on just state g, we'll also pattern matching on inspect state g:
gameMaster sp xm om g with state g | inspect state g
... | win p | _ = win p , _ , _ , g
... | draw | _ = draw , _ , _ , g
gameMaster {zero} sp xm om g | going | [ pf ] = ?
gameMaster {suc e} x xm om g | going | _ = ?
gameMaster {suc e} o xm om g | going | _ = ?
pf is now the proof that state g ≡ going, which we can feed to zero-no-going:
gameMaster {zero} sp xm om g | going | [ pf ]
= ⊥-elim (zero-no-going g pf)
The other two cases are easy: we just apply the AI function and recursively apply gameMaster to the result:
gameMaster {suc e} x xm om g | going | _
= gameMaster o xm om (move-p x (xm g) g)
gameMaster {suc e} o xm om g | going | _
= gameMaster x xm om (move-p o (om g) g)
I wrote some dumb AIs, the first one fills the first available empty square; the second one fills the last one.
player-lowest : AI
player-lowest _ = zero
max : ∀ {e} → Fin (suc e)
max {zero} = zero
max {suc e} = suc max
player-highest : AI
player-highest _ = max
Now, let's match player-lowest against player-lowest! In the Emacs, type C-c C-n gameMaster x player-lowest player-lowest start <RET>:
draw ,
0 ,
x ∷ (o ∷ (x ∷ (o ∷ (x ∷ (o ∷ (x ∷ (o ∷ (x ∷ [])))))))) ,
move-p x zero
(move-p o zero
(move-p x zero
(move-p o zero
(move-p x zero
(move-p o zero
(move-p x zero
(move-p o zero
(move-p x zero start))))))))
We can see that all squares are filled and they alternate between x and o. Matching player-lowest with player-highest gives us:
draw ,
0 ,
x ∷ (x ∷ (x ∷ (x ∷ (x ∷ (o ∷ (o ∷ (o ∷ (o ∷ [])))))))) ,
move-p x zero
(move-p o (suc zero)
(move-p x zero
(move-p o (suc (suc (suc zero)))
(move-p x zero
(move-p o (suc (suc (suc (suc (suc zero)))))
(move-p x zero
(move-p o (suc (suc (suc (suc (suc (suc (suc zero)))))))
(move-p x zero start))))))))
If you really want to work with the proofs, then I suggest the following representation of Fin:
Fin₂ : ℕ → Set
Fin₂ n = ∃ λ m → m < n
fin⟶fin₂ : ∀ {n} → Fin n → Fin₂ n
fin⟶fin₂ zero = zero , s≤s z≤n
fin⟶fin₂ (suc n) = map suc s≤s (fin⟶fin₂ n)
fin₂⟶fin : ∀ {n} → Fin₂ n → Fin n
fin₂⟶fin {zero} (_ , ())
fin₂⟶fin {suc _} (zero , _) = zero
fin₂⟶fin {suc _} (suc _ , s≤s p) = suc (fin₂⟶fin (_ , p))
Not strictly related to the question, but inspect uses rather interesting trick which might be worth mentioning. To understand this trick, we'll have to take a look at how with works.
When you use with on an expression expr, Agda goes through the types of all arguments and replaces any occurence of expr with a fresh variable, let's call it w. For example:
test : (n : ℕ) → Vec ℕ (n + 0) → ℕ
test n v = ?
Here, the type of v is Vec ℕ (n + 0), as you would expect.
test : (n : ℕ) → Vec ℕ (n + 0) → ℕ
test n v with n + 0
... | w = ?
However, once we abstract over n + 0, the type of v suddenly changes to Vec ℕ w. If you later want to use something which contains n + 0 in its type, the substitution won't take place again - it's a one time deal.
In the gameMaster function, we applied with to state g and pattern matched to find out it's going. By the time we use zero-no-going, state g and going are two separate things which have no relation as far as Agda is concerned.
How do we preserve this information? We somehow need to get state g ≡ state g and have the with replace only state g on either side - this would give us the needed state g ≡ going.
What the inspect does is that it hides the function application state g. We have to write a function hide in a way that Agda cannot see hide state g and state g are in fact the same thing.
One possible way to hide something is to use the fact that for any type A, A and ⊤ → A are isomorphic - that is, we can freely go from one representation to the other without losing any information.
However, we cannot use the ⊤ as defined in the standard library. In a moment I'll show why, but for now, we'll define a new type:
data Unit : Set where
unit : Unit
And what it means for a value to be hidden:
Hidden : Set → Set
Hidden A = Unit → A
We can easily reveal the hidden value by applying unit to it:
reveal : {A : Set} → Hidden A → A
reveal f = f unit
The last step we need to take is the hide function:
hide : {A : Set} {B : A → Set} →
((x : A) → B x) → ((x : A) → Hidden (B x))
hide f x unit = f x
Why wouldn't this work with ⊤? If you declare ⊤ as record, Agda can figure out on its own that tt is the only value. So, when faced with hide f x, Agda won't stop at the third argument (because it already knows how it must look like) and automatically reduce it to λ _ → f x. Data types defined with the data keyword don't have these special rules, so hide f x remains that way until someone reveals it and the type checker cannot see that there's a f x subexpression inside hide f x.
The rest is just arranging stuff so we can get the proof later:
data Reveal_is_ {A : Set} (x : Hidden A) (y : A) : Set where
[_] : (eq : reveal x ≡ y) → Reveal x is y
inspect : {A : Set} {B : A → Set}
(f : (x : A) → B x) (x : A) → Reveal (hide f x) is (f x)
inspect f x = [ refl ]
So, there you have it:
inspect state g : Reveal (hide state g) is (state g)
-- pattern match on (state g)
inspect state g : Reveal (hide state g) is going
When you then reveal hide state g, you'll get state g and finally the proof that state g ≡ going.

I think you are looking for an Agda technique known by the name "inspect" or "inspect on steroids". It allows you to obtain an equality proof for the knowledge learned from a with pattern match. I recommend you read the code in the following mail and try to understand how it works. Focus on how the function foo at the bottom needs to remember that "f x = z" and does so by with-matching on "inspect (hide f x)" together with "f x":
https://lists.chalmers.se/pipermail/agda/2011/003286.html
To use this in actual code, I recommend you import Relation.Binary.PropositionalEquality from the Agda standard library and use its version of inspect (which is superficially different from the code above). It has the following example code:
f x y with g x | inspect g x
f x y | c z | [ eq ] = ...
Note: "Inspect on steroids" is an updated version of an older approach at the inspect idiom.
I hope this helps...

Related

Is it possible to add assumptions to the domain of a function in Isabelle?

I'm not sure if it's okay to post a follow-up question like this, but I'll do it anyway.
So a few days ago I posted this question: How can I remove all occurrences of a sub-multiset in Isabelle?
I thought the answer was great, but when trying to prove the lemma
lemma "applied1 {#''a'',''a'',''d'',''c'',''a'',''a'',''d'',''c''#} {#''a'',''a'',''c''#} ''f'' = {#''f'',''f'',''d'',''d''#}"
I got really stuck. I found that I couldn't simply do it after unfolding the def and applying some simple automations. So I went back to my original function and made some tweaks to it such that it returns nothing if the input were to result in an infinite loop. I thought it was going to work this time, but Isabelle still couldn't prove termination. I'm pretty sure it's obvious that size x is constantly decreasing by a factor of size y and cannot be negative, so it will have to ultimately terminate when size x = 0 or when y is no longer a subset of x.
fun applied2 :: "'a multiset ⇒ 'a multiset ⇒ 'a ⇒ 'a multiset option" where
"applied2 x y z = (if z ∈# y ∨ y = {#} then None else (if y ⊆# x then Some (plus {#z#} (the (applied2 (x - y) y z))) else Some x))"
Is it possible to convince Isabelle that this function terminates using function instead of fun? Or are there other constraints I have to take into account?
I'm really sorry if I shouldn't be posting questions like this. I'm still inexperienced with Isabelle and I do hope I'm upholding my purpose to learn about the language as best as I can. Thanks in advance!
I believe that looking at the documentation would have given you the correct syntax.
function applied2 :: "'a multiset ⇒ 'a multiset ⇒ 'a ⇒ 'a multiset option" where
"applied2 x y z = (if z ∈# y ∨ y = {#} then None else (if y ⊆# x then Some (plus {#z#} (the (applied2 (x - y) y z))) else Some x))"
by pat_completeness auto
termination
by (relation "measure (λ(x,y,z). size x)")
(auto simp: mset_subset_eq_exists_conv nonempty_has_size)
If the problem is the proof, sledgehammer would have found it for you.
However, I don't see how you intend to go from applied2 to the function you really want. The real problem is determinism: you need an order to look at the subsets. Manuel's solution was using Sup, but this is indeed not executable.
If your only problem with the non-recursive definition is how to apply it to concrete inputs, I still think the alternative definition that I said was executable is the way to go. Here's a prove that the two non-recursive definitions I gave are equivalent, and the application to the example you gave above:
definition applied :: "'a multiset ⇒ 'a multiset ⇒ 'a ⇒ 'a multiset" where
"applied ms xs y = (if xs = {#} then ms else
(let n = Max {n. repeat_mset n xs ⊆# ms}
in ms - repeat_mset n xs + replicate_mset n y))"
lemma count_le_size: "count M x ≤ size M"
by (induction M) auto
lemma applied_code [code]:
"applied ms xs y = (if xs = {#} then ms else
(let n = (MIN x ∈set_mset xs. count ms x div count xs x)
in ms - repeat_mset n xs + replicate_mset n y))"
unfolding applied_def
proof (intro if_cong let_cong refl)
assume ne: "xs ≠ {#}"
have subset: "{n. repeat_mset n xs ⊆# ms} ⊆ {..size ms}"
proof safe
fix n assume n: "repeat_mset n xs ⊆# ms"
from ne obtain x where x: "x ∈# xs"
by auto
have "n * 1 ≤ n * count xs x"
using x by (intro mult_left_mono) auto
also have "… = count (repeat_mset n xs) x"
by simp
also have "… ≤ count ms x"
using n by (intro mset_subset_eq_count)
also have "… ≤ size ms"
by (rule count_le_size)
finally show "n ≤ size ms" by simp
qed
hence finite: "finite {n. repeat_mset n xs ⊆# ms}"
by (rule finite_subset) auto
show "Max {n. repeat_mset n xs ⊆# ms} = (MIN x∈set_mset xs. count ms x div count xs x)"
proof (intro antisym)
show "Max {n. repeat_mset n xs ⊆# ms} ≤ (MIN x∈set_mset xs. count ms x div count xs x)"
proof (rule Max.boundedI)
show "{n. repeat_mset n xs ⊆# ms} ≠ {}"
by (auto intro: exI[of _ 0])
next
fix n assume n: "n ∈ {n. repeat_mset n xs ⊆# ms}"
show "n ≤ (MIN x∈set_mset xs. count ms x div count xs x)"
proof (safe intro!: Min.boundedI)
fix x assume x: "x ∈# xs"
have "count (repeat_mset n xs) x ≤ count ms x"
using n by (intro mset_subset_eq_count) auto
also have "count (repeat_mset n xs) x = n * count xs x"
by simp
finally show "n ≤ count ms x div count xs x"
by (metis count_eq_zero_iff div_le_mono nonzero_mult_div_cancel_right x)
qed (use ne in auto)
qed (fact finite)
next
define m where "m = (MIN x∈set_mset xs. count ms x div count xs x)"
show "m ≤ Max {n. repeat_mset n xs ⊆# ms}"
proof (rule Max.coboundedI[OF finite], safe)
show "repeat_mset m xs ⊆# ms"
proof (rule mset_subset_eqI)
fix x
show "count (repeat_mset m xs) x ≤ count ms x"
proof (cases "x ∈# xs")
case True
have "count (repeat_mset m xs) x = m * count xs x"
by simp
also have "… ≤ (count ms x div count xs x) * count xs x"
unfolding m_def using ‹x ∈# xs› by (intro mult_right_mono Min.coboundedI) auto
also have "… ≤ count ms x"
by simp
finally show ?thesis .
next
case False
hence "count xs x = 0"
by (meson not_in_iff)
thus ?thesis by simp
qed
qed
qed
qed
qed
lemma replicate_mset_unfold:
assumes "n > 0"
shows "replicate_mset n x = {#x#} + replicate_mset (n - 1) x"
using assms by (cases n) auto
lemma
assumes "a ≠ c" "a ≠ f" "c ≠ f"
shows "applied {#a,a,c,a,a,c#} {#a,a,c#} f = mset [f, f]"
using assms
by (simp add: applied_code replicate_mset_unfold flip: One_nat_def)
The value command does not work on that example because a, c, etc. are free variables. But if you e.g. make an ad-hoc datatype for them, it works:
datatype test = a | b | c | f
value "applied {#a,a,c,a,a,c#} {#a,a,c#} f"
(* "mset [f, f]" :: "test multiset" *)

Is there a specific type for mathematical functions in Haskell?

I want to write a function that takes a mathematical function (/,x,+,-), a number to start with and a list of numbers. Then, it's supposed to give back a list.
The first element is the starting number, the second element the value of the starting number plus/minus/times/divided by the first number of the given list. The third element is the result of the previous result plus/minus/times/divided by the second result of the given list, and so on.
I've gotten everything to work if I tell the code which function to use but if I want to let the user input the mathematical function he wants, there are problems with the types. Trying :t (/) for example gives out Fractional a => a -> a -> a, but if you put that at the start of your types, it fails.
Is there a specific type to distinguish these functions (/,x,+,-)? Or is there another way to write this function succesfully?
prefix :: (Fractional a, Num a) => a -> a -> a -> a -> [a] -> [a]
prefix (f) a b = [a] ++ prefix' (f) a b
prefix' :: (Fractional a, Num a) => a -> a -> a -> a -> [a] -> [a]
prefix' (z) x [] = []
prefix' (z) x y = [x z (head y)] ++ prefix' (z) (head (prefix' (z) x y)) (tail y)
A right solution would be something like this:
prefix (-) 0 [1..5]
[0,-1,-3,-6,-10,-15]
Is there a specific type to distinguish these functions (/,*,+,-)?
I don't see a reason to do this. Why is \x y -> x+y considered "better" than \x y -> x + y + 1. Sure adding two numbers is something that most will consider more "pure". But it is strange to restrict yourself to a specific subset of functions. It is also possible that for some function \x y -> f x y - 1 "happens" to be equal to (+), except that the compiler can not determine that.
The type checking will make sure that one can not pass functions that operate on numbers, given the list contains strings, etc. But deliberately restricting this further is not very useful. Why would you prevent programmers to use your function for different purposes?
Or is there another way to write this function succesfully?
What you here describe is the scanl :: (b -> a -> b) -> b -> [a] -> [b] function. If we call scanl with scanl f z [x1, x2, ..., xn], then we obtain a list [z, f z x1, f (f z x1) x2, ...]. scanl can be defined as:
scanl :: (b -> a -> b) -> b -> [a] -> [b]
scanl f = go
where go z [] = [z]
go z (x:xs) = z : go (f z x) xs
We thus first emit the accumulator (that starts with the initial value), and then "update" the accumulator to f z x with z the old accumulator, and x the head of the list, and recurse on the tail of the list.
If you want to restrict to these four operations, just define the type yourself:
data ArithOp = Plus | Minus | Times | Div
as_fun Plus = (+)
as_fun Minus = (-)
as_fun Times = (*)
as_fun Div = (/)

Appending nil to a dependently typed length indexed vector in Lean

Assume the following definition:
def app {α : Type} : Π{m n : ℕ}, vector α m → vector α n → vector α (n + m)
| 0 _ [] v := by simp [add_zero]; assumption
| (nat.succ _) _ (h :: t) v' := begin apply vector.cons,
exact h,
apply app t v'
end
Do note that (n + m) are flipped in the definition, so as to avoid plugging add_symm into the definition. Also, remember that add / + is defined on rhs in Lean. vector is a hand rolled nil / cons defined length indexed list.
So anyway, first we have a lemma that follows from definition:
theorem nil_app_v {α : Type} : ∀{n : ℕ} (v : vector α n),
v = [] ++ v := assume n v, rfl
Now we have a lemma that doesn't follow from definition, as such I use eq.rec to formulate it.
theorem app_nil_v {α : Type} : ∀{n : ℕ} (v : vector α n),
v = eq.rec (v ++ []) (zero_add n)
Note that eq.rec is just C y → Π {a : X}, y = a → C a.
The idea of a proof is trivial by induction on v. The base case follows immediately from definition, the recursive case should follow immediately from the inductive hypothesis and definition, but I can't convince Lean of this.
begin
intros n v,
induction v,
-- base case
refl,
-- inductive case
end
The inductive hypothesis I get from Lean is a_1 = eq.rec (a_1 ++ vector.nil) (zero_add n_1).
How do I use it with conclusion a :: a_1 = eq.rec (a :: a_1 ++ vector.nil) (zero_add (nat.succ n_1))? I can unfold app to reduce the term a :: a_1 ++ vector.nil to a :: (a_1 ++ vector.nil), and now I am stuck.

Agda - Reverse-helper

I'm trying to prove this lema
reverse-++ : ∀{ℓ}{A : Set ℓ}(l1 l2 : 𝕃 A) → reverse (l1 ++ l2) ≡ (reverse l2) ++ (reverse l1)
reverse-++ [] [] = refl
reverse-++ l1 [] rewrite ++[] l1 = refl
reverse-++ l1 (x :: xs) = {!!}
But another function, reverse-helper keeps coming up into my goal and I have no idea how I get rid of it. Any guidance or suggestions?
I'm assuming that in the implementation of reverse, you call reverse-helper. In that case, you probably want to prove a lemma about reverse-helper that you can call in the lemma about reverse. This is a general thing: If you are proving something about a function with a helper function, you usually need a proof with a helper proof, because the induction structure of the proof usually matches the recursion structure of the function.
I think you should start with the different argument.
Since ++ is probably defined with [] ++ a = a, and reverse (x :: xs) = (reverse xs) ++ (x :: nil) it will be better to prove reverse-++ (x :: xs) ys = cong (\xs -> xs ++ (x :: nil)) (reverse-++ xs ys)

proving function definition correctness in Isabelle

I want to prove function definition correctness using the function keyword definition. Here is the definition of an addition function on the usual inductive definition of natural numbers:
theory FunctionDefinition
imports Main
begin
datatype natural = Zero | Succ natural
function add :: "natural => natural => natural"
where
"add Zero m = m"
| "add (Succ n) m = Succ (add n m)"
Isabelle/JEdit shows me the following subgoals:
goal (4 subgoals):
1. ⋀P x. (⋀m. x = (Zero, m) ⟹ P) ⟹ (⋀n m. x = (Succ n, m) ⟹ P) ⟹ P
2. ⋀m ma. (Zero, m) = (Zero, ma) ⟹ m = ma
3. ⋀m n ma. (Zero, m) = (Succ n, ma) ⟹ m = Succ (add_sumC (n, ma))
4. ⋀n m na ma. (Succ n, m) = (Succ na, ma) ⟹ Succ (add_sumC (n, m)) = Succ (add_sumC (na, ma))
Auto solve_direct: ⋀m ma. (Zero, m) = (Zero, ma) ⟹ m = ma can be solved directly with
Product_Type.Pair_inject: (?a, ?b) = (?a', ?b') ⟹ (?a = ?a' ⟹ ?b = ?b' ⟹ ?R) ⟹ ?R
using
apply (auto simp add: Product_Type.Pair_inject)
I get
goal (1 subgoal):
1. ⋀P a b. (⋀m. a = Zero ∧ b = m ⟹ P) ⟹ (⋀n m. a = Succ n ∧ b = m ⟹ P) ⟹ P
It is not clear how to proceed. At all, is this the right way to tackle this problem?
I know that Isabelle would do this automatically if I used a fun definition -- I want to learn how to do this manually .
The tutorial on the function package mentions in section 3 that fun f where ... abbreviates
function (sequential) f where ...
by pat_completeness auto
termination by lexicographic_order
Here pat_completeness is a proof method from the function package that automates proof of completeness for patterns of datatype constructors. This is the first subgoal that you have to prove. It is recommended to apply pat_completeness before auto, because auto changes the syntactic structure of the goal and pat_completeness might not work after auto.
If you want to prove pattern completeness without pat_completeness, you should try to do case analysis of all function parameters, i.e., case_tac a in your example.
Manuel already mentioned it in his comment, but I thought a more detailed example might be helpful anyway. Here is what you can do manually:
First you specify your function as usual
function add :: "natural => natural => natural"
where
"add Zero m = m" |
"add (Succ n) m = Succ (add n m)"
and then you prove that the given patterns cover all cases by
by (pat_completeness) auto
Afterwards you take care of termination. E.g., every datatype comes with a size function and you might note that the first argument of add strictly decreases in size for every recursive call. By default function will bundle all arguments of a function into a tuple for a termination proof, i.e., instead of two arguments n and m, in the termination proof you work with the single pair (n, m). Thus if you want to tell the system that it should use the size of the first argument you can do this as follows:
termination add
apply (relation "measure (size o fst)")
This will yield the remaining goals:
goal (2 subgoals):
1. wf (measure (size o fst))
2. !!n m. ((n, m), Succ n, m) : measure (size o fst)
That is, you have to show that the given relation is well-founded (which is trivial for measures, which are always well-founded, since they are constructed by mapping arguments to natural numbers and then using less-than on the naturals as relation) and that for every recursive call the arguments are actually in the given relation. Both goals are easily dispatched by simp.
apply simp
apply simp
done