Rel: 関係の性質


この短い(オプションの)章では、Coqでいくつかの基本的な定義と二項関係の定理の証明を行います。 重要な定義は実際に使う際(「プログラミング言語の基礎」のSmallstep章)に再度定義されます。 もしこれらに慣れているならばこの章を流し読みするか飛ばしても問題ありません。 しかし、Coqの基本的推論機構を使う良い練習問題ともなるので、IndProp章の直後に見ておくとよいかもしれません。

Set Warnings "-notation-overridden,-parsing".
From LF Require Export IndProp.

関係


集合X上の二項「関係」は、X2つをパラメータとする命題です。 つまり、集合Xの2つの要素に関する論理的主張です。

Definition relation (X: Type) := X -> X -> Prop.

まぎらわしいことに、Coqの標準ライブラリでは、一般的な用語「関係(relation)」を、この特定の場合を指すためだけに使っています。 ライブラリとの整合性を保つために、ここでもそれに従います。 したがって、Coq の識別子relationは常に、集合上の二項関係を指すために使います。 一方、日本語の「関係」は、Coq の relation を指す場合もあれば、 より一般の任意の数の(それぞれ別のものかもしれない)集合の間の関係を指す場合もあります。 どちらを指しているかは常に議論の文脈から明らかになるようにします。

nat上の関係の例は le で 、通常 n1 <= n2 の形で書かれる「以下」の関係です。

Print le.
====> Inductive le (n : nat) : nat -> Prop :=
             le_n : n <= n 
           | le_S : forall m : nat, n <= m -> n <= S m
Check le : nat -> nat -> Prop.
Check le : relation nat.
(Why did we write it this way instead of starting with Inductive le : relation nat...? Because we wanted to put the first nat to the left of the :, which makes Coq generate a somewhat nicer induction principle for reasoning about <=.)

基本性質


大学の離散数学の講義で習っているように、関係を「一般的に」議論し記述する方法がいくつもあります。 関係を分類する方法(反射的か、推移的か、など)、関係のクラスについて一般的に証明できる定理、 関係からの別の関係の構成、などです。例えば...

部分関数


集合X上の関係Rは、すべてのxに対して、R x yとなるyは高々1つであるとき、言い換えると、R x y1かつR x y2ならば y1 = y2 となるとき、「部分関数(partial function)」です。

Definition partial_function {X: Type} (R: relation X) :=
  forall x y1 y2 : X, R x y1 -> R x y2 -> y1 = y2.

例えば、前に定義したnext_nat関係は部分関数です。

Print next_nat.
Check next_nat : relation nat.

Theorem next_nat_partial_function :
   partial_function next_nat.
Proof.
  unfold partial_function.
  intros x y1 y2 H1 H2.
  inversion H1. inversion H2.
  reflexivity. Qed.

しかし、数値上の<=関係は部分関数ではありません。 ( <=が部分関数であると仮定すると、0<=0かつ0<=1から、0=1となります。 これはおかしなことです。 したがって、<=が部分関数だという仮定は矛盾するということになります。)

Theorem le_not_a_partial_function :
  ~ (partial_function le).
Proof.
  unfold not. unfold partial_function. intros Hc.
  assert (0 = 1) as Nonsense. {
    apply Hc with (x := 0).
    - apply le_n.
    - apply le_S. apply le_n. }
  discriminate Nonsense. Qed.

練習問題:★★, optional (total_relation_not_partial)

IndProp章(の課題)で定義した total_relation が部分関数ではないことを示しなさい。


練習問題:★★, optional (empty_relation_partial)

IndProp章(の課題)で定義した empty_relation が部分関数であることを示しなさい。


反射的(Reflexive)関係


集合X上の「反射的(reflexive)」関係とは、Xのすべての要素について、自身との関係が成立する関係です。

Definition reflexive {X: Type} (R: relation X) :=
  forall a : X, R a a.

Theorem le_reflexive :
  reflexive le.
Proof.
  unfold reflexive. intros n. apply le_n. Qed.

