web-dev-qa-db-ja.com

プログラムを証明できないのはなぜですか?

数学的なステートメントと同じように、コンピュータプログラムを証明できないのはなぜですか?数学的証明は、他の証明の上に構築されます。他の証明は、さらに多くの証明から公理に至るまで構築されます。これらの真理は、私たちが自明であると考えています。

コンピュータプログラムはそのような構造を持っていないようです。あなたがコンピュータプログラムを書く場合、あなたが以前に証明された作品を取り、あなたのプログラムの真実を示すためにそれらを使用することができるのはどうしてですか?存在しないのでできません。さらに、プログラミングの公理は何ですか?フィールドの非常に原子的な真実?

私は上記の良い答えを持っていません。しかし、ソフトウェアは科学ではなく芸術であるため、証明できないようです。ピカソをどのように証明しますか?

58
4thSpace

証明 are プログラム。

フォーマル検証 のプログラムは巨大な研究領域です。 (たとえば、 カーネギーメロン大学のグループ を参照してください。)

多くの複雑なプログラムが検証されています。たとえば、これを参照してください Haskellで書かれたカーネル

76
A. Rex

プログラムは絶対に正しいことが証明できます。お粗末なプログラムを証明するのは難しいです。それを合理的にうまく行うには、プログラムを進化させ、手を携えて証明する必要があります。

停止性問題のため、証明を自動化することはできません。ただし、任意のステートメントまたは一連のステートメントの事後条件と前提条件を手動で証明することはできます。

Dijsktraの プログラミングの分野 を読む必要があります。

次に、Gries ' The Science of Programming を読む必要があります。

次に、プログラムが正しいことを証明する方法を学びます。

31
S.Lott

停止問題は、検証できないプログラムがあることを示しているだけです。より興味深く、より実用的な質問は、どのクラスのプログラムcanがフォーマル検証されるかです。たぶん、誰もが気にかけているすべてのプログラムを(理論的には)検証できるでしょう。 実際には、これまでのところ、非常に小さなプログラムだけが正しいことが証明されています。

15
John D. Cook

不完全性を提起した人々へのほんの少しのコメント-それはすべて公理システムの場合ではなく、十分に強力なシステムだけです。

言い換えれば、ゲーデルは、それ自体を説明するのに十分強力な公理システムが必然的に不完全であることを証明しました。しかし、これはそれが役に立たないという意味ではなく、他の人がリンクしているように、プログラムの証明でさまざまな試みがなされてきました。

双対問題(証明をチェックするプログラムの作成)も非常に興味深いものです。

15
Sumudu Fernando

実際、あなたは確かに正しいプログラムを書くことができます。たとえば、Microsoftは、自動定理証明器を含む Spec# と呼ばれるC#言語の拡張機能を作成しました。 Javaの場合、 ESC/Java があります。そこにはもっとたくさんの例があると確信しています。

edit:どうやらspec#はもう開発されていませんが、 コントラクトツールは.NET 4.0の一部になります

停止問題 または 不完全性定理 について手を振っているポスターがいくつかありますが、これはおそらくプログラムの自動検証を妨げています。もちろん、これは真実ではありません。これらの問題は、正しいか間違っているかを証明できないプログラムを書くことが可能であることを示しているにすぎません。それは、確かに正しいプログラムを構築することを妨げるものではありません。

15
Wim Coenen

このトピックに本当に興味がある場合は、まず、このトピックに関する古典的な入門書であるDavidGriesの「TheScienceofProgramming」をお勧めします。

実際には、プログラムがある程度正しいことを証明することは可能です。前提条件と事後条件を記述し、前提条件を満たす状態が与えられた場合、実行後の結果の状態が事後条件を満たすことを証明できます。

ただし、注意が必要なのはループです。これらの場合、さらにループ不変条件を見つける必要があり、正しい終了を示すには、各ループの後に残っている可能な最大反復回数の上限関数を見つける必要があります。また、ループを繰り返すたびに、これが少なくとも1つ減少することを示す必要があります。

