В доказательстве мне нужно показать, что «если n не кратно трем, то n + n также не кратно трем». Я думаю, что мое доказательство слишком длинное и не очень элегантное. Есть ли какой-нибудь более красивый способ написать это? С или без ssreflect? (Я уверен, что в ssreflect есть oneliner :)).

Мое доказательство выполняет индукцию по n в три шага.

Require Import Omega.
Lemma math_helper n: forall k, (forall q, n <> q * 3) ->  n + n <> k * 3.
  (* name the predicate Q and strengthen induction hypothesis *)
  pattern n; match goal with [ _:_ |- ?P ?n] => let X := fresh Q in remember P as X end.
  enough (Q n /\ Q (1+n) /\ Q (2+n)) by tauto.
  induction n; subst Q;
    [| destruct IHn as [IH1 [IH2 IH3]]];
    repeat split; simpl; intros; auto; try omega.
  intro C; assert (k>=2) by omega; do 2 (try destruct k); try omega.
  assert (n+n = k*3) by omega.
  apply (IH1 k); auto; intros q HH; eapply (H (1+q)); subst n; omega.
Qed.
coq
3
larsr 5 Сен 2017 в 09:22

5 ответов

Лучший ответ

Существует еще более простое решение, просто полагаться на деление и позволить омеге рассуждать.

Lemma math_helper2 n : forall k, (forall q, n <> q * 3) ->  n + n <> k * 3.
Proof.
intros k kq A.
assert (k = 2 * (k / 2) + k mod 2) by (apply Nat.div_mod; omega).
assert (k mod 2 < 2) by (apply (Nat.mod_bound_pos k 2); omega).
apply (kq (k/2)); omega.
Qed.
6
Yves 5 Сен 2017 в 10:29

Как это часто бывает, ответ ssreflect однострочный:

From mathcomp Require Import ssreflect ssrbool ssrnat div.

Lemma math_helper n : 3 %| n.*2 -> 3 %| n.
Proof. by rewrite -muln2 Gauss_dvdl. Qed.

Хорошо, я немного обманул, потому что я изменил формулировку теоремы. Вот доказательство того, что вы на самом деле просили.

Lemma math_helper n k : (forall q, n <> q * 3) -> n + n <> k * 3.
Proof.
rewrite addnn -mul2n mulnC => h1 h2.
suff/dvdnP [q /h1]: 3 %| n by [].
by rewrite -(@Gauss_dvdl _ _ 2) //; apply/dvdnP; eauto.
Qed.
6
Arthur Azevedo De Amorim 5 Сен 2017 в 06:57

Это также может быть решено в ванильном Coq с использованием леммы Гаусса из стандартной библиотеки (поэтому следующее - просто переформулировка того, что Артур уже показал):

Require Import Coq.Numbers.Natural.Peano.NPeano.

Lemma math_helper n k : (forall q, n <> q * 3) -> n + n <> k * 3.
Proof.
  fold (Nat.double n); rewrite Nat.double_twice, (Nat.mul_comm k 3); intros H1 H2.
  assert (3 | 2 * n) as H3 by (rewrite H2; apply Nat.divide_factor_l).
  apply Nat.gauss in H3 as [x contra]; auto.
  apply (H1 _ contra).
Qed.
5
Anton Trunov 5 Сен 2017 в 09:11

Уточнение ответа Артура, которое мне нравится:

Lemma forall_negP T (P : T -> Prop) : (forall k, ~ P k) <-> ~ (exists k, P k).
Proof.
split; first by move=> H [w Hw]; apply: (H w).
by move=> H k Hk; apply: H; exists k.
Qed.

Lemma dvdnPN d m : (forall k, m <> k * d) <-> ~~ (d %| m).
Proof. by rewrite forall_negP; split=> /dvdnP. Qed.

Lemma math_helper n : (forall q, n <> q * 3) -> forall k, n + n <> k * 3.
Proof. by move/dvdnPN=> ?; apply/dvdnPN; rewrite addnn -muln2 Gauss_dvdl. Qed.

@AntonTrunov предлагает:

Lemma math_helper n : (forall q, n <> q * 3) -> forall k, n + n <> k * 3.
Proof. by rewrite !dvdnPN addnn -muln2 Gauss_dvdl. Qed.

Что довольно приятно!

В любом случае, как указал Артур, ФП следует полностью избавиться от леммы, проявляя большую осторожность в своих высказываниях.

2
ejgallego 5 Сен 2017 в 18:45

Вот ответ без ssreflect.

Вы можете заменить трехступенчатую индукцию на индукцию по курсу, используя well_founded_induction и lt_wf, затем вы можете сделать все числовые доказательства, используя омега. Тем не менее, вы все равно должны обращаться с универсально выраженными отрицаниями вручную.

Require Import Wellfounded Arith Omega.

Lemma math_helper n : forall k, (forall q, n <> q * 3) ->  n + n <> k * 3.
Proof.
induction n as [n' Ih] using (well_founded_ind lt_wf).
intros k pn' A; destruct (eq_nat_dec n' 0) as [n0 | nn0];[now intros; case (pn' 0); omega| ].
assert (cnd: n' - 3 < n') by omega.
apply (Ih _ cnd (k - 2));[intros q A'; apply (pn' (S q))|]; omega.
Qed.
3
Yves 5 Сен 2017 в 09:37