フィボナッチ数の最大公約数

フィボナッチ数の最大公約数 (GCD of Fibonacci Numbers)
============================

@suharahiromichi

2022/01/21

2022/01/29 GCDの帰納法について修正した。

このソースは、以下にあります。
https://github.com/suharahiromichi/coq/blob/master/math/ssr_fib_3.v


# はじめに
m番めとn番めフィボナッチ数の最大公約数は、mとnの最大公約数番めのフィボナッチ数に等しい、という定理があります。

```math
gcd(F_m, F_n) = F_{gcd(m, n)}

```
これは エドゥアール・リュカ (ルーカス）が最初に報告したのをクヌース先生が紹介して広まったのだそうです。TAOCP[2]に掲載されているようですが、私が読んだのは [1]と[1'] のほうで、証明は演習問題(6.27)になっています。
そこで、早速答えをみると、フィボナッチ数の加法定理に相当する式から、「$ m > n $ ならば、$ gcd(F_m, F_n) = gcd(F_{m - n}, F_n) $であることに注意して、帰納法使って証明せよ」、とだけ書いてあります。
証明を集めたサイト[3]を見ても書いてあることは同じで、[4]はもう少し詳しいですが、帰納法のところは証明というより説明になっています。
では、この定理の証明をCoqでやってみましょう、とりあえず、以下の方針でおこないます。

1. gcdに関する帰納法が肝なので、そこは Coq の Functional Induction [5] に任せる。

2. 1.のためには、Function コマンドで自分でフィボナッチ数を定義する必要がある。それも [5] を参考にした。

3. MathComp の GCDに関する豊富な補題を使うために、2.の定義とMathCompのGCDの定義が同じであることを証明しておく。


MathCompで証明をするならば、MathCompで定義されている自然数の最大公約数の関数 gcdn について、なんらかのかたちで帰納法の原理を用意するのが正しいアプローチですが、それは [7] を参照してください。
また、フィボナッチ数の加法定理については、[6] で証明しているため、証明は省略します。



```coq:

From mathcomp Require Import all_ssreflect.
Require Import FunInd.                      (* Functional Scheme *)
Require Import Recdef.                      (* Function *)
Require Import Wf_nat.                      (* wf *)

Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
(* Set Print All. *)

Section Fib3.


```

# フィボナッチ数の定義と定理


```coq:

  Function fib (n : nat) : nat :=
    match n with
    | 0 => 0
    | 1 => 1
    | (m.+1 as pn).+1 => fib m + fib pn (* fib n.-2 + fib n.-1 *)
    end.


```

1個分のフィボナッチ数の計算


```coq:

  Lemma fib_n n : fib n.+2 = fib n + fib n.+1.
  Proof.
    done.
  Qed.


```
隣り合ったフィボナッチ数は互いに素である。


```coq:

  Lemma fib_coprime (n : nat) : coprime (fib n) (fib n.+1).
  Proof.
    rewrite /coprime.
    elim: n => [//= | n IHn].
    rewrite fib_n.
      by rewrite gcdnDr gcdnC.
  Qed.


```
フィボナッチ数列の加法定理


```coq:

  Lemma fib_addition n m :
    1 <= m -> fib (n + m) = fib m * fib n.+1 + fib m.-1 * fib n.
  Proof.
    (* see. ssr_fib_2.v *)
  Admitted.                                 (* OK *)


```

# GCDの定義と定理
Function を使って定義します。


```coq:

  Function gcd (m n : nat) {wf lt m} : nat :=
    match m with
    | 0 => n
    | _ => gcd (n %% m) m
    end.
  Proof.
    - move=> m n m0 _.
      apply/ltP.
        by rewrite ltn_mod.
    - by apply: lt_wf.
  Qed.


```
MathComp の gcdn を同じであることを証明する。


```coq:

  Lemma gcdE m n : gcdn m n = gcd m n.
  Proof.
    functional induction (gcd m n).
    - by rewrite gcd0n.
    - rewrite -IHn0.
        by rewrite gcdnC gcdn_modl.
  Qed.


```
GCDの可換性


```coq:

  Check gcdnC : forall m n, gcdn m n = gcdn n m.
  Lemma gcdC m n : gcd m n = gcd n m.
  Proof.
      by rewrite -2!gcdE gcdnC.
  Qed.


```
GCDの簡単な性質


```coq:

  Lemma gcd0m m : gcd 0 m = m.
  Proof.
      by rewrite gcd_equation.            (* gcd の定義で展開する。 *)
  Qed.

  Lemma gcdmm m : gcd m m = m.
  Proof.
    case: m => [| m].
    - by rewrite gcd_equation.
    - by rewrite gcd_equation modnn gcd0m.
  Qed.

  Lemma gcdnn_gcd0n n : gcd n n = gcd 0 n.
  Proof.
      by rewrite gcdmm gcd0m.
  Qed.

  Check gcdnMDl : forall k m n : nat, gcdn m (k * m + n) = gcdn m n.
  Lemma gcdMDl (k m n : nat) : gcd m (k * m + n) = gcd m n.
  Proof.
      by rewrite -2!gcdE gcdnMDl.
  Qed.

  Check Gauss_gcdl : forall p m n : nat, coprime p n -> gcdn p (m * n) = gcdn p m.
  Lemma Gauss_gcdl' p m n : coprime p n -> gcd p (m * n) = gcd p m.
  Proof.
    rewrite -2!gcdE.
      by apply: Gauss_gcdl.
  Qed.


```

# フィボナッチ数のGCD

GKPの解答にある、``m > n`` ならば ``gcd (fib m) (fib n) = gcd (fib (m - n)) (fib n)``と同じものを証明するが、そのために ``m`` を ``0`` と非0で振り分ける。


```coq:

  Lemma fib_lemma_gkp' m n :
    1 <= m -> gcd (fib (n + m)) (fib n) = gcd (fib m) (fib n).
  Proof.
    move=> H.
    rewrite fib_addition //.
    rewrite gcdC addnC gcdMDl.
    rewrite Gauss_gcdl'.
    - by rewrite gcdC.
    - by apply: fib_coprime.
  Qed.

  Lemma fib_lemma_gkp m n :
    gcd (fib (n + m)) (fib n) = gcd (fib m) (fib n).
  Proof.
    case: m => [| m].
    - rewrite addn0 /=.
        by apply: gcdnn_gcd0n.
    - rewrite fib_lemma_gkp' //=.
  Qed.


```
gcdnMDl のフィボナッチ数版


```coq:

  Check gcdnMDl : forall k m n : nat, gcdn m (k * m + n) = gcdn m n.
  Lemma fib_gcdMDl n q r :
    gcd (fib (q * n + r)) (fib n) = gcd (fib n) (fib r).
  Proof.
    elim: q => [| q IHq].
    - rewrite mul0n add0n.
      rewrite gcdC.
      done.
    - Search _ (_.+1 * _).
      rewrite mulSn -addnA.
      rewrite [LHS]fib_lemma_gkp.
      done.
  Qed.


```
gcdn_modr のフィボナッチ数版


```coq:

  Check gcdn_modr : forall m n : nat, gcdn m (n %% m) = gcdn m n.
  Lemma fin_gcd_modr m n :
    gcd (fib m) (fib n) = gcd (fib n) (fib (m %% n)).
  Proof.
    move: (fib_gcdMDl n (m %/ n) (m %% n)).
    rewrite -divn_eq.
    done.
  Qed.


```

# 証明したいもの
$ F_0 = 0 $ や $ F_1 = 1 $ でも成り立つことを確認しておく。


```coq:

  Compute gcdn 0 0.                         (* 0 *)
  Compute gcdn 1 0.                         (* 1 *)
  Compute gcdn 0 1.                         (* 1 *)
  Compute gcdn 1 1.                         (* 1 *)

  Goal gcd (fib 1) (fib 0) = fib (gcd 1 0).
  Proof.
    rewrite gcd_equation //=.
      by rewrite gcd_equation.
  Qed.


```
functional induction を使って証明します。


```coq:

  Theorem gcd_fib__fib_gcd (m n : nat) : gcd (fib m) (fib n) = fib (gcd m n).
  Proof.
    rewrite gcdC.
    functional induction (gcd m n).
    - rewrite gcdC.
      rewrite gcd_equation.
      done.
    (* 
  IHn0 : gcd (fib m) (fib (n %% m)) = fib (gcd (n %% m) m)
  ============================
  gcd (fib n) (fib m) = fib (gcd (n %% m) m)
     *)
    - rewrite fin_gcd_modr.
      done.
  Qed.

End Fib3.

Section Fib3_2.

```

# おまけ
Coq Tokyo 終了後に教えてもらった GCD の帰納法


```coq:

  Lemma my_gcdn_ind (P : nat -> nat -> nat -> Prop) :
    (forall n, P 0 n n) ->
    (forall m n, P (n %% m) m (gcdn (n %% m) m) -> P m n (gcdn m n)) ->
    forall m n, P m n (gcdn m n).
  Proof.
    move => H0 Hmod.
    elim/ltn_ind => [[| m ]] // H n.
    - have -> : gcdn 0 n = n by elim: n.
      done.
    - apply : Hmod.
      exact : H (ltn_mod _ _) _.
  Qed.


```
これを使うと functional induction を使わずに証明できます。
[7] を参照してください。


```coq:

End Fib3_2.


```

# 文献
[1] Graham, Knuth, Patashnik "Concrete Mathematics", Second Edition

[1'] 有澤、安村、萩野、石畑訳、「コンピュータの数学」共立出版

[2] D.E.Knuth, "The Art of Computer Programming: Vol.1: Fundamental Algorithms (3rd ed.) "

[3] "GCD of Fibonacci Numbers"、https://proofwiki.org/wiki/GCD_of_Fibonacci_Numbers

[4] ぱるち、「フィボナッチ数列で互除法っぽいこと」、https://mathlog.info/articles/278

[5] 名古屋大学 2021年度秋・数理解析・計算機数学 IV (同 概論IV) "Mathcomp, 自己反映と数論の証明"、https://www.math.nagoya-u.ac.jp/~garrigue/lecture/2021_AW/ssrcoq5.pdf

[6] https://github.com/suharahiromichi/coq/blob/master/math/ssr_fib_2.v

[7] https://github.com/suharahiromichi/coq/blob/master/math/ssr_fib_3_2.v


```