プログラムのためにこれらすべてを手に入れたら、証明は機械的です。しかし、残念ながら、ループの不変関数と有界関数を自動的に導出する方法はありません。ループが小さい些細なケースでは人間の直感で十分ですが、現実的には、複雑なプログラムはすぐに手に負えなくなります。

8
Boojum

まず、なぜ「プログラムは証明できない」と言っているのですか?

とにかく「プログラム」とはどういう意味ですか?

プログラムによってアルゴリズムを意味しているのなら、クラスカル法を知らないのですか?ダイクストラの? MST?プリムの?二分探索?マージソート? DP?それらすべてには、それらの動作を説明する数学的モデルがあります。

説明します。数学は物事の理由を説明せず、単にその方法の絵を描きます。明日東に太陽が昇ることを証明することはできませんが、過去にそのことを行っていたデータを示すことはできます。

あなたは次のように述べています。「コンピュータプログラムを作成する場合、以前に証明された作品を取得し、それらを使用してプログラムの真実を示すことができるのはどうしてですか。存在しないため、できません。」

待つ?できませんか? http://en.wikipedia.org/wiki/Algorithm#Algorithmic_analysis

私はあなたに「真実」を示すことができません私はあなたに言語で「真実」を示すことができないのと同じくらい私はプログラムです。どちらも、私たちの世界に対する経験的理解を表しています。 「真実」ではありません。すべてのぎこちなさはさておき、マージソートアルゴリズムがリストの要素をO(nlogn)パフォーマンスでソートし、ダイクストラが重み付きグラフで最短経路を見つけることを数学的に示すことができます。または、ユークリッドのアルゴリズムにより、2つの数値間の最大公約数が検出されます。最後の場合の「私のプログラムの真実」は、2つの数値間の最大公約数を検出する可能性があります。

漸化式を使用して、フィボナッチプログラムがどのように機能するかを説明できます。

さて、コンピュータープログラミングは芸術ですか?確かにそうだと思います。数学と同じくらい。

6
andandandand

私は数学的な経歴を持っていないので、無知を許してください。しかし、「プログラムを証明する」とはどういう意味ですか?何を証明していますか?正しさ?正当性は、プログラムが「正しい」ことを確認する必要がある仕様です。しかし、この仕様は人間によって決定されます。この仕様が正しいことをどのように確認しますか?

私の考えでは、人間は本当に欲しいものを表現するのが難しいため、プログラムにはバグがあります。 代替テキストhttp://www.processdevelopers.com/images/PM_Build_Swing.gif

それで、あなたは何を証明していますか?注意の欠如によって引き起こされたバグ?

5
Nicolas Dorier

さらに、プログラミングの公理は何ですか?フィールドの非常に原子的な真実?

契約ベースのプログラミングと呼ばれるコースをTAしました(コースのホームページ: http://www.daimi.au.dk/KBP2/ )。ここで私がコース(および私が取った他のコース)から推定できるもの

言語のセマンティクスを正式に(数学的に)定義する必要があります。簡単なプログラミング言語について考えてみましょう。グローバル変数のみ、int、int配列、算術、if-then-else、while、代入、何もしない[これの「実装」として主流言語のサブセットを使用できる可能性があります]。

実行状態は、ペアのリスト(変数名、変数の値)になります。 「{Q1} S1 {Q2}」を「ステートメントS1を実行すると、実行状態Q1から状態Q2に移動します」と読みます。

その場合、1つの公理は_"if both {Q1} S1 {Q2} and {Q2} S2 {Q3}, then {Q1} S1; S2 {Q3}"_になります。つまり、ステートメントS1が状態Q1からQ2に移動し、ステートメントS2がQ2からQ3に移動する場合、「S1; S2」(S1の後にS2)が状態Q1から状態Q3に移動します。

別の公理は_"if {Q1 && e != 0} S1 {Q2} and {Q1 && e == 0} S2 {Q2}, then {Q1} if e then S1 else S2 {Q2}"_です。

ここで、少し改良します。{}のQnは、実際には状態自体ではなく、状態に関するステートメントになります。

M(out、A1、A2)が、ソートされた2つの配列をマージし、結果をoutに格納するステートメントであり、次の例で使用するすべての単語が形式的に(数学的に)表現されているとします。次に、"{sorted(A1) && sorted(A2)} A := M(A1, A2) {sorted(A) && permutationOf(A, A1 concatened with A2)}"は、Mがマージアルゴリズムを正しく実装しているという主張です。

上記の公理を使用してこれを証明しようとすることができます(おそらく他のいくつかが必要になるでしょう。たとえば、ループが必要になる可能性があります)。

これが、正しい証明プログラムがどのように見えるかを少し説明してくれることを願っています。そして私を信じてください:一見単純なアルゴリズムであっても、それらが正しいことを証明するには、lotの作業が必要です。私は知っています、私はたくさんの試みを読みました;-)

