0

二項演算子があるとしf :: "sT => sT => sT"ます。fWiki でここに示されている、クライン 4 グループの 4x4 乗法テーブルを実装するように定義したいと思います。

http://en.wikipedia.org/wiki/Klein_four-group

ここで試みているのは、16 エントリのテーブルを作成することだけです。まず、次のように 4 つの定数を定義します。

consts
  k_1::sT  
  k_a::sT  
  k_b::sT  
  k_ab::sT

次に、テーブル内の 16 エントリを実装する関数を定義します。

  k_1 * k_1 = k_1
  k_1 * k_a = k_a
  ...
  k_ab * k_ab = k_1

私は Isar で通常のようなプログラミングを行う方法を知りません。Isabelle ユーザーのリストで、(特定の) プログラミングのような構造が言語で意図的に強調されていないと言われているのを見たことがあります。

先日、単純な不自然な関数を作成しようとしましたがif, then, else、ソース ファイルでの使用を見つけた後、 isar-ref.pdfでそれらのコマンドへの参照を見つけることができませんでした。

チュートリアルを見るdefinitionと、簡単な方法で関数を定義することがわかります。それ以外は、 を必要とする再帰関数と帰納関数に関する情報しか表示されずdatatype、私の状況はそれよりも単純です。

私自身のデバイスに任せた場合、datatype上記の 4 つの定数に対して a を定義してから、いくつかの変換関数を作成して、2 項演算子f :: sT => sT => sT. を使おうとして少しいじりましfunたが、単純な取引ではありませんでした。

私は少し実験をfun行いましたinductive

更新:プログラミングと証明が答えを見つける場所であるというコメントに応えて、ここにいくつかの資料を追加します。理想的な Stackoverflow 形式から外れているようです。

私はいくつかの基本的な実験を行いました。主にfunだけでなく、 も使用しましinductiveた。私は誘導をかなり早くあきらめました。簡単な例から得たエラーのタイプは次のとおりです。

consts
  k1::sT

inductive k4gI :: "sT => sT => sT" where
  "k4gI k1 k1 = k1"
--"OUTPUT ERROR:"
--{*Proofs for inductive predicate(s) "k4gI"
    Ill-formed introduction rule ""
    ((k4gI k1 k1) = k1)
    Conclusion of introduction rule must be an inductive predicate  
*}

私の掛け算九九は帰納的ではないので、それをinductive追うのに時間を費やすべきだとは思いませんでした.

ここでは「パターン マッチング」が重要なアイデアのように思われるので、 を試してみましfunた。fun以下は、標準の関数型のみを使用しようとしている、本当にめちゃくちゃなコードです。

consts
  k1::sT

fun k4gF :: "sT => sT => sT" where
  "k4gF k1 k1 = k1"
--"OUTPUT ERROR:"
--"Malformed definition:
   Non-constructor pattern not allowed in sequential mode.
   ((k4gF k1 k1) = k1)"

その種のエラーが発生しました。プログラミングと証明で次のようなことを読みました。

「再帰関数は、データ型コンストラクターに対するパターン マッチングによって楽しく定義されます。

これらすべてが、初心者にfun必要な印象を与えますdatatype。その兄貴分まではfunction、私はそれについて知りません。

ここにあるようです。必要なのは、16 の基本ケースを持つ再帰関数だけであり、それが乗算表を定義します。

function答えは?

この質問を編集する際に、私functionは過去を思い出しましたfunction

consts
  k1::sT

function k4gF :: "sT => sT => sT" where
  "k4gF k1 k1 = k1"
  try

try の出力は、証明できることを示しています (更新: 実際には、証明ステップの 1 つだけを証明できることを示していると思います)。

Trying "solve_direct", "quickcheck", "try0", "sledgehammer", and "nitpick"... 
Timestamp: 00:47:27. 
solve_direct: (((k1, k1) = (k1, k1)) ⟹ (k1 = k1)) can be solved directly with
  HOL.arg_cong: ((?x = ?y) ⟹ ((?f ?x) = (?f ?y))) [name "HOL.arg_cong", kind "lemma"]
  HOL.refl: (?t = ?t) [name "HOL.refl"]
  MFZ.HOL⇣'eq⇣'is⇣'reflexive: (?r = ?r) [name "MFZ.HOL⇣'eq⇣'is⇣'reflexive", kind "theorem"]
  MFZ.HOL_eq_is_reflexive: (?r = ?r) [name "MFZ.HOL_eq_is_reflexive", kind "lemma"]
  Product_Type.Pair_inject:
    (⟦((?a, ?b) = (?a', ?b')); (⟦(?a = ?a'); (?b = ?b')⟧ ⟹ ?R)⟧ ⟹ ?R)
      [name "Product_Type.Pair_inject", kind "lemma"]

