我试图使用Znumtheory库来证明一个数字是素数。
在Znum理论中,素数是根据相对素数来定义的:
Inductive prime (p:Z) : Prop :=
prime_intro :
1 < p -> (forall n:Z, 1 <= n < p -> rel_prime n p) -> prime p.
因此,要证明3是素数,我应该将prime_intro应用于目标。这是我的尝试:
Theorem prime3 : prime 3.
Proof.
apply prime_intro.
- omega.
- intros.
unfold rel_prime. apply Zis_gcd_intro.
+ apply Z.divide_1_l.
+ apply Z.divide_1_l.
+ intros. Abort.
我不知道如何使用假设H : 1 <= n < 3
,其中n
是1
或2
。我可以破坏它,应用lt_eq_cases
并再次破坏它,但在第一种情况下我会被一个无用的1 < n
困住。
我并不期待看起来那么简单的事情会很困难。
答案 0 :(得分:2)
您提到的引理实际上是在该库中以名称prime_3
证明的。您可以在GitHub上查找其证据。
你提到如此难以证明这么简单的事情是多么奇怪。实际上,标准库中的证明非常复杂。幸运的是,有更好的方法来计算出这个结果。 Mathematical Components库主张基于布尔属性的不同开发风格。在那里,prime
不是归纳定义的谓词,而是函数nat -> bool
,它检查其参数是否为素数。因此,我们可以通过计算证明这些简单的事实:
From mathcomp Require Import ssreflect ssrbool ssrnat prime.
Lemma prime_3 : prime 3. Proof. reflexivity. Qed.
这里有一点神奇之处:库声明了强制is_true : bool -> Prop
,只要在预期命题的地方使用布尔值,就会自动插入强制Definition is_true (b : bool) : Prop := b = true.
。它的定义如下:
prime_3
因此,prime 3 = true
真正证明的是Lemma primeP p :
reflect (p > 1 /\ forall d, d %| p -> xpred2 1 p d) (prime p).
,这使得这个简单的证明成为可能。
该库允许您通过反射引理将这个素数概念连接到一个更传统的素数:
prime p
解压缩符号和定义,此声明所说的是true
等于p > 1
当且仅当d
和p
除以1
时p
相等到v0.1.0
或v0.1.1
。我担心解释这个反射引理如何正常工作将是一个漫长的弯路,但如果你发现这很有趣,我强烈建议你更多地了解数学成分。
答案 1 :(得分:2)
我有@ larsr证明的变体。
Require Import ZArith.
Require Import Znumtheory.
Require Import Omega.
Theorem prime3 : prime 3.
Proof.
constructor.
- omega.
- intros.
assert (n = 1 \/ n = 2) as Ha by omega.
destruct Ha; subst n; apply Zgcd_is_gcd.
Qed.
与@ larsr的证明一样,我们使用1 < 3
证明omega
,然后再次使用n=1
证明n=2
或omega
。
要证明根据rel_prime 1 3
定义的rel_prime 2 3
和Zis_gcd
,我们会应用Zgcd_is_gcd
。这个引理表明计算gcd
就足够了。这对于(1,3)
和(2,3)
等具体输入来说是微不足道的。
编辑:我们可以仅使用Gallina来推广此结果。我们定义了一个布尔函数is_prime
,我们证明它是正确的w.r.t.归纳规范prime
。我想这可以用更优雅的方式完成,但我对与Z
相关的所有引理感到困惑。此外,一些定义是不透明的,不能用于(至少直接)定义可计算函数。
Require Import ZArith.
Require Import Znumtheory.
Require Import Omega.
Require Import Bool.
Require Import Recdef.
(** [for_all] checks that [f] is true for any integer between 1 and [n] *)
Function for_all (f:Z->bool) n {measure Z.to_nat n}:=
if n <=? 1 then true
else f (n-1) && for_all f (n-1).
Proof.
intros.
apply Z.leb_nle in teq.
apply Z2Nat.inj_lt. omega. omega. omega.
Defined.
Lemma for_all_spec : forall f n,
for_all f n = true -> forall k, 1 <= k < n -> f k = true.
Proof.
intros.
assert (0 <= n) by omega.
revert n H1 k H0 H.
apply (natlike_ind (fun n => forall k : Z, 1 <= k < n ->
for_all f n = true -> f k = true)); intros.
- omega.
- rewrite for_all_equation in H2.
destruct (Z.leb_spec0 (Z.succ x) 1).
+ omega.
+ replace (Z.succ x - 1) with x in H2 by omega. apply andb_true_iff in H2.
assert (k < x \/ k = x) by omega.
destruct H3.
* apply H0. omega. apply H2.
* subst k. apply H2.
Qed.
Definition is_prime (p:Z) :=
(1 <? p) && for_all (fun k => Z.gcd k p =? 1) p.
Theorem is_prime_correct : forall z, is_prime z = true -> prime z.
Proof.
intros. unfold is_prime in H.
apply andb_true_iff in H. destruct H as (H & H0).
constructor.
- apply Z.ltb_lt. assumption.
- intros.
apply for_all_spec with (k:=n) in H0; try assumption.
unfold rel_prime. apply Z.eqb_eq in H0. rewrite <- H0.
apply Zgcd_is_gcd.
Qed.
证据变得几乎和@Arthur的一样简单。
Theorem prime113 : prime 113.
Proof.
apply is_prime_correct; reflexivity.
Qed.
答案 2 :(得分:1)
这是一个证明我认为通过它逐步完成可以理解的证据。 它保持在数论的水平,并没有那么多的定义。我提出了一些评论,不知道它是否会使其更具可读性。但如果您关心它,请尝试在IDE中逐步完成...
Require Import ZArith.
Require Import Znumtheory.
Inductive prime (p:Z) : Prop :=
prime_intro :
1 < p -> (forall n:Z, 1 <= n < p -> rel_prime n p) -> prime p.
Require Import Omega.
Theorem prime3 : prime 3.
Proof.
constructor.
omega. (* prove 1 < 3 *)
intros; constructor. (* prove rel_prime n 3 *)
exists n. omega. (* prove (1 | n) *)
exists 3. omega. (* prove (1 | 3) *)
(* our goal is now (x | 1), and we know (x | n) and (x | 3) *)
assert (Hn: n=1 \/ n=2) by omega; clear H. (* because 1 <= n < 3 *)
case Hn. (* consider cases n=1 and n=2 *)
- intros; subst; trivial. (* case n = 1: proves (x | 1) because we know (x | n) *)
- intros; subst. (* case n = 2: we know (x | n) and (x | 3) *)
assert (Hgcd: (x | Z.gcd 2 3)) by (apply Z.gcd_greatest; trivial).
(* Z.gcd_greatest: (x | 2) -> x | 3) -> (x | Z.gcd 2 3) *)
apply Hgcd. (* prove (x | 1), because Z.gcd 2 3 = 1 *)
Qed.
答案 3 :(得分:1)
有趣的事实:@ epoiner的答案可以与Ltac一起用于任何素数的校对脚本。
Theorem prime113 : prime 113.
Proof.
constructor.
- omega.
- intros n H;
repeat match goal with | H : 1 <= ?n < ?a |- _ =>
assert (Hn: n = a -1 \/ 1 <= n < a - 1) by omega;
clear H; destruct Hn as [Hn | H];
[subst n; apply Zgcd_is_gcd | simpl in H; try omega ]
end.
Qed.
然而,证明术语变得笨拙,检查变得越来越慢。这就是为什么计算被移入类型检查的小规模反射(ssreflect)从长远来看可能是优选的。很难击败@Arthur Azevedo De Amorim的证据:
Proof. reflexivity. Qed.
:-)无论是计算时间还是内存方面。