[これを読んだら:yourの手渡しは大丈夫だった、それは私に頭痛を引き起こした他のすべてのものです;-)]

4
Jonas Kölker

もちろん、他の人が投稿したように、彼らはそうすることができます。

非常に小さなサブルーチンが正しいことを証明することは、プログラミング関連の学位プログラムのすべての学部生がrequiredであるべきであるという良い演習です。やること。これにより、コードを明確にし、レビューしやすく、保守しやすくする方法について考えるための優れた洞察が得られます。

ただし、現実の世界では、実用性は限られています。

まず、プログラムにバグがあるのと同じように、数学的な証明もあります。数学的証明が本当に正しく、エラーがないことをどのように証明しますか?できません。また、反例として、公開されている数学的証明の多くで、場合によっては数年後にエラーが発見されています。

第二に、プログラムが何をすべきかについての明確な定義が「先験的に」なければ、プログラムが正しいことを証明することはできません。しかし、プログラムが何をすべきかについての明確な定義はプログラムです。 (コンパイラがない、ある種の仕様言語のプログラムかもしれませんが。)したがって、プログラムが正しいことを証明する前に、まず同等で事前にわかっている別のプログラムを用意する必要があります。正しいこと。したがって、QEDはすべてが無駄です。

Brooksによる古典的な "特効薬なし"の記事を追跡することをお勧めします。

3
Die in Sente

あなたが自信を探しているなら、プログラムを証明する代わりにそれらをテストすることです。これは理解しやすく、自動化できます。また、上記のように、証明が数学的に不可能なプログラムのクラスも可能にします。

何よりも、受け入れテストに合格する代わりとなる証拠はありません:*

  • プログラムが実際に実行すると言っていることを実行するからといって、ユーザーが望んでいることを実行するという意味ではありません。

    • でない限り、それが行うことはユーザーが望むことであると証明できます。

      • 次に証明しなければならないのは、彼らが本当に望んでいることです。なぜなら、ユーザーであるため、彼らはほぼ確実に彼らが何を望んでいるのかわからないからです。など。帰謬法。

*ユニット、カバレッジ、機能、統合、およびその他すべての種類のテストは言うまでもありません。

これがあなたの道に役立つことを願っています。

2
Mike A

この分野には多くの研究があります。他の人が言っているように、プログラム言語内の構成は複雑であり、特定の入力を検証または証明しようとすると、これはさらに悪化します。

ただし、多くの言語では、どの入力が受け入れ可能か(前提条件)、および最終結果(事後条件)を指定することもできます。

このような言語には、B、イベントB、Ada、Fortranが含まれます。

そしてもちろん、プログラムに関する特定の特性を証明するのに役立つように設計されたツールはたくさんあります。たとえば、デッドロックの自由を証明するために、SPINを介してプログラムをクランチすることができます。

論理エラーの検出にも役立つツールもたくさんあります。これは、静的分析(goanna、satabs)またはコードの実際の実行(gnu valgrind?)を介して実行できます。

ただし、開始(仕様)から実装、展開まで、プログラム全体を実際に証明できるツールは1つではありません。 Bメソッドは近づいていますが、その実装チェックは非常に弱いです。 (それは、人間がspeicficaitonの実装への翻訳において不滅であると仮定します)。