それが何を意味するのかわかりません。私が知ってfunctionいるのは、矛盾を証明しようとしているからです。私はそれがそれほど文句を言わないことを知っているだけです。このfunctionように乗算表を定義する方法を使用する場合、私は満足しています。

それでも、私は議論型なのでfunction、チュートリアルで学びませんでした. 数か月前にリファレンス マニュアルでそれについて学びましたが、その使用方法についてはまだよくわかりません。

私はfunctionで証明した を持っていautoますが、幸いなことに機能はおそらく良くありません。functionそれはの謎に追加されます。Defining Recursive Functions in Isabelle/HOLfunctionに情報があり、 と を比較しています。funfunction

ただし、 or のような再帰的なデータ型を使用しない or の例は見たことがありませfunん。よく見ていなかったのかもしれません。functionnat'a list

冗長で申し訳ありませんが、これは直接的な質問にはなりませんが、A から B に人を直接連れて行く Isabelle のチュートリアルはありません。

4

2 に答える 2

0

以下では、「質問に答えるだけ」という形式には従いませんが、私自身の質問に答えているので、私が言うことはすべて元の投稿者にとって興味深いものになるでしょう.

(2回目の更新開始)

これが私の最後の更新になるはずです。「洗練されていない方法」に満足するためには、「ローテク」な方法が最善の方法である可能性があることを比較することができます。

私は最終的に、メインの型を新しい型で動作させることをやめ、datatype結合性の証明が最後にある、このようなものからクラインの 4 群を作成しました。

datatype AT4k = e4kt | a4kt | b4kt | c4kt  

fun AOP4k :: "AT4k => AT4k => AT4k" where
  "AOP4k e4kt y    = y"
| "AOP4k x    e4kt = x"
| "AOP4k a4kt a4kt = e4kt"
| "AOP4k a4kt b4kt = c4kt"
| "AOP4k a4kt c4kt = b4kt"
| "AOP4k b4kt a4kt = c4kt"
| "AOP4k b4kt b4kt = e4kt"
| "AOP4k b4kt c4kt = a4kt"
| "AOP4k c4kt a4kt = b4kt"
| "AOP4k c4kt b4kt = a4kt"
| "AOP4k c4kt c4kt = e4kt"

notation
  AOP4k ("AOP4k") and
  AOP4k (infixl "*" 70) 

theorem k4o_assoc2:
  "(x * y) * z = x * (y * z)"
by(smt AOP4k.simps(1) AOP4k.simps(10) AOP4k.simps(11) AOP4k.simps(12) 
  AOP4k.simps(13) AOP4k.simps(2) AOP4k.simps(3) AOP4k.simps(4) AOP4k.simps(5) 
  AOP4k.simps(6) AOP4k.simps(7) AOP4k.simps(8) AOP4k.simps(9) AT4k.exhaust)

その結果、私は自分のif-then-else乗算関数に満足しています。なんで?if-then-else関数は魔法を非常に助長するからですsimp。このパターン マッチングは、それ自体では魔法のようには機能しません。

4x4 乗算表のif-then-else関数は次のとおりです。

definition AO4k :: "sT => sT => sT" where
  "AO4k x y = 
    (if x = e4k then y   else
    (if y = e4k then x   else
    (if x = y   then e4k else
    (if x = a4k  y = c4k then b4k else
    (if x = b4k  y = c4k then a4k else
    (if x = c4k  y = a4k then b4k else  
    (if x = c4k  y = b4k then a4k else 
            c4k)))))))"

ネストされたif-then-elseステートメントが 1 つあるため、 を実行autoすると 64 のゴールが生成されます。simp乗算表の値ごとに 1 つずつ、合計16 のルールを作成しました。他のすべてのsimpルールを使用して auto を実行すると、auto証明には約 90 ミリ秒かかります。

ローテクは時々行く方法です。それはRISCCISCのことです。

掛け算の表のような小さなものはテストには重要ですが、完了するまでに永遠にかかる大きなループにあるため、THY の速度が低下する場合は役に立ちません。

