关于模数的Coq归纳

时间:2015-03-21 23:03:09

标签: modulo coq induction

我是coq的新手,我真的很难应用感应。只要我可以使用来自图书馆的定理,或者像omega这样的策略,这一切都是"不是问题"。但是一旦这些不起作用,我就会卡住。

确切地说,现在我试图证明

Lemma mod_diff : forall n m : nat, n>=m /\ m <> 0 -> (n - m) mod m = n mod m.

案例n = 0我已经有了。

Proof.
    intros. destruct H as [H1 H2 ]. induction n.
      rewrite Nat.mod_0_l by omega. rewrite Nat.mod_0_l; omega.

但如何进行诱导步骤?

1 subgoal
n : nat
m : nat
H1 : S n >= m
H2 : m <> 0
IHn : n >= m -> (n - m) mod m = n mod m
______________________________________(1/1)
(S n - m) mod m = S n mod m

3 个答案:

答案 0 :(得分:5)

证明不需要归纳,Coq库中有足够的引理可以使用。为了找到这些引理,我使用了SeachAbout moduloSearchAbout plus

然后,我做了:

Lemma mod_add_back: forall n m : nat, m <> 0 -> ((n + m) mod m) = (n mod m).
intros.
rewrite Nat.add_mod.
rewrite Nat.mod_same.
rewrite plus_0_r.
rewrite Nat.mod_mod.
reflexivity.
assumption.
assumption.
assumption.
Qed.

Lemma mod_diff: forall n m : nat, n >= m /\ m <> 0 -> (n - m) mod m = n mod m.
intros.
intuition.
rewrite <- mod_add_back.
assert ((n - m + m) = n) by omega.
rewrite H.
reflexivity.
intuition.
Qed.

请注意使用assert ... by omega来证明重写的实例似乎不是可用的内置引理。这有点棘手,因为使用nat它一般不起作用,但仅限于n >= m。 (编辑:实际上内置的引理Nat.sub_add会工作)。

因此,证明中的想法是首先证明一个允许你“添加”的引理。 m,因为这似乎是一个好主意,有一个单独的引理。但是,我想它也可以作为单一的证明来完成。

实际上,n上的归纳根本没有推进证明,因为没有办法显示归纳假设的前提条件(不能从n >= m推导S n >= m)。虽然归纳是一个重要的构建块,但它并不总是正确的工具。

答案 1 :(得分:4)

正如@Atsby说的那样,库中已经有了有用的引理,所以你可以做一下

Require Import NPeano.
Require Import Omega.

Lemma mod_diff : forall n m : nat, n>=m /\ m <> 0 -> (n - m) mod m = n mod m.
  intros n m [H1 H2].
  rewrite <- (Nat.mod_add _ 1); try rewrite mult_1_l, Nat.sub_add; auto.
Qed.

关于如何通过归纳进行的问题,我的一般建议是获得尽可能一般的归纳假设,即在进行induction之前不要引入量化变量。而且,尝试获得一个归纳假设,这个假设也适用于下一个&#34;值。因此,我会尝试证明另一个公式(n + k * m) mod m = n mod m并对k进行归纳,因为只需要代数重写来证明k+1来自k的情况。但是,在这种情况下,那个&#39;其他公式&#39;已经在图书馆,名为Nat.sub_add

答案 2 :(得分:2)

你应该使用不同的归纳原理。

mod函数遵循以下关系。

Inductive mod_rel : nat -> nat -> nat -> Prop :=
  | mod_rel_1 : forall n1 n2, n2 = 0 -> mod_rel n1 n2 0
  | mod_rel_2 : forall n1 n2, n2 > 0 -> n1 < n2 -> mod_rel n1 n2 n1
  | mod_rel_3 : forall n1 n2 n3, n2 > 0 -> n1 >= n2 -> mod_rel (n1 - n2) n2 n3 -> mod_rel n1 n2 n3.

在标准数学中,通常假设模数为零是未定义的。 事实是所有涉及模数的定理都有一个前提条件,即第二个参数不是零,因此,无论是否定义模数为零都无关紧要。

以下是mod功能的域名。

Inductive mod_dom : nat -> nat -> Prop :=
  | mod_dom_1 : forall n1 n2, n2 = 0 -> mod_dom n1 n2
  | mod_dom_2 : forall n1 n2, n2 > 0 -> n1 < n2 -> mod_dom n1 n2
  | mod_dom_3 : forall n1 n2, n2 > 0 -> n1 >= n2 -> mod_dom (n1 - n2) n2 -> mod_dom n1 n2.