推移的(Transitive)関係


関係Rが「推移的(transitive)」であるとは、R a bかつR b cならば常にR a cとなることです。

Definition transitive {X: Type} (R: relation X) :=
  forall a b c : X, (R a b) -> (R b c) -> (R a c).

Theorem le_trans :
  transitive le.
Proof.
  intros n m o Hnm Hmo.
  induction Hmo.
  - apply Hnm.
  - apply le_S. apply IHHmo. Qed.

Theorem lt_trans:
  transitive lt.
Proof.
  unfold lt. unfold transitive.
  intros n m o Hnm Hmo.
  apply le_S in Hnm.
  apply le_trans with (a := (S n)) (b := (S m)) (c := o).
  apply Hnm.
  apply Hmo. Qed.

練習問題:★★, standard, optional (le_trans_hard_way)

lt_trans は、帰納法を使って手間をかければ、le_trans を使わずに証明することができます。 これをやってみなさい。

Theorem lt_trans' :
  transitive lt.
Proof.
  unfold lt. unfold transitive.
  intros n m o Hnm Hmo.
  induction Hmo as [| m' Hm'o].
Admitted.

練習問題:★★, standard, optional (lt_trans'')

同じことを、oについての帰納法で証明しなさい。

Theorem lt_trans'' :
  transitive lt.