(2回目の更新終了)

(更新開始)

(更新: 上記の私の質問は、「他のプログラミング言語と同様に、Isabelle で基本的なプログラミングを行うにはどうすればよいですか?」というカテゴリに分類されます。ここでは、特定の質問をいくつか超えていますが、挑戦についてのコメントは初心者に留めるようにしています。ドキュメントが中級レベルのときにイザベルを学ぼうとしている人は、少なくとも私の意見ではそうです。

ただし、私の質問に固有のものcaseは、多くのプログラミング言語の非常に基本的な機能であるステートメントが必要だということです。

今日のステートメントを探しているcaseときに、ドキュメントでもう一度検索を行った後、ゴールドをヒットしたと思いました。今回はIsabelle - A Proof Assistant for Higher-Order Logicです。

5ページにcase声明が記載されていますが、18ページには、それが にのみ有効であることを明確にしており、次のdatatypeようなエラーでそれを確認しているようです:

definition k4oC :: "kT => kT => kT" (infixl "**" 70) where
  "k4oC x y = (case x y of k1 k1 => k1)"
--{*Error in case expression:
    Not a datatype constructor: "i130429a.k1"
    In clause
    ((k1 k1) ⇒ k1)*}

これは、専門家であろうと初心者であろうと、Isabelle の基本的なプログラミング機能を実行するためのチュートリアルが必要な人の一例です。

「それを行うチュートリアルがあります」と言う場合。私は「いいえ、私の意見ではありません」と言います。

チュートリアルでは、Isabelle を他と区別する重要で洗練された機能を強調しています。

これは解説ですが、「Isabelle を学ぶにはどうすればよいですか?」という質問に結び付けるための解説であり、上記の最初の質問が関連しています。

ケンブリッジ、TUM、または NICTA の博士課程の学生でなくても Isabelle を学ぶ方法は、6 か月から 12 か月、またはそれ以上苦労することです。その間、あきらめなければ、中級レベルの指導を十分に理解できるレベルに達することができます。経験は異なる場合があります。

私にとって、私を次のレベルの証明に連れて行ってくれる3冊の本は、時間を見つけてそれらを読むことから私を引き離しautoますmetis.

誰かが「あなたは長々と解説や意見を述べて、Stackoverflow の回答形式を乱用しました」と言った場合。

私は言います、「そうですね、Isabelle で基本的なプログラミングを行うための良い方法を求めましたが、大きなステートメントよりも洗練されたものを望んでいましたif-then-else。私が求めたものに近いものを誰も提供してくれませんでした。実際、私ははパターン マッチング関数を提供しましたが、私がそれを行う必要があったことは文書化されていません. パターン マッチングは単純な概念ですが、再帰関数の証明要件のため、Isabelle では必ずしもそうではありません.if-then-else以下の関数を置き換えるためにそれを行うか、caseステートメントの方法でさえ、知りたいと思います.)

そうは言っても、私はいくらかの自由を取る傾向があります。現時点では、とにかくこのページのビューは 36 しかありません。おそらく、少なくとも 10 は私のブラウザからのものです。

Isabelle/HOL は強力な言語です。私は不平を言っていません。そう聞こえるだけです。)

(更新終了)

function何かが真であるか偽であるかを知ることは、非常に重要です。この場合、非帰納型で動作する可能性があると言われています。ただし、function以下を使用する方法は、Isabelle ドキュメントで見た結果ではなく、強制的なサブタイプに関するこの以前の SO の質問が必要でした。

Isabelle/HOL サブタイプとは何ですか? サブタイプを生成する Isar コマンドは?

掛け算の九九の 2x2 の部分を完成させるには 2 つの方法があります。私はここで理論にリンクしています:ASCIIフレンドリーな A_i130429a.thyjEditフレンドリーな i130429a.thyPDF、およびfolderとして。

2 つの方法は次のとおりです。

  1. 不器用ですが、迅速でsimpフレンドリーなif-then-else方法です。定義には 0 ミリ秒、証明には 155 ミリ秒かかります。
  2. を使ったパターンマッチングの方法function。ここでは、このやり方について長い間公の場で声に出して考えることができましたが、そうしません。ここで学んだことを使用することはわかっていますが、単純な乗算テーブル関数のエレガントなソリューションではないことは間違いありません。また、パターン マッチングを使用する基本的な関数を作成するために、そのすべてを行う必要があることは明らかではありません。 . もちろん、すべてを行う必要はないかもしれません。定義には 391 ミリ秒、証明には 317 ミリ秒かかります。