在Coq中只有全部函数,因此任何一对自然数都在mod的域中。 这可以通过有根据的归纳和案例分析来证明。

Conjecture wf_ind : forall P1, (forall n1, (forall n2, n2 < n1 -> P1 n2) -> P1 n1) -> forall n1, P1 n1.
Conjecture O_gt : forall n1, n1 = 0 \/ n1 > 0.
Conjecture lt_ge : forall n1 n2, n1 < n2 \/ n1 >= n2.

Conjecture mod_total : forall n1 n2, mod_dom n1 n2.

mod域相关的归纳原则是

Check mod_dom_ind : forall P1 : nat -> nat -> Prop,
  (forall n1 n2, n2 = 0 -> P1 n1 n2) ->
  (forall n1 n2, n2 > 0 -> n1 < n2 -> P1 n1 n2) ->
  (forall n1 n2, n2 > 0 -> n1 >= n2 -> mod_dom (n1 - n2) n2 -> P1 (n1 - n2) n2 -> P1 n1 n2) ->
  forall n1 n2, mod_dom n1 n2 -> P1 n1 n2.

但由于mod是完全的,因此可以将其简化为

Conjecture mod_ind : forall P1 : nat -> nat -> Prop,
  (forall n1 n2, n2 = 0 -> P1 n1 n2) ->
  (forall n1 n2, n2 > 0 -> n1 < n2 -> P1 n1 n2) ->
  (forall n1 n2, n2 > 0 -> n1 >= n2 -> P1 (n1 - n2) n2 -> P1 n1 n2) ->
  forall n1 n2, P1 n1 n2.

这种归纳原理适用于任何一对自然数。 它更适合证明有关mod的事实,因为它遵循mod定义的结构。 mod无法使用结构递归直接定义,因此结构归纳只会在证明有关mod的内容时为您提供。

不是每个证据都应该通过归纳来解决。 你需要问问自己为什么你认为某些事情是真实的,并将其转化为严格的证据。 如果你不确定为什么它是真的,你需要学习或发现它为什么或不是。

但是除法和模数可以通过结构递归间接定义。 在以下函数中,n3n4用作中间商和余数。你通过递减被除数并递增余数直到余数达到除数来定义它,此时你递增商并重置余数并继续。当被除数达到零时,你有真正的商和余数(假设你没有除以零)。

Conjecture ltb : nat -> nat -> bool.

Fixpoint div_mod (n1 n2 n3 n4 : nat) : nat * nat :=
  match n1 with
  | 0 => (n3, n4)
  | S n1 => if ltb (S n4) n2
    then div_mod n1 n2 n3 (S n4)
    else div_mod n1 n2 (S n3) 0
  end.

Definition div (n1 n2 : nat) : nat := fst (div_mod n1 n2 0 0).

Definition mod (n1 n2 : nat) : nat := snd (div_mod n1 n2 0 0).

您仍然没有使用结构归纳来证明divmod的内容。你用它来证明关于div_mod的事情。 这些函数对应于以下(结构感应)定理。

Theorem augmented_division_algorithm : forall n1 n2 n3 n4, n4 < n2 ->
  exists n5 n6, n1 + n3 * n2 + n4 = n5 * n2 + n6 /\ n6 < n2.
Proof.
induction n1.
firstorder.
exists n3.
exists n4.
firstorder.
firstorder.
destruct (lt_ge (S n4) n2).
specialize (IHn1 n2 n3 (S n4) H0).
firstorder.
exists x.
exists x0.
firstorder.
admit. (* H1 implies the conclusion. *)
Conjecture C2 : forall n1 n2, n1 < n2 -> 0 < n2.
pose proof (C2 _ _ H).
specialize (IHn1 n2 (S n3) 0).
firstorder.
exists x.
exists x0.
firstorder.
Conjecture C3 : forall n1 n2, n1 < n2 -> S n1 >= n2 -> S n1 = n2.
pose proof (C3 _ _ H H0).
subst.
cbn in *.
admit. (* H2 implies the conclusion. *)
Qed.

通过将n3n4设置为零,可以得出通常的除法算法。

Conjecture division_algorithm : forall n1 n2, 0 < n2 -> exists n5 n6,
  n1 = n5 * n2 + n6 /\ n6 < n2.

免责声明:猜想和简单类型的函数。