Proof on less than and less or equal on nat - proof

Assuming the following definitions (the first two are taken from http://www.cis.upenn.edu/~bcpierce/sf/Basics.html):
Fixpoint beq_nat (n m : nat) : bool :=
match n with
| O => match m with
| O => true
| S m' => false
end
| S n' => match m with
| O => false
| S m' => beq_nat n' m'
end
end.
Fixpoint ble_nat (n m : nat) : bool :=
match n with
| O => true
| S n' =>
match m with
| O => false
| S m' => ble_nat n' m'
end
end.
Definition blt_nat (n m : nat) : bool :=
if andb (ble_nat n m) (negb (beq_nat n m)) then true else false.
I would like to prove the following:
Lemma blt_nat_flip0 : forall (x y : nat),
blt_nat x y = false -> ble_nat y x = true.
Lemma blt_nat_flip : forall (x y : nat),
blt_nat x y = false -> beq_nat x y = false -> blt_nat y x = true.
The furthest I was able to get to is to prove blt_nat_flip assuming blt_nat_flip0. I spent a lot of time and I am almost there but overall it seems more complex than it should be. Anybody has a better idea on how to prove the two lemmas?
Here is my attempt so far:
Lemma beq_nat_symmetric : forall (x y : nat),
beq_nat x y = beq_nat y x.
Proof.
intros x. induction x.
intros y. simpl. destruct y.
reflexivity. reflexivity.
intros y. simpl. destruct y.
reflexivity.
simpl. apply IHx.
Qed.
Lemma and_negb_false : forall (b1 b2 : bool),
b2 = false -> andb b1 (negb b2) = b1.
Proof.
intros. rewrite -> H. unfold negb. destruct b1.
simpl. reflexivity.
simpl. reflexivity.
Qed.
Lemma blt_nat_flip0 : forall (x y : nat),
blt_nat x y = false -> ble_nat y x = true.
Proof.
intros x.
induction x.
intros. destruct y.
simpl. reflexivity.
simpl. inversion H.
intros. destruct y. simpl. reflexivity.
simpl. rewrite -> IHx. reflexivity.
(* I am giving up for now at this point ... *)
Admitted.
Lemma blt_nat_flip : forall (x y : nat),
blt_nat x y = false -> beq_nat x y = false ->
blt_nat y x = true.
Proof.
intros.
unfold blt_nat.
rewrite -> beq_nat_symmetric. rewrite -> H0.
rewrite -> and_negb_false.
replace (ble_nat y x) with true.
reflexivity.
rewrite -> blt_nat_flip0. reflexivity. apply H. reflexivity.
Qed.

coq seems to have trouble doing an inversion on H in the last case of your induction, but if you unfold blt_nat before, it seems to work as intended.

Related

foldr for squareOn - Haskell

In my lecture, we had to define the function squareOn such that
with foldr.
The answer was
squareOn :: (Eq a, Num a) => [a] -> a -> a
squareOn = foldr (\x acc y -> if y == x then x*x else acc y) id
I undestand how foldr works, but I'm new at lambda expressions in Haskell. Is acc any type of function from Haskell? It would be nice if someone could explain how squareOn works. :)
This is a sort-of advanced usage of foldr. Normally, we see foldr used as in
fun xs = foldr (\x acc -> something using x and acc) base xs
or equivalently
fun = foldr (\x acc -> something using x and acc) base
which corresponds to the following recursive function:
fun [] = base
fun (x:xs) = something using x and acc
where acc = fun xs
Your case is a special case of this usage, where base, acc, and something using x and acc are functions. That is, we have
fun [] = \y -> base'
fun (x:xs) = \y -> something using x, acc, y
where acc = \y -> fun xs y
Moving back to foldr, we get
fun = foldr (\x acc -> \y -> something using x, acc, y) (\y -> base')
which can also be written as
fun = foldr (\x acc y -> something using x, acc, y) (\y -> base')
where a somehow confusing three-argument function appears to be passed to foldr.
Your specific case,
squareOn = foldr (\x acc y -> if y == x then x*x else acc y) id
corresponds to the explicit recursion:
squareOn [] = id
squareOn (x:xs) = \y -> if y == x then x*x else acc y
where acc = \y -> squareOn xs y
or
squareOn [] y = y
squareOn (x:xs) y = if y == x then x*x else squareOn xs y
which you should be able to understand.
Let's define this function without a lambda.
squareOn :: (Eq a, Num a) => [a] -> a -> a
squareOn = foldr f id
where
f x acc = g
where
g y | x == y = x * x
| otherwise = acc y
Now it's become what foldr usually looks like. It takes a function taking two arguments f and an initial value id.
When you pass [2, 4] to squareOn, it'll be expanded to foldr f id [2, 4], then f 2 (f 4 id) by the definition of foldr.
f 4 id returns a function that takes one argument y which returns 4 * 4 if y is 4, and returns id y otherwise. Let's call this function p.
p y | 4 == y = 4 * 4
| otherwise = id y
Now, f 2 (f 4 id) returns a function that takes one argument y which returns 2 * 2 if y is 2, and returns p y otherwise. When you name it q, it'll be like this.
q y | 2 == y = 2 * 2
| otherwise = p y
So squareOn [2, 4] 3, for example, is equivalent to q 3.
Whoever skipped those explicit arguments just made it unnecessarily harder on yourself to learn this stuff. It's totally superficial. Adding the explicit arguments, as specified by the type signature, gives us
squareOn :: (Eq a, Num a) => [a] -> a -> a
squareOn = foldr (\x acc y -> if y == x then x*x else acc y) id
squareOn xs = foldr (\x acc y -> if y == x then x*x else acc y) id xs
squareOn xs y = foldr (\x acc y -> if y == x then x*x else acc y) id xs y
squareOn xs y = foldr g id xs y where { g x acc y | y == x = x*x
| otherwise = acc y }
squareOn xs y = (case xs of {
[] -> id ;
(x:xs2) -> g x (foldr g id xs2)
}) y where { g x acc y | y == x = x*x
| otherwise = acc y }
Now we can see everything in play here, as opposed to having to keep it all in mind. There is playing chess, and then there's playing blindfold chess, and why play it blindfolded if you can just see?
So now it becomes obvious that passing that y around(*) from call to call unchanged actually has no purpose here, because it is the same y, and it is already in scope:
squareOn xs y = (case xs of {
[] -> y ;
(x:xs2) -> g x (foldr g y xs2)
}) where { g x acc | y == x = x*x
| otherwise = acc }
which simplifies back as just
squareOn xs y = foldr g y xs where { g x acc | y == x = x*x
| otherwise = acc }
{- cf.
squareOn xs y = foldr g id xs y where { g x acc y | y == x = x*x
| otherwise = acc y } -}
And to be pointlessly short and pointfree, like your original code,
squareOn = flip (foldr g) where { g x acc | y == x = x*x
| otherwise = acc }
Or it could be simplified to
squareOn xs y = case xs of {
[] -> y ;
(x:_) | y == x -> x*x ;
(_:xs2) -> squareOn xs2 y }
and further to a worker/wrapper with nested unary worker, whichever is clearer for you.
Passing the unchanged quantity around to have it in scope is only really needed in languages without nested scope, like Prolog.
(*)(so that explanation in full, which you asked for, about how this technique works, is actually in the linked answer).

Can I extract a proof of bounds from an enumeration expression?

Consider this trivial program:
module Study
g : Nat -> Nat -> Nat
g x y = x - y
f : Nat -> List Nat
f x = map (g x) [1, 2 .. x]
It gives an obvious error:
|
4 | g x y = x - y
| ^
When checking right hand side of g with expected type
Nat
When checking argument smaller to function Prelude.Nat.-:
Can't find a value of type
LTE y x
— Saying I should offer some proof that this subtraction is safe to perform.
Surely, in the given context, g is always invoked safely. This follows from the way enumerations behave. How can I extract a proof of that fact so that I can give it to the invocation of g?
I know that I can use isLTE to obtain the proof:
g : Nat -> Nat -> Nat
g x y = case y `isLTE` x of
(Yes prf) => x - y
(No contra) => ?s_2
This is actually the only way I know of, and it seems to me that in a situation such as we have here, where x ≥ y by construction, there should be a way to avoid a superfluous case statement. Is there?
For map (\y = x - y) [1, 2 .. x] there needs to be a proof \y => LTE y x for every element of [1, 2 .. x]. There is Data.List.Quantifiers.All for this: All (\y => LTE y x) [1, 2 .. x].
But constructing and applying this proof is not so straight-forward. You could either build a proof about the range function lteRange : (x : Nat) -> All (\y => LTE y x) (natRange x) or define a function that returns a range and its proof lteRange : (x : Nat) -> (xs : List Nat ** All (\y => LTE y x) xs). For simplicity, I'll show an example with the second type.
import Data.List.Quantifiers
(++) : All p xs -> All p ys -> All p (xs ++ ys)
(++) [] ys = ys
(++) (x :: xs) ys = x :: (xs ++ ys)
lteRange : (x : Nat) -> (xs : List Nat ** All (\y => LTE y x) xs)
lteRange Z = ([] ** [])
lteRange (S k) = let (xs ** ps) = lteRange k in
(xs ++ [S k] ** weakenRange ps ++ [lteRefl])
where
weakenRange : All (\y => LTE y x) xs -> All (\y => LTE y (S x)) xs
weakenRange [] = []
weakenRange (y :: z) = lteSuccRight y :: weakenRange z
Also, map only applies one argument, but (-) needs the proof, too. So with a little helper function …
all_map : (xs : List a) -> All p xs -> (f : (x : a) -> p x -> b) -> List b
all_map [] [] f = []
all_map (x :: xs) (p :: ps) f = f x p :: all_map xs ps f
We can roughly do what you wanted without checking for LTE during the run-time:
f : Nat -> List Nat
f x = let (xs ** prfs) = lteRange x in all_map xs prfs (\y, p => x - y)

Proving if n = m and m = o, then n + m = m + o in Idris?

I am trying to improve my Idris skill by looking at some of the exercises Software Foundations (originally for Coq, but I am hoping the translation to Idris not too bad). I am having trouble with the "Exercise: 1 star (plus_id_exercise)" which reads:
Remove "Admitted." and fill in the proof.
Theorem plus_id_exercise : ∀ n m o : nat,
n = m → m = o → n + m = m + o.
Proof.
(* FILL IN HERE *) Admitted.
I have translated to the following problem in Idris:
plusIdExercise : (n : Nat) ->
(m : Nat) ->
(o : Nat) ->
(n == m) = True ->
(m == o) = True ->
(n + m == m + o) = True
I am trying to perform a case by case analysis and I am having a lot of issues. The first case:
plusIdExercise Z Z Z n_eq_m n_eq_o = Refl
seems to work, but then I want to say for instance:
plusIdExercise (S n) Z Z n_eq_m n_eq_o = absurd
But this doesn't work and gives:
When checking right hand side of plusIdExercise with expected type
S n + 0 == 0 + 0 = True
Type mismatch between
t -> a (Type of absurd)
and
False = True (Expected type)
Specifically:
Type mismatch between
\uv => t -> uv
and
(=) FalseUnification failure
I am trying to say this case can never happen because n == m, but Z (= m) is never the successor of any number (n). Is there anything I can do to fix this? Am I approaching this correctly? I am somewhat confused.
I would argue that the translation is not entirely correct. The lemma stated in Coq does not use boolean equality on natural numbers, it uses the so-called propositional equality. In Coq you can ask the system to give you more information about things:
Coq < About "=".
eq : forall A : Type, A -> A -> Prop
The above means = (it is syntactic sugar for eq type) takes two arguments of some type A and produces a proposition, not a boolean value.
That means that a direct translation would be the following snippet
plusIdExercise : (n = m) -> (m = o) -> (n + m = m + o)
plusIdExercise Refl Refl = Refl
And when you pattern-match on values of the equality type, Idris essentially rewrites terms according to the corresponding equation (it's roughly equivalent to Coq's rewrite tactic).
By the way, you might find the Software Foundations in Idris project useful.

Coq: Defining a special function

I want to define a function f w/ 2 explicit arguments. The types of the arguments and value of f are applications of some g. Suppose the arguments' types are g x y and g z w. The tricky part is that f's value must depend on the unifiability of x and z. Below is a naive attempt at defining f that fails. How should I tackle this?
Inductive A := a | a0 | fa.
Inductive B := b | b0.
Parameter C: Type.
Parameter g: A -> B -> C.
Parameter CT:> C -> Type.
Parameter gab: g a b.
Parameter ga0b: g a0 b.
Definition f {x y z w}(n: g x y)(m: g z w) :=
ltac:(match x with z => exact (g z b) | _ => exact (g fa b) end).
Compute f gab ga0b. (*= g fa b: C*)
Compute f gab gab. (*! = g fa b: C !*)
f's value must depend on the unifiability of x and z
It is impossible to write such a definition. Suppose you could write a function that could tell whether or not two natural numbers unified, call it unify_nat : nat -> nat -> bool. Consider now the functions
F := fun x y : nat => if unify_nat (x + y) (y + x) then True else False
G := fun x y : nat => if unify_nat (x + y) (x + y) then True else False
We can prove, because addition is commutative, that forall x y, F x y = G x y. But then unify_nat (x + y) (y + x) must return true, even though x + y and y + x do not unify.
There are two things you can do: (1) you can ask not if the terms unify, but if they are propositionally equal; and (2) you can write a notation, or an alias, which is like syntactic sugar for a definition.
1.
The command Scheme Equality will generate an equality decision function for most inductive types:
Scheme Equality for A.
Definition f {x y z w}(n: g x y)(m: g z w) :=
if A_beq x z then g z b else g fa b.
Compute f gab ga0b. (*= g fa b: C*)
Compute f gab gab. (*= g a b: C*)
2.
We can create evars with open_constr:(_) and use unification to infer the types of n and m:
Ltac f_tac n m :=
let x := open_constr:(_) in
let y := open_constr:(_) in
let z := open_constr:(_) in
let w := open_constr:(_) in
let n := constr:(n : g x y) in
let m := constr:(m : g z w) in
match x with z => exact (g z b) | _ => exact (g fa b) end.
Notation f n m := (ltac:(f_tac n m)) (only parsing).
Compute f gab ga0b. (*= g fa b: C*)
Compute f gab gab. (*= g a b: C*)

Using coq, trying to prove a simple lemma on trees

Trying to prove correctness of a insertion function of elements into a bst I got stuck trying to prove a seemingly trivial lemma.
My attempt so far:
Inductive tree : Set :=
| leaf : tree
| node : tree -> nat -> tree -> tree.
Fixpoint In (n : nat) (T : tree) {struct T} : Prop :=
match T with
| leaf => False
| node l v r => In n l \/ v = n \/ In n r
end.
(* all_lte is the proposition that all nodes in tree t
have value at most n *)
Definition all_lte (n : nat) (t : tree) : Prop :=
forall x, In x t -> (x <= n).
Lemma all_lte_trans: forall n m t, n <= m /\ all_lte n t -> all_lte m t.
Proof.
intros.
destruct H.
unfold all_lte in H0.
unfold all_lte.
intros.
Clearly if everything in the tree is smaller than n and n <= m everything is smaller than m, but I cannot seem to make coq believe me. How do I continue?
You have to use the le_trans theorem :
le_trans: forall n m p : nat, n <= m -> m <= p -> n <= p
that comes from Le package.
It meas that you have to import Le or more generally Arith with :
Require Import Arith.
at the beginning of your file. Then, you can do :
eapply le_trans.
eapply H0; trivial.
trivial.