微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在Prolog中实例化整数变量

如何解决在Prolog中实例化整数变量

作为我的第一个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])
,

我假设使用整数而不是FloorOneFloorTwo等会更简单。但是,在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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?