How to work with the WHILE loop constructor while constructing proofs in the simple imperative language of SF - while-loop

In the IMP chapter of SF, I don't know how to work with the while statements (particularly, the E_WhileTrue constructor). In the below code I'm getting a unification error.
This is not a problem in the book, but an example I made up.
Can you please explain how I can work through multiple loops in a while loop so that I can understand how to complete this example
Example ceval_example1234:
empty_st =[
X ::= 2;;
WHILE X <= 2
DO Y ::= 3 ;; X ::= X + 1
END
]=> (X !-> 3; Y !-> 3 ; X !-> 2).
Proof.
(* We must supply the intermediate state *)
apply E_Seq with (X !-> 2).
- (* assignment command *)
apply E_Ass. reflexivity.
- apply E_WhileTrue with (Y !-> 3; X !-> 2). simpl. reflexivity.
apply E_Seq with ( Y !-> 3; X !-> 2).
apply E_Ass. reflexivity.
Everything below here is more or less what I want to do to finish the proof.
apply E_Ass. reflexivity.
apply E_WhileFalse.
reflexivity.
Qed.

Got it.
Example ceval_example1234:
empty_st =[
X ::= 2;;
WHILE X <= 2
DO Y ::= 3 ;; X ::= X + 1
END
]=> (X !-> 3; Y !-> 3 ; X !-> 2).
Proof.
(* We must supply the intermediate state *)
apply E_Seq with (X !-> 2).
- (* assignment command *)
apply E_Ass. reflexivity.
- apply E_WhileTrue with (X !-> 3; Y !-> 3; X !-> 2). simpl. reflexivity.
apply E_Seq with ( Y !-> 3; X !-> 2).
apply E_Ass. reflexivity.
apply E_Ass. simpl. reflexivity.
apply E_WhileFalse.
simpl. reflexivity.
Qed.

Related

Are variables bounded to free variables still free variables?

I am looking at some questions in my textbook about whether or not the variables are free or bound. I am not sure about these two in particular.
First off, I want to make sure I understand the concept of free vs. bound. I am fairly sure this x is a free variable in the following:
variable x is free in expression "x"
I believe this is true but I just want to make sure.
These two questions I am not really sure about, however.
(/ (+ 1 x) (let x 2 (+ x x))),
(let x y (/ (+ 1 x) (let x 2 (+ x x))))
For the top expression, the x in the first subexpression is unbound(right?) but x in the second subexpression is bound to 2, so would that mean the x in regards to the expression as a whole is unbound?
For the bottom expression, x is bound to y, but y is a free variable(?). So would x be free because y is free or is it bound because x is still bounded to y?
For (/ (+ 1 x) (let x 2 (+ x x))), the x in the first subexpression is unbound but x in the second subexpression is bound to 2, so would that mean the x in regards to the expression as a whole is unbound?
Yes. Although I would use the terminology "is bound" or "is free" only with respect to a concrete variable expression, not to a name. As you can see, it's ambiguous what "x" refers to.
I'd say "the whole expression has a free variable x", which is what you usually care about when trying to evaluate the expression.
For (let x y (/ (+ 1 x) (let x 2 (+ x x)))), x is bound to y, but y is a free variable. So would x be free because y is free or is it bound because x is still bounded to y?
The x is bound (and can be substituted). y is free.

Proving `weaken` doesn't change the value of a number

Let's say we want to prove that weakening the upper bound of a Data.Fin doesn't change the value of the number. The intuitive way to state this is:
weakenEq : (num : Fin n) -> num = weaken num
Let's now generate the defini... Hold on! Let's think a bit about that statement. num and weaken num have different types. Can we state the equality in this case?
The documentation on = suggests we can try to, but we might want to use ~=~ instead. Well, anyway, let's go ahead and generate the definition and case-split, resulting in
weakenEq : (num : Fin n) -> num = weaken num
weakenEq FZ = ?weakenEq_rhs_1
weakenEq (FS x) = ?weakenEq_rhs_2
The goal in the weakenEq_rhs_1 hole is FZ = FZ, which still makes sense from the value point of view. So we optimistically replace the hole with Refl, but only to fail:
When checking right hand side of weakenEq with expected type
FZ = weaken FZ
Unifying k and S k would lead to infinite value
A somewhat cryptic error message, so we wonder if that's really related to the types being different.
Anyway, let's try again, but now with ~=~ instead of =. Unfortunately, the error is still the same.
So, how one would state and prove that weaken x doesn't change the value of x? Does it really make sense to? What should I do if that's a part of a larger proof where I might want to rewrite a Vect n (Fin k) with Vect n (Fin (S k)) that's obtained by mapping weaken over the original vector?
If you really want to prove that the value of the Fin n does not change after applying the weaken function, you would need to prove the equality of these values:
weakenEq: (num: Fin n) -> finToNat num = finToNat $ weaken num
weakenEq FZ = Refl
weakenEq (FS x) = cong $ weakenEq x
To your second problem/Markus' comment about map (Data.Fin.finToNat) v = map (Data.Fin.finToNat . Data.Fin.weaken) v:
vectorWeakenEq : (v: Vect n (Fin k)) ->
map Fin.finToNat v = map (Fin.finToNat . Fin.weaken) v
vectorWeakenEq [] = Refl
vectorWeakenEq (x :: xs) =
rewrite sym $ weakenEq x in
cong {f=(::) (finToNat x)} (vectorWeakenEq xs)
And to see why num = weaken num won't work, let's take a look at a counterexample:
getSize : Fin n -> Nat
getSize _ {n} = n
Now with x : Fin n, getSize x = n != (n + 1) = getSize (weaken x). This won't happen with functions which only depend on the constructors, like finToNat. So you have to constrain yourself to those and prove that they behave like that.