Proof.
  unfold lt. unfold transitive.
  intros n m o Hnm Hmo.
  induction o as [| o'].
Admitted.

leの推移性は、同様に、後に(つまり以下の反対称性の証明において) 有用な事実を証明するのに使うことができます...

Theorem le_Sn_le : forall n m, S n <= m -> n <= m.
Proof.
  intros n m H. apply le_trans with (S n).
  - apply le_S. apply le_n.
  - apply H.
Qed.

練習問題:★, standard, optional (le_S_n)

Theorem le_S_n : forall n m,
  (S n <= S m) -> (n <= m).
Proof.
Admitted.

練習問題:★★, optional (le_Sn_n_inf)

以下の定理の非形式的な証明を示しなさい。
定理: すべてのnについて、~(S n <= n)
形式的な証明はこの次のoptionalな練習問題ですが、 ここでは、形式的な証明を行わずに、まず非形式的な証明を示しなさい。
証明:

練習問題:★, standard, optional (le_Sn_n)

Theorem le_Sn_n : forall n,
  ~ (S n <= n).
Proof.
Admitted.

反射性と推移性は後の章で必要となる主要概念ですが、Coq で関係を扱う練習をもう少ししましょう。 次のいくつかの概念もよく知られたものです。

対称的(Symmetric)関係と反対称的(Antisymmetric)関係


関係Rが「対称的(symmetric)」であるとは、R a bならばR b aとなることです。

Definition symmetric {X: Type} (R: relation X) :=
  forall a b : X, (R a b) -> (R b a).

練習問題:★★, standard, optional (le_not_symmetric)

Theorem le_not_symmetric :
  ~ (symmetric le).
Proof.
Admitted.

関係Rが「反対称的(antisymmetric)」であるとは、R a bかつR b aならば a = b となることです。 つまり、Rにおける「閉路(cycle)」は自明なものしかないということです。

Definition antisymmetric {X: Type} (R: relation X) :=
  forall a b : X, (R a b) -> (R b a) -> a = b.

練習問題:★★, standard, optional (le_antisymmetric)

Theorem le_antisymmetric :
  antisymmetric le.
Proof.
Admitted.

練習問題:★★, standard, optional (le_step)

Theorem le_step : forall n m p,
  n < m ->
  m <= S p ->
  n <= p.
Proof.
Admitted.

同値(Equivalence)関係


関係が「同値(equivalence)」であるとは、その関係が、反射的、対称的、かつ推移的であることです。

Definition equivalence {X:Type} (R: relation X) :=
  (reflexive R) /\ (symmetric R) /\ (transitive R).

半順序(Partial Order)と前順序(Preorder)


関係が「半順序(partial order)」であるとは、その関係が、反射的、「反」対称的、かつ推移的であることです。 Coq 標準ライブラリでは、半順序のことを単に「順序(order)」と呼びます。

Definition order {X:Type} (R: relation X) :=
  (reflexive R) /\ (antisymmetric R) /\ (transitive R).

前順序(preorder、または擬順序)とは、半順序の条件から反対称性を除いたものです。

Definition preorder {X:Type} (R: relation X) :=
  (reflexive R) /\ (transitive R).

Theorem le_order :
  order le.
Proof.
  unfold order. split.
    - apply le_reflexive.
    - split.
      + apply le_antisymmetric.
      + apply le_trans. Qed.

反射推移閉包


関係Rの反射推移閉包とは、Rを含み反射性と推移性の両者を満たす最小の関係のことです。 形式的には、Coq標準ライブラリのRelationモジュールで、以下のように定義されます。

Inductive clos_refl_trans {A: Type} (R: relation A) : relation A :=
    | rt_step x y (H : R x y) : clos_refl_trans R x y
    | rt_refl x : clos_refl_trans R x x
    | rt_trans x y z
          (Hxy : clos_refl_trans R x y)
          (Hyz : clos_refl_trans R y z) :
          clos_refl_trans R x z.

例えば、next_nat関係の反射推移閉包はle関係と同値になります。

Theorem next_nat_closure_is_le : forall n m,
  (n <= m) <-> ((clos_refl_trans next_nat) n m).
Proof.
  intros n m. split.
  -
    intro H. induction H.
    + apply rt_refl.
    +
      apply rt_trans with m. apply IHle. apply rt_step.
      apply nn.
  -
    intro H. induction H.
    + inversion H. apply le_S. apply le_n.
    + apply le_n.
    +
      apply le_trans with y.
      apply IHclos_refl_trans1.
      apply IHclos_refl_trans2. Qed.

上の反射推移閉包の定義は自然です。 定義はRの反射推移閉包がRを含み反射律と推移律について閉じている最小の関係であることを明示的に述べています。 しかし、この定義は、証明をする際にはあまり便利ではありません。 rt_trans 規則の「非決定性(nondeterminism)」によって、しばしばわかりにくい帰納法になってしまいます。 以下は、より使いやすい定義です。

Inductive clos_refl_trans_1n {A : Type}
                             (R : relation A) (x : A)
                             : A -> Prop :=
  | rt1n_refl : clos_refl_trans_1n R x x
  | rt1n_trans (y z : A)
      (Hxy : R x y) (Hrest : clos_refl_trans_1n R y z) :
      clos_refl_trans_1n R x z.

新しい反射推移閉包の定義は、rt_step規則とrt_trans規則を「まとめ」て、 1ステップの規則にします。 このステップの左側はRを1回だけ使います。このことが帰納法をはるかに簡単なものにします。
次に進む前に、二つの定義が同じものを定義していることを確認しなければなりません。
最初に、clos_refl_trans_1nが、「失われた」2つのclos_refl_transコンストラクタの働きを代替することを示す二つの補題を証明します。

Lemma rsc_R : forall (X:Type) (R:relation X) (x y : X),
       R x y -> clos_refl_trans_1n R x y.
Proof.
  intros X R x y H.
  apply rt1n_trans with y. apply H. apply rt1n_refl. Qed.

練習問題:★★, standard, optional(rsc_trans)

Lemma rsc_trans :
  forall (X:Type) (R: relation X) (x y z : X),
      clos_refl_trans_1n R x y ->
      clos_refl_trans_1n R y z ->
      clos_refl_trans_1n R x z.
Proof.
Admitted.

そして、反射推移閉包の2つの定義が同じ関係を定義していることを証明するために、 上記の事実を使います。

練習問題:★★★, standard, optional (rtc_rsc_coincide)

Theorem rtc_rsc_coincide :
         forall (X:Type) (R: relation X) (x y : X),
  clos_refl_trans R x y <-> clos_refl_trans_1n R x y.
Proof.
Admitted.