Isabelle: If statement inside a sum - isabelle

I have a problem with an if-statement within a sum.
I checked the solution in another question on if statements in isabelle
but it did not help.
Here is an example:
theorem dummy:
fixes a :: "('a::comm_ring_1 poly)"
and B :: "(('a::comm_ring_1 poly)^'n∷finite^'n∷finite)"
shows "1=1"
proof-
{ fix i j
have "(∑k∈UNIV. if i = k then (B $ i $ j) else 0) = B $ i $ j" sorry
}
How can I prove the lemma where the "sorry" is?

The theorem you are looking for is setsum_delta:
finite ?S ⟹
(∑k∈?S. if k = ?a then ?b k else 0) =
(if ?a ∈ ?S then ?b ?a else 0)
If you write k = i instead of i = k in your sum, it can even be solved automatically:
have "(∑k∈UNIV. if k = i then (B $ i $ j) else 0) = B $ i $ j"
by (simp add: setsum_delta)
The find_theorems command is very useful for this. If you type
find_theorems "∑_∈_. if _ then _ else _"
You get setsum_delta as one of the matches – that's how I found it.

Related

Transformation of goals by "rule"

I'm trying to use rule dec_induct to do an induction proof with a base case that is not 0, but I don't understand how the rule is being applied by Isabelle. If I state the following lemma:
lemma test:
shows "P a"
proof (rule dec_induct)
Isabelle transforms it into three subgoals, which I assume are supposed to be the premises of dec_induct unified with my goal. dec_induct is
⟦?i ≤ ?j; ?P ?i; ⋀n. ⟦?i ≤ n; n < ?j; ?P n⟧ ⟹ ?P (Suc n)⟧ ⟹ ?P ?j
, so I would think that the ?j in its conclusion would unify with the "a" of my goal. That is, I would expect the following three subgoals:
?i ≤ a
?P ?i
⋀n. ⟦?i ≤ n; n < a; ?P n⟧ ⟹ ?P (Suc n)
But the subgoals Isabelle actually transforms it to are
?i ≤ ?j
P a
⋀n. ⟦?i ≤ n; n < ?j; P a⟧ ⟹ P a
How is Isabelle getting that, and how can I get it to perform the induction as I expect? I realize I should be using the induct method, but I'm just trying to understand how rule works.
Higher order unification can produce very unintuitive results, especially when you have patterns like ?f ?x, i.e. a schematic variable of function type, applied to another schematic variable. I don't know much about higher order unification, but it seems that if you unify ?f ?x with something like f x, you tend to get the unifier [?f ↦ λy. f x] instead of [?f ↦ f, ?x ↦ x], which is probably what you wanted.
You can experiment with it like this to see precisely what the possible inferred unifiers are:
context
fixes P :: "int ⇒ bool" and j :: int
begin
ML ‹
local
val ctxt = Context.Proof #{context}
val env = Envir.init
val ctxt' = #{context} |> Proof_Context.set_mode Proof_Context.mode_schematic
val s1 = "?P ?j"
val s2 = "P j"
val (t1, t2) = apply2 (Syntax.read_term ctxt') (s1, s2)
val prt = Syntax.pretty_term #{context}
fun pretty_schem s = prt (Var ((s, 0), \<^typ>‹unit›))
fun pretty_unifier (Envir.Envir {tenv, ...}, _) =
tenv
|> Vartab.dest
|> map (fn ((s,_),(_,t)) => Pretty.block
(Pretty.breaks [pretty_schem s, Pretty.str "↦", prt t]))
|> (fn x => Pretty.block (Pretty.str "[" :: Pretty.commas x # [Pretty.str "]"]))
in
val _ =
Pretty.breaks [Pretty.str "Unifiers for", prt t1, Pretty.str "and", prt t2, Pretty.str ":"]
|> Pretty.block
|> Pretty.writeln
val _ =
Unify.unifiers (ctxt, env, [(t1, t2)])
|> Seq.list_of
|> map pretty_unifier
|> map (fn x => Pretty.block [Pretty.str "∙ ", x])
|> map (Pretty.indent 2)
|> Pretty.fbreaks
|> Pretty.block
|> Pretty.writeln
end
›
Output:
Unifiers for ?P ?j and P j :
∙ [?P ↦ λa. P j]
(Disclaimer: This is only experimental code to illustrate what is going on, this is not clean Isabelle/ML coding style.)
To summarise: don't rely on higher-order unification to figure out instantiations of function variables, especially when you have patterns like ?f ?x.

Simplifying if-then-else in summations or products

While doing some basic algebra, I frequently arrive at a subgoal of the following type (sometimes with a finite sum, sometimes with a finite product).
lemma foo:
fixes N :: nat
fixes a :: "nat ⇒ nat"
shows "(a 0) = (∑x = 0..N. (if x = 0 then 1 else 0) * (a x))"
This seems pretty obvious to me, but neither auto nor auto cong: sum.cong split: if_splits can handle this. What's more, sledgehammer also surrenders when called on this lemma. How can one efficiently work with finite sums and products containing if-then-else in general, and how to approach this case in particular?
My favourite way to do these things (because it is very general) is to use the rules sum.mono_neutral_left and sum.mono_neutral_cong_left and the corresponding right versions (and analogously for products). The rule sum.mono_neutral_right lets you drop arbitrarily many summands if they are all zero:
finite T ⟹ S ⊆ T ⟹ ∀i∈T - S. g i = 0
⟹ sum g T = sum g S
The cong rule additionally allows you to modify the summation function on the now smaller set:
finite T ⟹ S ⊆ T ⟹ ∀i∈T - S. g i = 0 ⟹ (⋀x. x ∈ S ⟹ g x = h x)
⟹ sum g T = sum h S
With those, it looks like this:
lemma foo:
fixes N :: nat and a :: "nat ⇒ nat"
shows "a 0 = (∑x = 0..N. (if x = 0 then 1 else 0) * a x)"
proof -
have "(∑x = 0..N. (if x = 0 then 1 else 0) * a x) = (∑x ∈ {0}. a x)"
by (intro sum.mono_neutral_cong_right) auto
also have "… = a 0"
by simp
finally show ?thesis ..
qed
Assuming the left-hand side could use an arbitrary value between 0 and N, what about adding a more general lemma
lemma bar:
fixes N :: nat
fixes a :: "nat ⇒ nat"
assumes
"M ≤ N"
shows "a M = (∑x = 0..N. (if x = M then 1 else 0) * (a x))"
using assms by (induction N) force+
and solving the original one with using bar by blast?

Reasoning about the boolean vector in Coq, based on the value of its sum. (kind of universal instantiation for vectors)

I've got stuck with theorem which is easy to formulate:
"If the maximal element of the vector is 0 then each element of the vector is 0".
The goal is to be able to use such an idiom as "fold_left orb false v".
So my first aim is to prove this particular lemma:
Lemma all_then_some (A:Type) :
forall (n:nat) (p:Fin.t (S n))
(v : Vector.t bool (S n))
(H : (Vector.fold_left orb false v) = false),
(Vector.nth v p) = false.
Proof.
...
Some thoughts:
1) To strengthen the hypothesis and prove something like this:
(forall (b:bool), (List.fold_left orb l b) = b) <->
(forall (p:nat), (List.nth p l false) = false)
(** NB: variant for lists here! **)
2) Use principle "rectS" from the standard library /Vectors/Fin.v
3) Use small scale reflection library.
UPDATE: to find the partial solution please see my answer below.(ged)
UPDATE2: Solution is here: https://github.com/georgydunaev/TRASH/blob/master/UNIV_INST.v
(it is called "Theorem all_then_someV")
You can indeed use a more structured lemma from math-comp, a quick example [that can surely be improved]:
From mathcomp Require Import all_ssreflect.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Lemma nat_of_bool_inj : injective nat_of_bool.
Proof. by case=> [] []. Qed.
Lemma all_false n (r : n.-tuple bool) :
\max_(i in 'I_n) tnth r i <= 0 ->
forall i, tnth r i = false.
Proof.
by move/bigmax_leqP => H i; apply/nat_of_bool_inj/eqP; rewrite -leqn0 H.
Qed.
You have some more specialized lemmas relating \big[orb/false] with has.
The code consists of two parts:
I have proved my lemma for List in the 1st part and, similarly, I have almost proved for Vector in the 2nd part.
There is a problem in the last step of the second part.
("induction p." causes "Abstracting over the terms "n0" and "p" leads to a term … which is ill-typed". I don't understand what shall I do instead of "induction p.".)
(*PART 1*)
Require Import Coq.Lists.List.
Import ListNotations.
Fixpoint A2 l :fold_left orb l true = true.
Proof.
destruct l; simpl.
reflexivity.
apply A2.
Defined.
Theorem A1 (x y:bool): (orb x y = false)->(x=false)/\(y=false).
Proof. intro H. destruct x, y; firstorder || inversion H. Defined.
Fixpoint A0 b l : fold_left orb (b :: l) false = orb b (fold_left orb l false) .
Proof.
destruct l.
simpl. firstorder.
simpl.
destruct b.
simpl.
apply A2.
simpl.
reflexivity.
Defined.
Fixpoint all_then_some (l:list bool) {struct l}:
(List.fold_left orb l false) = false ->
(forall (p:nat), (List.nth p l false) = false).
Proof.
intros.
destruct l. simpl. destruct p; trivial.
simpl.
rewrite A0 in H.
pose (Q:=A1 _ _ H).
destruct Q.
destruct p. trivial.
apply all_then_some.
trivial.
Defined.
(*PART 2*)
Require Import Coq.Vectors.Vector.
Import VectorNotations.
Fixpoint B2 (n:nat) (l:t bool n) :fold_left orb true l = true.
Proof.
destruct l; simpl.
reflexivity.
apply B2.
Defined.
Fixpoint B0 b (n:nat) (l:t bool n) :
fold_left orb false (b :: l) = orb b (fold_left orb false l) .
Proof.
destruct l.
simpl. firstorder.
simpl.
destruct b.
simpl.
apply B2.
simpl.
reflexivity.
Defined.
Fixpoint all_then_someV (n:nat) (l:Vector.t bool n) {struct l}:
(Vector.fold_left orb false l ) = false ->
(forall p, (Vector.nth l p ) = false).
Proof.
intros.
induction l eqn:equa.
inversion p. (* simpl. destruct p; trivial.*)
(*simpl.*)
rewrite B0 in H.
pose (Q:=A1 _ _ H).
destruct Q.
induction p.
I think something like the following code can help (because "destruct" tactic is like "_rect" application), but I am not sure.
Definition G0 h (n:nat) (l:Vector.t bool n) := fold_left orb false (h :: l) = false.
fold G0 in H.
assert (vari : G0 h n l).
exact H.
clear H.
revert h l vari.
set (P := fun n p => forall (h : bool) (l : t bool n) (_ : G0 h n l),
#eq bool (#nth bool (S n) (cons bool h n l) p) false).
unshelve eapply (#Fin.rectS P).
UPDATE2: Solution is here: https://github.com/georgydunaev/TRASH/blob/master/UNIV_INST.v
(it is called "Theorem all_then_someV")

How to replace hypotheses `0 < d` with `S d'` in Coq?

How to replace hypotheses 0 < d with S d' in Coq?
In Coq, I've the annoying hypotheses that 0 < d, which I need to replace to apply euclid_div_succ_d_theorem to prove euclid_div_theorem as a corollary.
How can I somehow convert the assumptions into the proper form to apply the theorem?
Theorem euclid_div_theorem :
forall d : nat,
0 < d ->
forall n : nat,
exists q r : nat,
n = q * d + r /\ r < d.
Theorem euclid_div_succ_d_theorem :
forall d : nat,
forall n : nat,
exists q r : nat,
n = q * (S d) + r /\ r < (S d).
Using the standard lemmas from the Arith module you can change 0 < d into exists m, d = S m, which (after destruction) gives you the desired result.
Require Import Arith.
Theorem euclid_div_theorem : forall d : nat,
0 < d -> forall n : nat, exists q r : nat, n = q * d + r /\ r < d.
Proof.
intros d H n.
apply Nat.lt_neq, Nat.neq_sym, Nat.neq_0_r in H.
destruct H; rewrite H.
apply euclid_div_succ_d_theorem.
Qed.
Here is how I did it:
Search (exists _, _ = S _). gives us the last lemma (it's easier to go backwards from your goal here, imho):
Nat.neq_0_r: forall n : nat, n <> 0 <-> (exists m : nat, n = S m)
This means we need to infer d <> 0 from 0 < d, so again Search (_ < _ -> _ <> _). yields:
Nat.lt_neq: forall n m : nat, n < m -> n <> m
Now it's easy to see that we need to swap the lhs and rhs of the inequality, so I did Search (?x <> ?y -> ?y <> ?x).:
Nat.neq_sym: forall n m : nat, n <> m -> m <> n
I could've also used a more universal lemma:
not_eq_sym: forall (A : Type) (x y : A), x <> y -> y <> x
It'd give us the same result.
There is, however, a less tedious way of proving the lemma -- you can always use destruct d. and prove it by cases:
intros d H n.
destruct d.
- inversion H. (* H is a contradiction now: `0 < 0` *)
- apply euclid_div_succ_d_theorem.

coq --- function power definition

I am interested in how would one define f to the n in Coq:
Basically, as an exercise, I would like to write this definition and then confirm that my
algorithm implements this specification. Inductive definition seems appropriate here, but I was not able to make it clean as above. What would be a clean Coq implementation of the above?
With the pow_func function that gallais defined, you can state your specification as lemmas, such as:
Lemma pow_func0: forall (A:Type) (f: A -> A) (x: A), pow_fun f O x = f x.
and
Lemma pow_funcS: forall (n:nat) (A: Type) (f: A->A) (x:A), pow_fun f (S n) x = f (pow_fun f n x).
The proof should be trivial by unfolding the definition
Inductive is used to define types closed under some operations; this is not what you are looking for here. What you want to build is a recursive function iterating over n. This can be done using the Fixpoint keyword:
Fixpoint pow_func {A : Type} (f : A -> A) (n : nat) (a : A) : A :=
match n with
| O => f a
| S n => f (pow_func f n a)
end.
If you want a nicer syntax for this function, you can introduce a Notation:
Notation "f ^ n" := (pow_func f n).
However, note that this is not a well-behaved definition of a notion of power: if you compose f ^ m and f ^ n, you don't get f ^ (m + n) but rather f ^ (1 + m + n). To fix that, you should pick the base case f ^ 0 to be the neutral element for composition id rather than f itself. Which would give you:
Fixpoint pow_func' {A : Type} (f : A -> A) (n : nat) (a : A) : A :=
match n with
| O => a
| S n => f (pow_func' f n a)
end.

Resources