選択した制約ソルバーを使用してゼブラパズルを解く演習を行い、Prologclpfdライブラリを使用して試しました。
Prologでこの問題を解決する他の慣用的な方法があることを私は知っていますが、この質問は特にclpfd
パッケージに関するものです!
だから私が解決しようとしているパズルの特定のバリエーション(それらがたくさんあるとすると)はこれです:
5軒の家があります
- イギリス人は赤い家に住んでいます
- スウェーデン人は犬を飼っています
- デンマーク人はお茶を飲むのが好きです
- 緑の家は白い家に残されています
- 温室の所有者はコーヒーを飲みます
- ポールモールを吸う人は鳥を飼っています
- 真ん中の家でミルクを飲む
- 黄色い家の所有者はダンヒルを吸う
- ノルウェー人は最初の家に住んでいます
- マールボロ喫煙者は猫の飼い主の隣に住んでいます
- 馬の飼い主はダンヒルを吸う人の隣に住んでいます
- ウィンフィールド喫煙者はビールを飲むのが好きです
- ノルウェー人は青い家の隣に住んでいます
- ドイツ人はロスマンを吸う
- マールボロ喫煙者には、水を飲む隣人がいます
私は次のアプローチでそれを解決しようとしました:
家が持つことができる各属性は、「英国」、「犬」、「緑」などの変数としてモデル化されます。属性は、それらが発生する家に応じて、たとえば変数の場合、1〜5の値を取ることができます。 「犬」は値3を取り、犬は3番目の家に住んでいます。
このアプローチにより、次のような隣接制約のモデル化が容易になります。
def neighbor(X, Y) :-
(X #= Y-1) #\/ (X #= Y+1).
しかし、どういうわけか、clpfd
(IMO)問題が正しくモデル化されていても、パッケージは解決策を生成しません(Choco制約ソルバーでまったく同じモデルを使用し、結果は正しいものでした)。
完全なコードは次のとおりです。
:- use_module(library(clpfd)).
neighbor(X, Y) :-
(X #= (Y - 1)) #\/ (X #= (Y + 1)).
solve([British, Swedish, Danish, Norwegian, German], Fish) :-
Nationalities = [British, Swedish, Danish, Norwegian, German],
Colors = [Red, Green, Blue, White, Yellow],
Beverages = [Tea, Coffee, Milk, Beer, Water],
Cigarettes = [PallMall, Marlboro, Dunhill, Winfield, Rothmanns],
Pets = [Dog, Bird, Cat, Horse, Fish],
all_different(Nationalities),
all_different(Colors),
all_different(Beverages),
all_different(Cigarettes),
all_different(Pets),
Nationalities ins 1..5,
Colors ins 1..5,
Beverages ins 1..5,
Cigarettes ins 1..5,
Pets ins 1..5,
British #= Red, % Hint 1
Swedish #= Dog, % Hint 2
Danish #= Tea, % Hint 3
Green #= White - 1 , % Hint 4
Green #= Coffee, % Hint 5,
PallMall #= Bird, % Hint 6
Milk #= 3, % Hint 7
Yellow #= Dunhill, % Hint 8,
Norwegian #= 1, % Hint 9
neighbor(Marlboro, Cat), % Hint 10
neighbor(Horse, Dunhill), % Hint 11
Winfield #= Beer, % Hint 12
neighbor(Norwegian, Blue), % Hint 13
German #= Rothmanns, % Hint 14,
neighbor(Marlboro, Water). % Hint 15
内の概念を誤解しましたかclpfd
、それともここで明らかな何かを単に見逃していますか?それが役立つ場合は、ここでChocoとScalaを使用して実装された同じアプローチを見つけることができます。
編集:ソルバーが問題を解決できないと私が信じる理由は、変数の明確な値が出てこないためですが、「魚1..3 \/5」などの範囲のみが出てくるからです。