体系的な方法でクエリがPrologで失敗した*理由*を報告する
少なくともデータベース内の述語に関する限り、述語のセットが失敗した理由を返すために使用できるアプローチ、パターン、または組み込み機能をPrologで探しています。ユーザーがシステムでクエリを実行するときに、「それは誤りです」以上のことを言えるようにしようとしています。
たとえば、2つの述語があるとします。blue/1
何かが青いdog/1
場合はtrue、何かが犬の場合はtrue:
blue(X) :- ...
dog(X) :- ...
次のクエリをPrologに提示しfoo
、犬であるが青ではない場合、Prologは通常「false」を返します。
? blue(foo), dog(foo)
false.
私が欲しいのは、次のような帯域外呼び出しであっても、述語の接続詞が正しくない理由を見つけることです。
? getReasonForFailure(X)
X = not(blue(foo))
述語を特定の方法で記述しなければならない場合は問題ありません。人々が使用したアプローチを探しています。
私がこれまでこれを行ってきた方法は、ある程度の成功を収めており、定型化された方法で述語を記述し、いくつかのヘルパー述語を使用して事後の理由を見つけることです。例えば:
blue(X) :-
recordFailureReason(not(blue(X))),
isBlue(X).
そして、recordFailureReason / 1を実装して、スタックの最深部で発生した「理由」を常に記憶するようにします。クエリが失敗した場合、最も深い失敗が発生した場合は、失敗の「最良の」理由として記録されます。そのヒューリスティックは多くの場合驚くほどうまく機能しますが、うまく機能するには述語を注意深く構築する必要があります。
何か案は?この種の分析のために設計された述語論理システムがあれば、私はPrologの外を見たいと思っています。
回答
いくつかの考え:
論理プログラムが失敗した理由:「理由」に対する答えは、もちろん「Prologプログラムによって与えられた制約を満たす変数割り当てがないため」です。
これは明らかに役に立たないですが、まさに「青い犬」の場合です。そのようなことはありません(少なくともモデル化する問題では)。
実際、ブルードッグ問題に対する唯一の許容可能な答えは、システムが完全な定理証明モードに入り、次のように出力されたときに得られます。
blue(X) <=> ~dog(X)
または多分ただ
dog(X) => ~blue(X)
または多分ただ
blue(X) => ~dog(X)
仮定に応じて。「青い犬の証拠はありません」。それがプログラムが述べていることなので、それは本当です。したがって、この質問の「理由」は、プログラムを書き直す要求です...
そこではないこともない良い答え:「なぜ、X 2 <0であることのNO xなどがあり、」不良設定であると答えようがあり「という理由だけで」または「あなたは実数に自分自身を制限しているため、」または「という0であるため方程式はちょうど間違っています」 ...それでそれは非常に依存します。
「なぜ」をより役立つものにするには、この「なぜ」を何らかの形で修飾する必要があります。これは、プログラムを構造化し、クエリを拡張して、プルーフツリーの構築中に収集される追加情報がバブリングするようにすることで実行できますが、次の情報を事前に決定する必要があります。
query(Sought, [Info1, Info2, Info3])
そして、このクエリは常に成功します(query/2
つまり、「成功」は「モデル化された問題の解決策を見つけることに成功した」ではなく、「計算を終了することに成功した」ことを意味します)、
変数は、Sought
あなたが答えたい実際のクエリ、原子のすなわち1の具体化の答えになりますtrue
かfalse
(そして多分unknown
あなたは、二値論理では十分に持っていた場合)、Info1, Info2, Info3
あなたが答えるために追加的な詳細になります何かの何か、なぜ場合がSought
ありますfalse
。
多くの場合、「なぜ」と尋ねたいのは、「モデル化された問題の解決策を見つけるのに失敗する」と「計算を終了するのに失敗する」という2つの異なる失敗の混同にかかっていることに注意してください。たとえば、maplist/3
2つのリストに適用してこれが機能することを期待したいが、誤って2つのリストの長さが異なる場合:取得しますfalse
-しかし、これはfalse
from計算(この場合はバグのため)であり、false
fromではありませんモデリング。重い利きであることはassertion/1
、ここに役立ちますが、これは独自の方法で醜いあることがあります。
実際、論理プログラミング部分のない命令型言語または関数型言語と比較してください。障害が発生した場合(おそらく例外?)、対応する「理由」は何でしょうか。不明です。
補遺
これは素晴らしい質問ですが、よく考えれば考えるほど、タスク固有の方法でしか答えられないと思います。論理プログラムを構造化してwhy
、why
実際にどのような情報を作成するかを決定する必要があります。戻る。それはタスク固有のものになります。「これまたはそれが真実である場合」の情報の欠落に関する何かであり、「これまたはそれ」は述語の専用セットから選択されます。もちろん、これは予想されます。命令型または関数型プログラムにその結果(またはその欠如)を説明させる一般的な方法がないためです。
これに関する論文(IEEEXploreとACMLibraryを含む)を少し探しましたが、次のことがわかりました。
- DL-Liteでの否定的なクエリ回答の説明についての推論。これは実際には記述論理用であり、アブダクション推論を使用します。
- WhyNot:Cycのツールについて説明している、大規模なナレッジベースで失敗したクエリのデバッグ。
- Flora-2のドキュメントもランダムに調べましたが、基本的には「デバッガーを使用してください」と書かれているようです。しかし、デバッグは単なるデバッグであり、説明ではありません。
もっとあるに違いない。
Prologの純粋な単調サブセット内にとどまっている限り、一般化を説明と見なすことができます。例を挙げると、blue/1
との正確な定義に応じて、次の一般化が考えられますdog/1
。
?-blue(foo)、*dog(foo)。 false。
この一般化では、目標全体dog(foo)
が削除されました。プレフィックス*
は、実際には:- op(950, fy, *). *(_).
Informallyのように定義された述語であり、上記は次のように読み取ることができます。このクエリが失敗するだけでなく、この一般化されたクエリも失敗します。青いfooはまったくありません(ない場合)。しかし、青いfooはあるかもしれませんが、青い犬はまったくいません...
?-blue(_X / *foo* /)、dog(_X / *foo* /)。 false。
これfoo
で、新しい変数に置き換えることでプログラムを一般化できました_X
。このようにして、2つの目標間の共有が維持されます。
を導入するなど、より多くのそのような一般化が可能dif/2
です。
この手法は、手動と自動の両方で適用できます。詳細については、サンプルセッションのコレクションがあります。GUPUを使用したPrologでの宣言型プログラム開発も参照してください。