2017-10-25 9 views
1
における機能の終了

証明します。資料はthisの5ページ目です。この関数は、正規表現(Isabelle/HOLで形式化されています)の正規化関数の一部として実行されます。 le_regex関数は同じ論文から適合されています。私は決定的な合計順序でregexのパラメータ化を避けるためにasciiを使用しています(プログラムを抽出したい)。は、私はトラブル次の関数の終了を証明を持っていますCoqの

Inductive regex : Set := 
    | Empty : regex 
    | Epsilon : regex 
    | Symbol : ascii -> regex 
    | Union : regex -> regex -> regex 
    | Concat : regex -> regex -> regex 
    | Star : regex -> regex. 

Lemma eq_regex_dec : forall u v : regex, {u = v} + {u <> v}. 
Proof. decide equality; apply ascii_dec. Defined. 

Fixpoint le_regex u v : bool := 
    match u, v with 
    | Empty  , _   => true 
    | _   , Empty  => false 
    | Epsilon  , _   => true 
    | _   , Epsilon  => false 
    | Symbol a , Symbol b  => nat_of_ascii a <=? nat_of_ascii b 
    | Symbol _ , _   => true 
    | _   , Symbol _  => false 
    | Star u  , Star v  => le_regex u v 
    | Star u  , _   => true 
    | _   , Star v  => false 
    | Union u1 u2 , Union v1 v2 => if eq_regex_dec u1 v1 
            then le_regex u2 v2 
            else le_regex u1 v1 
    | Union _ _ , _   => true 
    | _   , Union _ _ => false 
    | Concat u1 u2, Concat v1 v2 => if eq_regex_dec u1 v1 
            then le_regex u2 v2 
            else le_regex u1 v1 
    end. 

私は正しいアプローチは減少メジャーを定義し、終了を証明するためにProgram Fixpointを使用することだと思います。しかし、私は正しい対策(オペレータの数に基づく試行が失敗した)を考え出すのに問題があります。私は仕事を別々の機能に分解しようとしましたが、同様の問題に遭遇しました。どんな援助も感謝されるでしょう、または正しい方向を指すヒント。私はあなたがタイプregexに値を返すべきではないことを示唆している

Union u v, w   => norm_union u (norm_union v w) (* line 5 *) 

:あなたは次の行では、ネストされた再帰呼び出しを持っているので、

+2

正規表現の定義を質問の一部としてCoq構文で追加してください。 – Yves

答えて

3

あなたのコードは、通常の測定機能で扱われているものよりも複雑ですsizeおよびcombined_sizeの適切な概念についてはタイプ{r : regex | size r < combined_size u v}である。

あなたの問題を数時間調査した後、再帰は引数の字句順に依存していることが分かります。 norm_union v wUnion v wを返すことがありますので、引数の(u, Union v w)(Union u v, w)より小さい必要があります。 実際にメジャーを使用する場合は、左側のウェイトを右側のウェイトより大きくする必要があり、Unionのメジャーのメジャーは、全体の尺度。

字句順の性質のため、私は尺度を使わないことを選択しました。また、私はProgram Fixpointも十分に分かっていないので、別のツールを使って問題を解決しました。私が思いついた解決策はhere on githubで見ることができます。少なくともこれは証明が必要なすべての減少条件を示しています。

+0