Obtain decidable total order on a type from an injection into `nat`

Since the natural numbers support a decidable total order, the injection nat_of_ascii (a : ascii) : nat induces a decidable total order on the type ascii. What would be a concise, idiomatic way of expressing this in Coq? (With or without type classes, modules, etc.)
Such process is fairly routine and will depend on the library you have chosen. For order.v, based on math-comp, the process is totally mechanical [in fact, we'll develop a general construction for types with an injection to total orders later in the post]:
From Coq Require Import Ascii String ssreflect ssrfun ssrbool.
From mathcomp Require Import eqtype choice ssrnat.
Require Import order.
Import Order.Syntax.
Import Order.Theory.
Lemma ascii_of_natK : cancel nat_of_ascii ascii_of_nat.
Proof. exact: ascii_nat_embedding. Qed.
(* Declares ascii to be a member of the eq class *)
Definition ascii_eqMixin := CanEqMixin ascii_of_natK.
Canonical ascii_eqType := EqType _ ascii_eqMixin.
(* Declares ascii to be a member of the choice class *)
Definition ascii_choiceMixin := CanChoiceMixin ascii_of_natK.
Canonical ascii_choiceType := ChoiceType _ ascii_choiceMixin.
(* Specific stuff for the order library *)
Definition ascii_display : unit. Proof. exact: tt. Qed.
Open Scope order_scope.
(* We use the order from nat *)
Definition lea x y := nat_of_ascii x <= nat_of_ascii y.
Definition lta x y := ~~ (lea y x).
Lemma lea_ltNeq x y : lta x y = (x != y) && (lea x y).
Proof.
rewrite /lta /lea leNgt negbK lt_neqAle.
by rewrite (inj_eq (can_inj ascii_of_natK)).
Qed.
Lemma lea_refl : reflexive lea.
Proof. by move=> x; apply: le_refl. Qed.
Lemma lea_trans : transitive lea.
Proof. by move=> x y z; apply: le_trans. Qed.
Lemma lea_anti : antisymmetric lea.
Proof. by move=> x y /le_anti /(can_inj ascii_of_natK). Qed.
Lemma lea_total : total lea.
Proof. by move=> x y; apply: le_total. Qed.
(* We can now declare ascii to belong to the order class. We must declare its
subclasses first. *)
Definition asciiPOrderMixin :=
POrderMixin lea_ltNeq lea_refl lea_anti lea_trans.
Canonical asciiPOrderType := POrderType ascii_display ascii asciiPOrderMixin.
Definition asciiLatticeMixin := Order.TotalLattice.Mixin lea_total.
Canonical asciiLatticeType := LatticeType ascii asciiLatticeMixin.
Canonical asciiOrderType := OrderType ascii lea_total.
Note that providing an order instance for ascii gives us access to a large theory of total orders, plus operators, etc..., however the definition of total itself is fairly simple:
"<= is total" == x <= y || y <= x
where <= is a "decidable relation" and we assume, of course, decidability of equality for the particular type. Concretely, for an arbitrary relation:
Definition total (T: Type) (r : T -> T -> bool) := forall x y, r x y || r y x.
so if T is and order, and satisfies total, you are done.
More generally, you can define a generic principle to build such types using injections:
Section InjOrder.
Context {display : unit}.
Local Notation orderType := (orderType display).
Variable (T : orderType) (U : eqType) (f : U -> T) (f_inj : injective f).
Open Scope order_scope.
Let le x y := f x <= f y.
Let lt x y := ~~ (f y <= f x).
Lemma CO_le_ltNeq x y: lt x y = (x != y) && (le x y).
Proof. by rewrite /lt /le leNgt negbK lt_neqAle (inj_eq f_inj). Qed.
Lemma CO_le_refl : reflexive le. Proof. by move=> x; apply: le_refl. Qed.
Lemma CO_le_trans : transitive le. Proof. by move=> x y z; apply: le_trans. Qed.
Lemma CO_le_anti : antisymmetric le. Proof. by move=> x y /le_anti /f_inj. Qed.
Definition InjOrderMixin : porderMixin U :=
POrderMixin CO_le_ltNeq CO_le_refl CO_le_anti CO_le_trans.
End InjOrder.
Then, the ascii instance gets rewritten as follows:
Definition ascii_display : unit. Proof. exact: tt. Qed.
Definition ascii_porderMixin := InjOrderMixin (can_inj ascii_of_natK).
Canonical asciiPOrderType := POrderType ascii_display ascii ascii_porderMixin.
Lemma lea_total : #total ascii (<=%O)%O.
Proof. by move=> x y; apply: le_total. Qed.
Definition asciiLatticeMixin := Order.TotalLattice.Mixin lea_total.
Canonical asciiLatticeType := LatticeType ascii asciiLatticeMixin.
Canonical asciiOrderType := OrderType ascii lea_total.

sbcl illegal function call

I decided reading SICP a little, just to see what it is all about (I am not MIT student, actually already almost done with studying, this is no homework, but the content might be homework for someone.). Since I have installed sbcl, I have to change syntax a little, compared to the book. However, I don't understand why my solution to exercise 1.3 is not working:
(defun square (x) (* x x))
(defun sum-of-squares (x y)
(+ (square x) (square y)))
(defun sum-of-squares-two-max (x y z) (
(cond
((eq (min x y z) x) (sum-of-squares y z))
((eq (min x y z) y) (sum-of-squares x z))
(t (sum-of-squares x y))
)))
To load this I run sbcl --load exercise-1.3.lisp. When I load it, I get the error:
; file: /home/xiaolong/development/LISP/SICP/exercise-1.3.lisp
; in: DEFUN SUM-OF-SQUARES-TWO-MAX
; ((COND ((EQ (MIN X Y Z) X) (SUM-OF-SQUARES Y Z))
; ((EQ (MIN X Y Z) Y) (SUM-OF-SQUARES X Z)) (T (SUM-OF-SQUARES X Y))))
;
; caught ERROR:
; illegal function call
; (DEFUN SUM-OF-SQUARES-TWO-MAX (X Y Z)
; ((COND ((EQ # X) (SUM-OF-SQUARES Y Z)) ((EQ # Y) (SUM-OF-SQUARES X Z))
; (T (SUM-OF-SQUARES X Y)))))
;
; caught STYLE-WARNING:
; The variable X is defined but never used.
;
; caught STYLE-WARNING:
; The variable Y is defined but never used.
;
; caught STYLE-WARNING:
; The variable Z is defined but never used.
;
; compilation unit finished
; caught 1 ERROR condition
; caught 3 STYLE-WARNING conditions
Multiple things I don't understand:
Why are some variables not used? I use all of them in the conditional ...
Why is a function call illegal? How can I compose functions if I cannot call a function from inside a function? (I probably can, but I am doing it wrong?)
When I comment out the third function, it loads without errors.
I checked the syntax for the conditional multiple times already, cannot find the mistake.
How can I correct this code?
Get rid of the extra open paren.
(defun sum-of-squares-two-max (x y z)
(cond
((eq (min x y z) x) (sum-of-squares y z))
((eq (min x y z) y) (sum-of-squares x z))
(t (sum-of-squares x y))))
The issue is that, with the paren, the code will call whatever your cond will evaluate to (as with all first items within parens). Without the paren, it knows that the result of the function is whatever the cond evaluates to.
Also, a general warning: SICP uses scheme, so you'll see some small differences between the book and what common lisp macros force you into.

Struggling with rewrite tactic in Idris

I'm going through Terry Tao's real analysis textbook, which builds up fundamental mathematics from the natural numbers up. By formalizing as many of the proofs as possible, I hope to familiarize myself with both Idris and dependent types.
I have defined the following datatype:
data GE: Nat -> Nat -> Type where
Ge : (n: Nat) -> (m: Nat) -> GE n (n + m)
to represent the proposition that one natural number is greater than or equal to another.
I'm currently struggling to prove reflexivity of this relation, i.e. to construct the proof with signature
geRefl : GE n n
My first attempt was to simply try geRefl {n} = Ge n Z, but this has type Ge n (add n Z). To get this to unify with the desired signature, we obviously have to perform some kind of rewrite, presumably involving the lemma
plusZeroRightNeutral : (left : Nat) -> left + fromInteger 0 = left
My best attempt is the following:
geRefl : GE n n
geRefl {n} = x
where x : GE n (n + Z)
x = rewrite plusZeroRightNeutral n in Ge n Z
but this does not typecheck.
Can you please give a correct proof of this theorem, and explain the reasoning behind it?
The first problem is superficial: you are trying to apply the rewriting at the wrong place. If you have x : GE n (n + Z), then you'll have to rewrite its type if you want to use it as the definition of geRefl : GE n n, so you'd have to write
geRefl : GE n n
geRefl {n} = rewrite plusZeroRightNeutral n in x
But that still won't work. The real problem is you only want to rewrite a part of the type GE n n: if you just rewrite it using n + 0 = n, you'd get GE (n + 0) (n + 0), which you still can't prove using Ge n 0 : GE n (n + 0).
What you need to do is use the fact that if a = b, then x : GE n a can be turned into x' : GE n b. This is exactly what the replace function in the standard library provides:
replace : (x = y) -> P x -> P y
Using this, by setting P = GE n, and using Ge n 0 : GE n (n + 0), we can write geRefl as
geRefl {n} = replace {P = GE n} (plusZeroRightNeutral n) (Ge n 0)
(note that Idris is perfectly able to infer the implicit parameter P, so it works without that, but I think in this case it makes it clearer what is happening)