预测提取的Coq代码到Haskell的运行时间

时间:2019-04-22 15:01:31

标签: performance haskell coq

我有以下版本的isPrime用Coq编写(并证明)。

  • 30大约需要Compute (isPrime 330)秒 在我的机器上完成。
  • 提取的Haskell代码大约需要1秒才能验证9767是质数。

根据this post中的评论, 时间差异没有任何意义,但我想知道为什么吗? 提取Coq代码时还有其他方法可以预测性能吗?毕竟,有时候性能很重要,一旦努力证明它是正确的,就很难改变Coq的来源。 这是我的Coq代码:

(***********)
(* IMPORTS *)
(***********)
Require Import Coq.Arith.PeanoNat.

(************)
(* helper'' *)
(************)
Fixpoint helper' (p m n : nat) : bool :=
  match m with
  | 0 => false
  | 1 => false
  | S m' => (orb ((mult m n) =? p) (helper' p m' n))
  end.

(**********)
(* helper *)
(**********)
Fixpoint helper (p m : nat) : bool :=
  match m with
  | 0 => false
  | S m' => (orb ((mult m m) =? p) (orb (helper' p m' m) (helper p m')))
  end.

(***********)
(* isPrime *)
(***********)
Fixpoint isPrime (p : nat) : bool :=
  match p with
  | 0 => false
  | 1 => false
  | S p' => (negb (helper p p'))
  end.

(***********************)
(* Compute isPrime 330 *)
(***********************)
Compute (isPrime 330).

(********************************)
(* Extraction Language: Haskell *)
(********************************)
Extraction Language Haskell.

(***************************)
(* Use Haskell basic types *)
(***************************)
Require Import ExtrHaskellBasic.

(****************************************)
(* Use Haskell support for Nat handling *)
(****************************************)
Require Import ExtrHaskellNatNum.
Extract Inductive Datatypes.nat => "Prelude.Integer" ["0" "succ"]
"(\fO fS n -> if n Prelude.== 0 then fO () else fS (n Prelude.- 1))".

(***************************)
(* Extract to Haskell file *)
(***************************)
Extraction "/home/oren/GIT/CoqIt/FOLDER_2_PRESENTATION/FOLDER_2_EXAMPLES/EXAMPLE_03_PrintPrimes_Performance_Haskell.hs" isPrime.

1 个答案:

答案 0 :(得分:2)

您的Coq代码使用自然的Peano编码。对mult 2 2的评估实际上是通过归约进行的:

mult (S (S 0)) (S (S 0)))
= (S (S 0)) + mult (S 0) (S (S 0)))
= (S (S 0)) + ((S (S 0)) + mult 0 (S (S 0)))
= (S (S 0)) + ((S (S 0)) + 0)
= (S (S 0)) + ((S 0) + (S 0))
= (S (S 0)) + (0 + (S (S 0))
= (S (S 0)) + (S (S 0))
= (S 0) + (S (S (S 0)))
= 0 + (S (S (S (S 0)))
= (S (S (S (S 0))))

,然后检查是否相等mult 2 2 =? 5,进一步减少:

(S (S (S (S 0)))) =? (S (S (S (S (S 0)))))
(S (S (S 0))) =? (S (S (S (S 0))))
(S (S 0)) =? (S (S (S 0)))
(S 0) =? (S (S 0))
0 =? (S 0)
false

与此同时,在Haskell方面,2 * 2 == 5的求值方法是将两个Integers相乘并将它们与另一个Integer进行比较。这有点快。 ;)

在这里令人难以置信的是,Coq对isPrime 330的评估只需要30秒而不是30年。

我不知道如何预测提取代码的速度,只是说对Peano数字的原始运算将大大加速,而其他代码可能会适度地更快,这仅仅是因为许多工作已经完成使GHC生成快速代码,性能一直不是Coq开发的重点。