お返事ありがとうございます。私は対策を使うときには難しい目標に遭遇し、入れ子にされた再帰のために 'Program Fixpoint'が発生しました。私はあなたが記述する方法で機能を定義することができますが、私は少し不明です*どのように*私はそれを使用します。メジャーを定義するための命題( 'size r

2

作業の余分な日の後、私は今この質問に対するより完全な答えを持っています。それはまだthis linkに見えます。この解決策にはいくつかのコメントが必要です。

まず、Fixという名前の関数コンストラクタを使用しています(長い名前はCoq.Init.Wf.Fixです。これは、よく定義された再帰によって関数を定義するために使用できる上位関数です)。順序はorderと呼ばれている。まあは2000年代初頭に集中的に研究し、彼らはProgram Fixpointコマンドの基礎で残っているし、受注を設立しました。

第二に、あなたが行うケースを書いたコードが同時にタイプregexの2つの値を分析するので、この36ケースにつながります(最初のケースがEmptyである場合、2番目の引数についてケース分析がないため、多少なりともあります).36ケースはyには表示されませんなぜなら、いくつかのコンストラクタは、パターンが単なる変数である同じルールでカバーされているからです。このようなケースの倍数化を避けるために、私はケース分析を に対して具体的な誘導型を考案しました。私はこの特定のタイプarTと呼んだ。次に、タイプregexの任意の要素をarTの対応する要素にマップする関数arを定義します。タイプarTには6個ではなく3個のコンストラクターがあるため、パターンマッキング式のコード数は大幅に少なくなり、プルーフはあまり冗長になりません。

次に、Fixを使用してnorm_unionを定義しました。 Coq(そしてIsabelleを含むほとんどの定理証明者)の通常のように、 の言語は再帰関数が常に終了するようにします。この場合、再帰呼び出しは、関数の入力よりも小さいより小さい引数の場合にのみ発生します。この場合、これは、再帰関数の本体を、最初の引数として第1引数として、第2引数として再帰呼び出しを表すために使用される関数をとる関数で記述することによって行われます。この関数の名前はnorm_union_Fで、次のようにそのタイプがある:このタイプの説明では

forall p : regex * regex, 
    forall g : (forall p', order p' p -> 
      {r : regex | size_regex r <= size_2regex p'}), 
    {r : regex | size_regex r <= size_2regex p} 

、再帰呼び出しを表すために使用される関数の名前はgであり、我々はgの種類は、それができることを課していることがわかりorderという名前の最初の引数pより小さいregexの語のペアでのみ使用できます。このタイプの説明では、再帰呼び出しの戻り型がregexではなく{r : regex | size_regex r <= size_2regex p'}ではないことを表現することも選択しました。これは、ネストされた再帰を処理する必要があるためです。再帰呼び出しの出力は、他の再帰呼び出しの入力として使用されます。 これは、この回答の主なトリックです。このコードで

Definition norm_union_F : forall p : regex * regex, 
    forall g : (forall p', order p' p -> 
       {r : regex | size_regex r <= size_2regex p'}), 
    {r : regex | size_regex r <= size_2regex p} := 
fun p norm_union => 
    match ar (fst p) with 
    arE _ eq1 => exist _ (snd p) (th1 p) 
    | arU _ u v eq1 => 
    match ar (snd p) with 
     arE _ eq2 => exist _ (Union u v) (th2' _ _ _ eq1) 
    | _ => exist _ (proj1_sig 
      (norm_union (u, 
       proj1_sig (norm_union (v, snd p) 
       (th3' _ _ _ eq1))) 
       (th4' _ _ _ eq1 (th3' _ _ _ eq1) 
        (proj1_sig (norm_union (v, snd p) (th3' _ _ _ eq1))) 
        _))) 
      (th5' _ _ _ eq1 
       (proj1_sig (norm_union (v, snd p) 
           (th3' _ _ _ eq1))) 
       (proj2_sig (norm_union (v, snd p) 
           (th3' _ _ _ eq1))) 
       (proj1_sig 
        (norm_union 
          (u, proj1_sig (norm_union (v, snd p) 
              (th3' _ _ _ eq1))) 
        (th4' _ _ _ eq1 (th3' _ _ _ eq1) 
        (proj1_sig (norm_union (v, snd p) (th3' _ _ _ eq1))) 
        (proj2_sig (norm_union (v, snd p) (th3' _ _ _ eq1)))))) 
       (proj2_sig 
        (norm_union 
          (u, proj1_sig (norm_union (v, snd p) 
              (th3' _ _ _ eq1))) 
        (th4' _ _ _ eq1 (th3' _ _ _ eq1) 
        (proj1_sig (norm_union (v, snd p) (th3' _ _ _ eq1))) 
        (proj2_sig (norm_union (v, snd p) (th3' _ _ _ eq1))))))) 
    end 
    | arO _ d1 d2 => 
    match ar (snd p) with 
     arE _ eq2 => exist _ (fst p) (th11' _) 
    | arU _ v w eq2 => 
     if eq_regex_dec (fst p) v then 
      exist _ (Union v w) (th7' _ _ _ eq2) 
     else if le_regex (fst p) v then 
     exist _ (Union (fst p) (Union v w)) (th8' _ _ _ eq2) 
     else exist _ (Union v (proj1_sig (norm_union (fst p, w) 
       (th9' _ _ _ eq2)))) 
       (th10' _ _ _ eq2 
       (proj1_sig (norm_union (fst p, w) 
         (th9' _ _ _ eq2))) 
       (proj2_sig (norm_union (fst p, w) 
         (th9' _ _ _ eq2)))) 
    | arO _ d1 d2 => 
     if eq_regex_dec (fst p) (snd p) then 
     exist _ (fst p) (th11' _) 
     else if le_regex (fst p) (snd p) then 
     exist _ (Union (fst p) (snd p)) (th12' _) 
     else exist _ (Union (snd p) (fst p)) (th13' _) 
    end 
    end. 

、すべての出力値はexist _コンテキスト内で、次のとおりです:

はその後、我々はnorm_union_F関数の本体を持っていないだけで、我々は、出力値を生成しますが、我々はまた、サイズがあることを示してやりますこの値の入力ペアの合計サイズよりも小さくなります。さらに、すべての再帰呼び出しはproj1_sigコンテキスト内にあるため、出力値を構築する瞬間のサイズ情報は忘れてしまいます。また、ここではすべての再帰呼び出し(ここではnorm_unionという名前の関数を呼び出すことで表されます)は、再帰呼び出しへの入力が最初の入力よりも実際に小さいという証拠もあります。すべての証明はthe complete developmentです。

refineのような戦術を使用してnorm_union_Fを定義することはおそらく可能ですが、あなたは探索に招待されます。

その後、我々はnorm_union_1の出力が{x | size_regex x <= size_2regex p}を入力したことをnorm_union_1

Definition norm_union_1 : forall p : regex*regex, 
    {x | size_regex x <= size_2regex p} := 
    Fix well_founded_order (fun p => {x | size_regex x <= size_2regex p}) 
    norm_union_F. 

注本当に再帰関数を定義します。これはあなたが求めているタイプではありません。したがって、出力が入力よりも小さい論理情報を忘れることによって、あなたが望むものである新しい関数を定義します。

Definition norm_union u v : regex := proj1_sig (norm_union_1 (u, v)). 

あなたが依頼した機能であることは、まだ疑問に思うかもしれません。自分自身を納得させるために、私たちはあなたが定義したことを正確に表現する補助詞を証明しようとしています。

まず、norm_union_1の対応する補題を証明します。これは、Fix関数に関連付けられた定理、名前Fix_eqに依存しています。証明が必要なのはかなり日常的なことです(それはいつも自動的に行うことができますが、私はそのための自動ツールを開発することに決して慣れていません)。

そして、私たちは最も興味深い見出しを完成させます。これはnorm_unionのものです。 (私は単にそれをコピー&ペースト)

Lemma norm_union_eqn u v : 
    norm_union u v = 
    match u, v with 
    | Empty , v   => v 
    | u  , Empty  => u 
    | Union u v, w   => norm_union u (norm_union v w) 
    | u  , Union v w => if eq_regex_dec u v 
          then Union v w 
          else if le_regex u v 
           then Union u (Union v w) 
           else Union v (norm_union u w) 
    | u  , v   => if eq_regex_dec u v 
          then u 
          else if le_regex u v 
           then Union u v 
           else Union v u 
    end. 

は、この式の右辺は、あなたの最初の質問に与えたコードが正確であることに注意してください:ここでは文です。この最終定理の証明は、かなり体系的です。

私はあなたの要求に厳密に従って努力しましたが、実際には3つの再帰関数を使用して同じ機能を簡単に実装していることがわかりました。最初のものはUnionのバイナリツリーを平らにしてリストのように見せ、他の2つはこれらのユニオンを注文le_regexに関してソートし、重複が解消されるとすぐに削除します。そのような実装は、ネストされた再帰の必要性を回避するだろう。

ネストされた再帰に固執してここに記載されているテクニックを参照する必要がある場合は、TPHOLs2000のBalaaとBertotの論文に最初に掲載されました。この論文は、Coqが別の構文を使用していた時点で書かれているため、読みにくいです。

関連する問題