ちなみに、Bメソッドを使用すると、小さな公理から複雑な証明を作成することがよくあります。 (そして、同じことが他の誇張定理証明者にも当てはまります)。

2
Alex Lim

ここで言及されていないのは、形式手法ベースのシステムである B --Method です。パリの地下の安全システムを開発するために使用されました。 BおよびイベントBの開発をサポートするために利用できるツールがあります。特に Rodin です。

2
Johnno Nolan

プログラムを証明できるだけでなく、証明からコンピューターにプログラムを構築させることもできます。 Coq を参照してください。したがって、実装を間違えた可能性について心配する必要はありません。

2
Jay Kominek

ゲーデルの定理 それにもかかわらず...ポイントは何でしょうか?どのような単純な「真実」を証明したいですか?あなたはそれらの真実から何を導き出したいですか?私はこれらの言葉を食べるかもしれませんが...実用性はどこにありますか?

1
Jason Punyon

プログラムは証明することができます。たとえばNewJerseyのStandardML(SML/NJ)のような言語で書くと、とても簡単です。

1
vartec

純粋に関数型言語(つまりHaskell)を想定しましょう。このような言語では、副作用を非常に明確に考慮することができます。

プログラムが正しい結果を生成することを証明するには、以下を指定する必要があります。

  1. データ型と数学セット間の対応
  2. haskell関数と数学関数の対応
  3. 他の関数から構築できる関数を指定する一連の公理、および数学的な側面での対応する構造。

この一連の仕様は表示的意味論と呼ばれます。彼らはあなたが数学を使ったプログラムについての理由を証明することを可能にします。

良いニュースは、「プログラムの構造」(上記のポイント3)と「数学セットの構造」が非常に似ていることです(流行語はtopos、またはデカルト閉圏 =)、したがって1 /数学側で行う証明はプログラム構造に簡単に転送されます2 /あなたが書いたプログラムは数学的に正しいことが簡単に示されます。

1
Alexandre C.

私はすべての答えを読んだわけではありませんが、私が見ているように、プログラムを証明することは無意味です。それが誰もそれをしない理由です。

比較的小規模/中規模のプロジェクト(たとえば、10K行のコード)がある場合、証明はおそらく10K行になるでしょう。

プログラムにバグがある可能性がある場合は、証明にも「バグ」がある可能性があることを考えてみてください。たぶんあなたは証明のための証明が必要になるでしょう!

考慮すべきもう1つのことは、プログラムは非常に形式的で正確です。プログラムコードは非常に馬鹿げたマシンで実行する必要があるため、これ以上厳密で正式なものを取得することはできません。

証明は人間によって読み取られる予定ですが、実際のコードよりも厳密ではない傾向があります。

証明したいのは、特定のデータ構造(クイックソート、バイナリツリーへの挿入など)を操作する低レベルのアルゴリズムだけです。

これらのことはやや複雑で、なぜ機能するのか、および/または常に機能するのかどうかはすぐにはわかりません。これらは、他のすべてのソフトウェアの基本的な構成要素でもあります。

0
hasen

停止問題 (プログラムが完了するかどうかと同じくらい単純なことを証明することの難しさについて)を読んでください。基本的に、この問題はゲーデルの不完全性定理に関連しています。

0
timday

