I'm new to Coq. I've been working through Pierce's Logical Foundations. I'm stepping into new ground.
I'm trying use of the field tactic for the first time. I use it thrice in the below theorem. Twice it fails, yielding m <> 0%R where m is a term in context.
I'm sure I just fail to understand proper use. May someone enlighten me? (I tried reading this doc page but didn't gain much understanding!)
From Coq Require Import Reals.Reals.
Require Import Field.
Definition simple_compound (A r n m : R) : R :=
A * (Rpower (1 + r / m) (m * n)).
Definition continuous_compound (A r n: R) : R :=
A * (exp (r * n)).
Definition simple_to_continuous_interest (Rs n m: R) : R :=
m * ln (1 + Rs / m).
Definition continuous_to_simple_interest (Rc n m: R) : R :=
m * ((exp (Rc / m)) - 1).
Theorem continuous_to_simple_works : forall (A Rc n m : R),
continuous_compound A Rc n = simple_compound A (continuous_to_simple_interest Rc n m) n m.
Proof.
intros A Rc n m.
unfold continuous_compound. unfold simple_compound. unfold continuous_to_simple_interest.
unfold Rpower. apply f_equal.
assert (H: (m * (exp (Rc / m) - 1) / m)%R = (exp (Rc / m) - 1)%R). {
field. admit.
}
rewrite -> H.
assert (H2: (1 + (exp (Rc / m) - 1))%R = (exp (Rc / m))%R). {
field.
}
rewrite -> H2.
assert (H3: (m * n * ln (exp (Rc / m)))%R = (ln (exp (Rc / m)) * m * n)%R). {
rewrite -> Rmult_comm. rewrite -> Rmult_assoc. reflexivity.
}
rewrite -> H3.
rewrite -> ln_exp.
assert (H4: (Rc / m * m)%R = Rc%R). {
field. admit.
}
rewrite -> H4.
reflexivity.
Admitted.
That is expected. Your first use of field is on a goal akin to (m * x) / m = x. There is absolutely no way of defining the division over real numbers so that this equality holds for all real numbers x when m is equal to 0. So, the field tactic is able to prove this equality only if you are able to prove m <> 0. Your third use of field is on an equality (x / m) * m = x, and again, it can only hold for any x if you know that m is nonzero.
Related
I’m trying to prove that for a list of bytes a, all bytes are x01 from index 2 to (n-m-2), where n is the length of a:
(forall (i : nat), ((i >= 2) /\ (i < ((n - m) - 1))) -> ((nth_error a i) = (Some x01)))
and I do have this in the context:
H : nth_error a ?j =
nth_error ([x00; x00] ++ repeat x01 (n - m - 2) ++ repeat x00 m)%list ?j
So, after intros i i_range. I have:
i : nat
i_range : is_true (1 < i) /\ is_true (i < n - m - 1)
H : nth_error a ?j =
nth_error ([x00; x00] ++ repeat x01 (n - m - 2) ++ repeat x00 m)%list ?j
______________________________________(1/1)
nth_error a i = Some x01
Is this a right approach to destruct the RHS of H to eliminate the first two bytes and the last m bytes? If so, how can I do that with respect to i_range? Let me know if my proof strategy is flawed.
Thanks in advance for any suggestion.
Edit:
The last goal's typo is fixed. It was nth_error buff i = Some x01 first and I changed to nth_error a i = Some x01.
If you can ensure H starts with “forall j,”, the goal should be provable. I am not sure I understand the strategy you suggests, but I’d rewrite ntherror (prefix ++ foo ++ bar) i to ntherror foo (i - 2) (using suitable lemmas, either existing or provable), then since foo is defined using repeat, rewrite ntherror (repeat baz x01) to x01. All these lemmas have arithmetic side conditions that should hold.
I'm new to Coq. I've been working through Pierce's Logical Foundations. I'm stepping out-of-scope of the text into Real numbers and finding myself clueless. I thought I'd prove something easy so I wrote out some formulas for interest calculations. Now I'd like to prove my conversions are correctly written in my Theorem.
I have no idea how to proceed and am in need of hints and guides!!!
From Coq Require Import Reals.Reals.
Definition simple_compound (A r n m : R) : R :=
A * (Rpower (1 + r / m) (m * n)).
Definition continuous_compound (A r n: R) : R :=
A * (exp (r * n)).
Definition simple_to_continuous_interest (Rm n m: R) : R :=
m * ln (1 + Rm).
Definition continuous_to_simple_interest (Rc n m: R) : R :=
m * (exp (Rc / m) - 1).
(** Prove that given Rm n m, then Rc is m * ln (1 + Rm). *)
Theorem continuous_to_simple_works : forall (A Rc n m : R),
continuous_compound A Rc n = simple_compound A (continuous_to_simple_interest Rc n m) n m.
Proof.
intros A Rc n m.
unfold continuous_compound. unfold simple_compound. unfold continuous_to_simple_interest.
simpl. (** ... and I'm stuck. I would know how to do this algebraically but am clueless in Coq. *)
First, I suggest to unfold Rpower.
Second, a useful lemma is f_equal; it states that, to prove f a = f b, it suffices to prove a = b. (There is also a tactic with the exact same name, which will behave similarly.)
Third, you need to perform some algebraic simplifications. To do so, you can use replace foo with bar; as the name implies, it replaces all the occurrences of foo in the goal with bar and it requires you to prove bar = foo. This latter equality can then be discharged with the field tactic, which checks that two expressions are equal by using the rewriting rules of addition, multiplication, division.
Fourth, you should end up with a goal containing a subterm ln (exp baz). Obviously, you want to replace it with baz. You can use the command Search (ln (exp _)) to find the name of the corresponding lemma. It happens to be named ln_exp, so rewrite ln_exp will do the trick.
I'm trying to prove that n <= 2^n in Coq, and I'm missing a simple lemma that must exist somewhere:
a <= b /\ c <= d -> a+c <= b+d
Even more generally, how can I search Coq libraries for lemmas like this one?
Here is my code for completeness:
(***********)
(* imports *)
(***********)
Require Import Nat.
Require Import Init.Nat.
Require Import Coq.Arith.PeanoNat.
(************************)
(* exponential function *)
(************************)
Definition f (a : nat) : nat := 2^a.
(**********************)
(* inequality theorem *)
(**********************)
Theorem a_leq_pow_2_a: forall a, a <= f(a).
Proof.
induction a as[|a' IHa].
- apply le_0_n.
- unfold f.
rewrite Nat.pow_succ_r.
* rewrite Nat.mul_comm.
rewrite Nat.mul_succ_r.
rewrite Nat.mul_1_r.
unfold f in IHa.
(* stuck here *)
Qed.
The command for searching lemmas is called Search. (For older Coq versions, it was split into SearchAbout, SearchPattern, etc.) See the documentation for all the possible variants.
In your case, you are looking for a lemma with a consequent of the form _+_ <= _+_. So, you can type the following, which will give six results, including the one you are looking for:
Search (_ + _ <= _ + _).
(*
Nat.add_le_mono_r: forall n m p : nat, n <= m <-> n + p <= m + p
Nat.add_le_mono: forall n m p q : nat, n <= m -> p <= q -> n + p <= m + q
...
*)
I'm using Coq 8.5pl1.
To make a contrived but illustrative example,
(* fix so simpl will automatically unfold. *)
Definition double := fix f n := 2*n.
Theorem contrived n : double (2 + n) = 2 + double (1 + n).
Now, I only want to simplify the arguments to double,
and not any part outside of it. (For example, because the
rest has already carefully been put into the correct form.)
simpl.
S (S (n + S (S (n + 0)))) = S (S (S (n + S (n + 0))))
This converted the outside (2 + ...) to (S (S ...)) as well as unfolding double.
I can match one of them by doing:
match goal with | |- (double ?A) = _ => simpl A end.
double (S (S n)) = 2 + double (1 + n)
How do I say that I want to simplify all of them?
That is, I want to get
double (S (S n)) = 2 + double (S n)
without having to put a separate pattern for each call to double.
I can simplify except for double itself with
remember double as x; simpl; subst x.
double (S (S n)) = S (S (double (S n)))
Opaque/Transparent approach
Combining the results of this answer and this one, we get the following solution:
Opaque double.
simpl (double _).
Transparent double.
We use the pattern capability of simpl to narrow down its "action domain", and Opaque/Transparent to forbid (allow resp.) unfolding of double.
Custom tactic approach
We can also define a custom tactic for simplifying arguments:
(* simplifies the first argument of a function *)
Ltac simpl_arg_of function :=
repeat multimatch goal with
| |- context [function ?A] =>
let A' := eval cbn -[function] in A in
change A with A'
end.
That let A' := ... construction is needed to protect nested functions from simplification. Here is a simple test:
Fact test n :
82 + double (2 + n)
=
double (1 + double (1 + 20)) + double (1 * n).
Proof.
simpl_arg_of double.
The above results in
82 + double (S (S n)) = double (S (double 21)) + double (n + 0)
Had we used something like context [function ?A] => simpl A in the definition of simpl_arg_of, we would've gotten
82 + double (S (S n)) = double 43 + double (n + 0)
instead.
Arguments directive approach
As suggested by #eponier in comments, we can take advantage of yet another form of simpl -- simpl <qualid>, which the manual defines as:
This applies simpl only to the applicative subterms whose head occurrence is the unfoldable constant qualid (the constant can be referred to by its notation using string if such a notation exists).
The Opaque/Transparent approach doesn't work with it, however we can block unfolding of double using the Arguments directive:
Arguments double : simpl never.
simpl double.
You may find the ssreflect pattern selection language and rewrite mechanism useful here. For instance, you can have a finer grained control with patterns + the simpl operator /=:
From mathcomp Require Import ssreflect.
Definition double := fix f n := 2*n.
Theorem contrived n : double (2 + n) = 2 + double (1 + n).
rewrite ![_+n]/=.
Will display:
n : nat
============================
double (S (S n)) = 2 + double (S n)
You can also use anonymous rewrite rules:
rewrite (_ : double (2+n) = 2 + double (1+n)) //.
I would personally factor the rewrite in smaller lemmas:
Lemma doubleE n : double n = n + n.
Proof. by elim: n => //= n ihn; rewrite -!plus_n_Sm -plus_n_O. Qed.
Lemma doubleS n : double (1 + n) = 2 + double n.
Proof. by rewrite !doubleE /= -plus_n_Sm. Qed.
Theorem contrived n : double (1+n) = 2 + double n.
rewrite doubleS.
I have some trouble understanding how to use some of the things I've defined in Coq within proofs. I have this fragment of definition and functions:
Inductive string : Set :=
| E : string
| s : nat -> string -> string.
Inductive deduce : Set :=
|de : string -> string -> deduce.
Infix "|=" := de.
Inductive Rules : deduce -> Prop :=
| compress : forall (n : nat) (A : string), rule (( s n ( s n A)) |= ( s n A))
| transitive : forall A B C : string, rule (A |= B) -> rule (B |= C) -> rule (A |= C).
Fixpoint RepString (n m : nat): string:=
match n with
|0 => E
|S n => s m ( RepString n m)
end.
I need to prove something apparently easy but I bump into two problems:
Lemma LongCompress (C : string)(n : nat): n >=1 -> Rules
((RepString n 0 ) |= (s 0 E) ).
Proof.
intros.
induction n.
inversion H.
simpl.
apply compress.
So here I have problem one, I get:
"Unable to unify "Rules (s ?M1805 (s ?M1805 ?M1806) |= s ?M1805 ?M1806)" with
"Rules (s 0 (RepString n 0) |- s 0 E)".'"
Now, I can see why I get the error, while technically RepString n 0 is the same as s 0 (s 0 (s 0( ... s 0 E))) I simply can't find the way to let coq know that, I've tried messing with apply compress with like 10 different things I still can't get it right. I need to "unfold" it something like that (of course unfold doesn't work...).
I'm out of ideas and I would very much appreciate any input you have on this!
EDIT FROM NOW ON.
Inductive Rules : deduce -> Prop :=
| compress : forall (n : nat) (A : string), rule (( s n ( s n A)) |= ( s n A))
| transitive : forall A B C : string, rule (A |= B) -> rule (B |= C) -> rule (A |= C)
| inspection : forall (n m : nat) (A : string), m < n -> rule ((s n A) |- (s m A)).
Definition less (n :nat ) (A B : string) := B |= (s n A).
Lemma oneLess (n m : nat): rule (less 0 (RepString n 1) (RepString m 1)) <-> n< m.
I have generalised the lemmas that Anton Trunov helped me prove, but now I bumped into another wall. I think the problem might start with the way I've written the Theorem itself, I will appreciate any ideas.
I'd prove something a little bit more general: for any two non-empty strings of zeros s = 0000...0 and t = 00...0, if length s > length t, then s |= t, i.e.
forall n m,
m <> 0 ->
n > m ->
Rules (RepString n 0 |= RepString m 0).
Here is a helper lemma:
Require Import Coq.Arith.Arith.
Require Import Coq.omega.Omega.
Hint Constructors Rules. (* add this line after the definition of `Rules` *)
Lemma LongCompress_helper (n m k : nat):
n = (S m) + k ->
Rules (RepString (S n) 0 |= RepString (S m) 0).
Proof.
generalize dependent m.
generalize dependent n.
induction k; intros n m H.
- Search (?X + 0 = ?X). rewrite Nat.add_0_r in H.
subst. simpl. eauto.
- apply (transitive _ (RepString n 0) _); simpl in H; rewrite H.
+ simpl. constructor.
+ apply IHk. omega.
Qed.
Now, we can easily prove our advertised general lemma:
Lemma LongCompress_general (n m : nat):
m <> 0 ->
n > m ->
Rules (RepString n 0 |= RepString m 0).
Proof.
intros Hm Hn. destruct n.
- inversion Hn.
- destruct m.
+ exfalso. now apply Hm.
+ apply LongCompress_helper with (k := n - m - 1). omega.
Qed.
It's easy to see that any sufficiently long string of zeros can be compressed into the singleton-string 0:
Lemma LongCompress (n : nat):
n > 1 -> Rules ( RepString n 0 |= s 0 E ).
Proof.
intro H. replace (s 0 E) with (RepString 1 0) by easy.
apply LongCompress_general; auto.
Qed.