私はプロローグを使用しており、次のコードがあります。
:- use_module(library(clpb)).
fun(A, B, C, D, E) :-
sat(A + B + C + D),
sat(E),
labeling([A, B, C, D, E]).
すべてのソリューションを数えたい場合、どうすればよいですか? clpb で使用される sat_count(+Expr, -Count) について読んだことがありますが、エラーなしで実装することはできません
ソリューションの数をカウントする簡単な方法は、ソリューションを生成して、いくつあるかを確認することです。
たとえば、投稿したプログラムでは、findall/3
次のように使用して答えを得ることができます。
?- findall(., fun(A, B, C, D, E), Ls), 長さ (Ls, L)。 Ls = ['.', '.', '.', '.', '.', '.', '.', '.', '.'|...], L = 15 .
もちろん、これはスケールが悪く、より複雑なケースではすぐに実行不可能になります。それでも、この例では、この戦略で十分です。
sat_count/2
CLP(B) には、sat_count/2
すでに発見されているものがあります。
の主な利点はsat_count/2
、ソリューションを列挙せずに数えられることです。もちろん、非常に多くのソリューションがある場合、これは非常に便利です。
使用の秘訣sat_count/2
は、 を避け て、制約のみを投稿するlabeling/1
ような方法でコア リレーションを記述することです。
例えば:
楽しみ (A、B、C、D、E) :- sat(A + B + C + D), sat(E)。
これにはいくつかの利点があります。まず、クエリを実行できるようになりました。
?- 楽しい (A、B、C、D、E)。 E = 1、 sat(A=\= ... # ... # B#B*C#B*C*D#B*D#C#C*D#D).
この答えは、それE
が必然的に 1であることを示しています! を使用していた場合labeling/1
、これはやや見づらかったでしょう。
さらに、関連する制約をポストした後sat_count/2
、最初の引数として真に評価されなければならない CLP(B) 式を提供することにより、 を使用できます。
この場合、解にこれ以上制約を加えたくないので、最初の引数として、関心のある変数を含むトートロジーを指定します。これに適したイディオムは です +[1|Vs]
。
したがって、次を使用できます。
?- 楽しみ(A、B、C、D、E)、 sat_count( +[1,A,B,C,D,E] , カウント). E = 1、 カウント = 15、 sat(A=\= ... # ... # B#B*C#B*C*D#B*D#C#C*D#D).
この特定のケースでは、ソリューションの数が非常に少ないため、2 つのアプローチの違いはほとんどありません。
それでも、制約ロジック プログラムを作成するときの重要な一般原則を強調したいと思います。
解決策の実際の検索(および同様の述語 (組み込みおよび手動の両方))からコア関係を分離することをお勧めします。
labeling/1
この原則を守れば、拘束の終了と伝播を個別に調べることができます。
さらに、これにより、プログラムを再コンパイルすることなく、さまざまな検索戦略を試すことができます!