プログラムのいくつかの部分は証明することができます。たとえば、コンパイルが成功した場合に型の安全性を静的に検証および保証するC#コンパイラ。しかし、あなたの質問の核心は、プログラムが正しく実行されることを証明することだと思います。多くの(私はほとんどとは言いませんが)アルゴリズムが正しいことを証明できますが、プログラム全体はおそらく次の理由で静的に証明することはできません。

  • 検証では、すべての可能な分岐(呼び出し、if、および中断)をトラバースする必要があります。これは、高度なプログラムコードでは、非常に立方体の時間計算量を持ちます(したがって、妥当な時間内に完了することはありません)。
  • コンポーネントの作成またはリフレクションの使用による一部のプログラミング手法では、コードの実行を静的に予測できません(つまり、別のプログラマーがライブラリをどのように使用するかわからず、コンパイラーはコンシューマーでのリフレクションがどのようになるかを予測するのに苦労しています機能を呼び出します。

そしてそれらはほんの一部です...

0
Scofield

さらに、プログラミングの公理は何ですか?フィールドの非常に原子的な真実?

opcodes「アトミックトゥルース」ですか?たとえば、見て...

mov ax,1

...プログラマーは、ハードウェアの問題がなければ、このステートメントを実行した後、CPUのaxレジスターに1が含まれることを公理的に主張しないかもしれませんか?

あなたがコンピュータプログラムを書く場合、あなたが以前に証明された作品を取り、あなたのプログラムの真実を示すためにそれらを使用することができるのはどうしてですか?

その場合、「前の作業」は、新しいプログラムが実行されるランタイム環境である可能性があります。

新しいプログラムは証明できます。正式な証明とは別に、「検査」およびさまざまな形式の「テスト」(「受け入れテスト」を含む)によって証明できます。

ピカソをどのように証明しますか?

ソフトウェアが芸術よりも工業デザインや工学に似ている場合、より良い質問は「橋や飛行機をどのように証明するか」かもしれません。

0
ChrisW

プログラムに明確に定義された目的と初期の仮定がある場合(ゲーデルを無視して...)、それを証明することができます。 6 <= x <= 10の場合、すべての素数xを見つけます。答えは7であり、それを証明できます。 NIMを再生するプログラム (最初に書いたPythonプログラム))を作成しました。理論的には、ゲームがコンピューターの状態になった後、コンピューターが常に勝ちます。勝つことができます。私はそれが真であることを証明できませんでしたが、それはIS true(数学的にはデジタルバイナリ合計証明による)コードに誤りがない限り信じています。間違いを犯して、まじめな話ではありませんが、このプログラムが優れているかどうか誰かに教えてもらえますか?

四色定理 のようなコンピュータコードで「証明」された数学的定理がいくつかあります。しかし、あなたが言ったように、あなたはプログラムを証明することができるので、反対意見がありますか?

0
Alex

ほとんどの回答は練習に焦点を合わせており、それは問題ありません。実際には、正式な校正については気にしません。しかし、理論的には何ですか?

プログラムは、数学的なステートメントと同じように証明できます。しかし、あなたが意図した意味ではありません!十分に強力なフレームワークには、証明できない数学的ステートメント(およびプログラム)があります! ここ を参照してください

0
Davide

プログラムが正しいことを証明することは、プログラムの仕様に関連してのみ行うことができます。それは可能ですが、費用と時間がかかります

一部のCASEシステムは、他のシステムよりも証明に適したプログラムを生成しますが、これも仕様の正式なセマンティクスに依存しています...

...では、仕様が正しいことをどのように証明しますか?正しい!より多くの仕様で!

0
Steven A. Lowe

ちょうど私の2セント、すでにそこにある興味深いものに追加します。

証明できないすべてのプログラムの中で、最も一般的なものはIO(世界またはユーザーとの予測できない相互作用)を実行するプログラムです。自動証明でさえ、「証明された」ことを忘れることがあります。 「プログラム」は、モデルで説明されている理想的なハードウェアではなく、一部の物理ハードウェアで実行されます。

一方、数学的な証明は世界の多くを気にしません。数学で繰り返される質問は、それが本当のことを説明しているかどうかです。虚数や非ユークリッド空間のような新しいものが発明されるたびに発生します。これらの新しい理論は非常に優れたツールであるため、質問は忘れられます。良いプログラムのように、それはうまくいきます。

0
kriss

ここは騒がしいけど、とにかく風に乗って叫ぶぞ….

「正しいことを証明する」は、文脈によって意味が異なります。 形式システム で、「正しいことを証明する」とは、式が他の証明された(または公理的な)式から導出できることを意味します。プログラミングの「正しいことを証明する」は、コードが正式な仕様と同等であることを示しているだけです。しかし、どのようにして正式な仕様が正しいことを証明しますか?残念ながら、テスト以外に、仕様にバグがないことを示したり、実際の問題を解決したりする方法はありません。