の使用に頼らなければif-then-elseならないことに関しては、Isabelle/HOL は基本的なプログラミング ステートメントに関しては機能が豊富ではないか、これらの基本的なステートメントが文書化されていません。このif-then-elseステートメントは、Isar リファレンス マニュアルのインデックスにもありません。「文書化されていない場合は、 Haskellのような、文書化されていない素敵なcaseステートメントがあるかもしれません」と思います。それでも、私はいつでも Isabelle を Haskell よりも優先します。

以下、A_i130429a.thy の各セクションについて説明します。些細なことですが、完全ではありません。その方法を教えてくれる例を見たことがないからです。

未定義のままの型と 4 つの定数から始めます。

typedecl kT
consts
  k1::kT
  ka::kT
  kb::kT
  kab::kT

注目すべきは、定数が未定義のままであることです。私が多くのものを未定義のままにしているということは、自分自身のテンプレートとして使用するドキュメントやソースで良い例を見つけるのに問題がある理由の一部です.

function非帰納的なデータ型でインテリジェントに使用しようとするテストを行いますが、機能しません。私のif-then-else関数では、関数ドメインを制限していないことがわかった後、この関数の問題はドメインにもあることがわかりました。はor for everyをfunction k4f0望んxでいますが、これは明らかに正しくありません。k1kax

function k4f0 :: "kT => kT" where
  "k4f0 k1 = k1"
| "k4f0 ka = ka"
apply(auto)
apply(atomize_elim)
--"goal (1 subgoal):
   1. (!! (x::sT). ((x = k1) | (x = ka)))"

私はあきらめて、 で醜い関数を定義しますif-then-else

definition k4o :: "kT => kT => kT" (infixl "**" 70) where
  "k4o x y =
    (if x = k1 & y = k1 then k1 else
    (if x = k1 & y = ka then ka else
    (if x = ka & y = k1 then ka else
    (if x = ka & y = ka then k1 else (k1)
    ))))"
declare k4o_def [simp add]

難しいのは、関数の結合性を証明しようとすることk4oです。しかし、それは私がドメインを制限していないからです. ステートメントに含意を入れると、auto魔法が作動し、fastforce魔法もそこにあり、より速く、それを使用します。

abbreviation k4g :: "kT set" where
  "k4g == {k1, ka}"

theorem
  "(x \<in> k4g & y \<in> k4g & z \<in> k4g) --> (x ** y) ** z = x ** (y ** z)"
  by(fastforce)(*155ms*)

魔法は私を幸せにしfunction、パターン マッチングでそれをやり遂げようとする動機を与えてくれます。上記にリンクされている、強制的なサブタイピングに関する最近の SO の回答により、ドメインを で修正する方法がわかりましたtypedef。それが完璧な解決策だとは思いませんが、確かに何かを学びました。

typedef kTD = "{x::kT. x = k1 | x = ka}"
  by(auto)
declare [[coercion_enabled]]
declare [[coercion Abs_kTD]]

function k4f :: "kTD => kTD => kT" (infixl "***" 70) where
  "k4f k1 k1 = k1"
| "k4f k1 ka = ka"
| "k4f ka k1 = ka"
| "k4f ka ka = k1"
by((auto),(*391ms*)
  (atomize_elim),
  (metis (lifting, full_types) Abs_kTD_cases mem_Collect_eq),
  (metis (lifting, full_types) Rep_kTD_cases Rep_kTD_inverse mem_Collect_eq),
  (metis (lifting, full_types) Rep_kTD_cases Rep_kTD_inverse mem_Collect_eq),
  (metis (lifting, full_types) Rep_kTD_cases Rep_kTD_inverse mem_Collect_eq),
  (metis (lifting, full_types) Rep_kTD_cases Rep_kTD_inverse mem_Collect_eq))
termination
by(metis "termination" wf_measure)

theorem
  "(x *** y) *** z = x *** (y *** z)"
by(smt
  Abs_kTD_cases
  k4f.simps(1)
  k4f.simps(2)
  k4f.simps(3)
  k4f.simps(4)
  mem_Collect_eq)(*317ms*)
于 2013-04-30T03:04:04.043 に答える