如何解决在Prolog中实例化整数变量
一栋公寓楼有八层。五楼有 唯一的有两间卧室的公寓。理发师太太有孩子了,不能 电梯出故障时,将婴儿车上楼。长老夫妇 他们已经退休,也发现攀登困难。阿切尔先生喜欢 顶层的和平与安宁。库克夫人和她 女儿需要一间两居室公寓。胡珀先生和太太住在先生的正下方 射手。库克太太住在加德纳先生之上,而在Driver太太之下。先生和 费舍尔太太比埃尔德太太和太太高。
从本质上讲,我将其视为一组代数整数关系,因此我想在[1..8]
中将每个实体实例化为整数并声明已知的值和关系。
floors([Archer,Barber,Cook,Driver,Elder,Fisher,Gardner,Hooper]) :-
Archer=8,Cook=5,Hooper is Archer-1,Barber<4,Elder<4,Fisher>Elder,Cook>Gardner,Cook<Driver.
?- floors([A,B,C,D,E,F,G,H]).
但是我在第5行(第一个不等式)得到ERROR:Arguments are not sufficiently instantiated
。
我尝试添加
Vars = [Archer,Hooper],Vars ins 1..8,
但是随后我得到了模糊的ERROR: UnkNown procedure: floors/1 (DWIM Could not correct goal)
我确定我缺少明显的东西。感谢所有帮助。
解决方法
我喜欢从结构上看待这些难题。我将从这个开始:
[floor(1,[_]),floor(2,floor(3,floor(4,floor(5,[_,_]),floor(6,floor(7,floor(8,[_])]
请注意,我使用了一系列匿名变量来表示每个楼层的卧室。 5楼是仅有的两间卧室。
现在我需要定义一堆辅助谓词。
onfloor(N,X,Floors) :-
member(floor(N,Xs),Floors),member(X,Xs).
justbelow(X,Y,[floor(_,floor(_,Ys)|_]) :-
member(X,member(Y,Ys).
justbelow(X,[_|T]) :-
justbelow(X,T).
below(X,Floors) :-
append(Lower,Upper,onfloor(_,Lower),Upper).
lower3([A,B,C|_],[A,C]).
top([T],[T]).
top([_|T],X) :- top(T,X).
现在,我的sovle(Floors)
谓词是每个线索的简单翻译:
solve(Floors) :-
Floors = [floor(1,[_])],lower3(Floors,barber,elder,top(Floors,Top),archer,onfloor(Floor,cook,daughter,justbelow(hooper,below(gardener,below(cook,driver,below(elder,fisher,true.
当我使用?- solve(Floors).
运行此命令时,会得到以下信息:
floor(1,[barber]),[elder]),[gardener]),[fisher]),[cook,daughter]),[driver]),[hooper]),[archer])
,
我假设使用整数而不是FloorOne
,FloorTwo
等会更简单。但是,在Prolog中对整数进行推理需要一个称为CLP(FD)(或CLP(ℤ))的特殊库,该库代表有限域约束逻辑编程,其工作原理与关于事实的推理。 (感谢false的技巧-有关更多信息,请参见here。)在SWI-Prolog中,必须显式导入。在我的示例中,可能性空间是居民和楼层号的所有置换,而事实限制了允许置换的空间。
% import a constraint-solving library
% note that the syntax for clpfd has a hash sign (#=,#<,etc)
:- use_module(library(clpfd)).
floors([Archer,Barber,Cook,Driver,Elder,Fisher,Gardner,Hooper]) :-
% possible facts are all the permutations
permutation( [Archer,Hooper],[1,2,3,4,5,6,7,8]),% clues
Archer #= 8,Cook #= 5,Hooper is Archer - 1,Barber #= 1,Elder #= 2,Fisher #> Elder,Cook #> Gardner,Cook #< Driver.
?- floors([A,C,D,E,F,G,H]).
A = 8,B = 1,C = 5,D = 6,E = 2,F = 3,G = 4,H = 7 ;
A = 8,F = 4,G = 3,H = 7
,
原始代码中出现错误消息的原因如下:当像<
中使用Barber<4
之类的运算符时,变量Barber
必须已经实例化。 (考虑另一种选择,即序言应该为Barber
选择一个值以满足目标'Barber Barber的可能性将是巨大的。)没有目标,但是,在Barber<4
之前,强制序言实例化Barber
。
您已经通过添加目标解决了自己的问题
permutation([Archer,8])
因为此目标迫使每个变量Archer
.. Hooper
用一个数字实例化。使用这种方法,您可以只使用原始的运算符而不使用'#',因为不再有关于实例化变量不足的原始错误消息。
在实例化整数变量时,还有另一个谓词可能对您有帮助:between/3
,可以在您的代码中按以下方式使用:... between(1,8,Barber),Barber<4,
...。目标between(1,Barber)
将确保在考虑目标Barber
之前,使用1..8
中的值实例化Barber<4
。
当然,在这种情况下,您可以将两个目标between(1,Barber<4
组合为一个目标between(1,Barber)
。因此,也可以通过以下方式用between/3
代替permutation/2
来实现完整的示例:
:- use_module(library(clpfd)).
floors([Archer,Hooper]) :-
Archer=8,Cook=5,Hooper is Archer-1,between(1,Elder),AboveElder is Elder+1,between(AboveElder,Fisher),BelowCook is Cook-1,BelowCook,Gardner),AboveCook is Cook+1,between(AboveCook,Driver),all_different([Archer,Hooper]).
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。