0
Chris Broski

他の人が指摘したように、(いくつかの)プログラムは確かに証明することができます。

ただし、実際の問題の1つは、最初に証明したい何か(つまり、仮定または定理)が必要なことです。したがって、プログラムについて何かを証明するには、最初に、プログラムが何をすべきかについての正式な説明が必要です(たとえば、事前条件と事後条件)。

つまり、プログラムの正式な仕様が必要です。しかし、合理的な(厳密ではない)仕様を取得することは、ソフトウェア開発ですでに最も難しいことの1つです。したがって、(実世界の)プログラムについて興味深いことを証明することは一般的に非常に困難です。

ただし、より簡単に形式化(および証明)できる(そして証明された)ものがいくつかあります。少なくともプログラムがクラッシュしないことを証明できれば、それはすでに何かです:-)。

ところで、一部のコンパイラの警告/エラーは、本質的にプログラムに関する(単純な)証明です。たとえば、Javaコンパイラは、コード内の初期化されていない変数にアクセスしないことを証明します(そうでない場合、コンパイラエラーが発生します)。

0
sleske

これについて少し読みましたが、2つの問題があります。

まず、正しさと呼ばれる抽象的なものを証明することはできません。適切に設定されていれば、2つの正式なシステムが同等であることを証明できます。プログラムが一連の仕様を実装していることを証明できます。これを行うには、証明とプログラムをほぼ並行して構築するのが最も簡単です。したがって、仕様は、証明するものを提供するために十分に詳細である必要があり、したがって、仕様は事実上プログラムです。目的を満たすためにプログラムを書くという問題は、目的を満たすためにプログラムの正式な詳細仕様を書くという問題になりますが、それは必ずしも一歩前進ではありません。

第二に、プログラムは複雑です。正しさの証明もそうです。あなたがプログラムを書くのを間違えることができるならば、あなたは確かにそれを証明することができます。ダイクストラとグリーは、基本的に、私が完璧な数学者であれば、優れたプログラマーになることができると私に言いました。ここでの価値は、証明とプログラミングは2つの多少異なる思考プロセスであり、少なくとも私の経験では、私はさまざまな種類の間違いを犯しているということです。

私の経験では、プログラムを証明することは役に立たないわけではありません。私が正式に説明できることをしようとしているとき、実装が正しいことを証明することで、見つけにくいエラーをたくさん排除し、主に愚かなエラーを残します。これはテストで簡単に見つけることができます。非常にバグのないコードを生成する必要があるプロジェクトでは、それは便利な補助になる可能性があります。すべてのアプリケーションに適しているわけではなく、特効薬ではありません。

0
David Thornley

あまり抽象的な観点からは、何かを証明することは、不確実性の分野を証明されたヌルセットに減らすことの問題です。現実の世界では完璧に到達できないので、それは希望的観測です。

コンピュータプログラムは、その環境が証明されていない(または証明できない)場合、確かに正しく、現実の世界では失敗する可能性があります。

  • oSカーネル、ドライバー、すべてのユーザーモードライブラリ、および同時に実行されるプログラムは、直接的および間接的な短期的および長期的な副作用を含めて、証明する必要があります。

  • ハードウェアは常に期待どおりに動作する必要があります(停電、洪水、地震、EMF干渉など)を含む)、

  • エンドユーザーは常に期待どおりに動作する必要があります(有名な要素「X」)。

自動エラー訂正は、さまざまなハードウェアコンポーネント(RAM、ディスク、コントローラーなど)に実装されていますが、それでもハードウェア障害が発生し、カスケードエラーや... provably correctプログラムの障害が発生します。

そして、私はエンドユーザーの創造性についてエピローグしようとさえしていません...

したがって、(正しく)provably correctと評価されたプログラムは、実際にはprovably safeであることを意味するものではありません。

これは、定義済みの調査(実世界のサブセットにしかなり得ない)で検討されたセットの場合、このプログラムは期待どおりに動作することを意味します。

0
Gil