3

我帖子末尾的代码应该回答以下难题:

布朗、克拉克、琼斯和史密斯是 4 位重要的公民,他们以建筑师、银行家、医生和律师的身份为社区服务,尽管不一定分别。布朗比琼斯更保守,但比史密斯更自由,他的高尔夫球手比比他年轻的男人更好,收入也比比克拉克大的男人高。比建筑师挣得多的银行家既不是最年轻的,也不是最年长的。

打高尔夫球比律师差的医生,也没有建筑师那么保守。不出所料,最年长的人最保守,收入最高,最年轻的人是最好的高尔夫球手。每个人的职业是什么?

代码:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% We represent each "person" with a six-tuple of the form
%
% [ name , profession , age , income , politics , golf ranking ]
%
% where name is either brown, clark, jones, or smith
%       profession is either banker, lawyer, doctor, or architect
%       age is a range 1 .. 4, with 1 being the youngest and 4 the oldest
%       income is a range 1 .. 4, with 1 being the least and 4 the most
%       politics is a range 1 .. 4, with 1 being conservative, 4 liberal
%       golf ranking is a range 1 .. 4, 1 for the best rank, 4 for the worst
%
:- use_module(library(clpfd)).
solutions(L) :- L = [ [brown, _, _, _, _, _], [clark, _, _, _, _, _],
                      [jones, _, _, _, _, _], [smith, _, _, _, _, _] ],
                clue1(L),
                clue2(L),
                clue3(L),
                clue4(L),
                constrained_profession(L),
                constrained_age(L),
                constrained_income(L),
                constrained_politics(L),
                constrained_golf_rank(L).

%
% clue #1
% brown, who is more conservateive than jones but
% more liberal than smith, is a better golfer than
% the men who are younger than he is and has a larger
% income than the men who are older than clark
%

clue1(L) :- member(P1,L), member(P2,L), member(P3,L),
            P1 = [brown, _, A1, _, L1, G1],
            P2 = [jones, _, _, _, L2, _],
            P3 = [smith, _, _, _, L3, _],
            liberaler( P2, P1 ),
            liberaler( P1, P3 ),
            not( clue1_helper_a(L) ),
            not( clue1_helper_b(L) ).

% for all men younger than brown he is a better golfer ===>
% it is not the case that there exists a man younger than brown
% such that brown is not a better golfer than him.
% The "is not the case" is taken care of in clue1.

clue1_helper_a(L) :- member(P1,L), P1 = [brown, _, A1, _, L1, G1],
                     member(PU,L), PU = [_, _, AU, _, _, GU],
                     younger(PU,P1),
                     not(golfier(P1, PU)).

% for all men older than clark, brown makes more money than they do ===>
% it is not the case that there exists a man older than clark such that
% brown does not make more money than him.
% The "is not the case" is taken care of in clue1.

clue1_helper_b(L) :- member(P1,L), P1 = [brown, _, _, _, _, _],
                     member(P2,L), P2 = [clark, _, _, _, _, _],
                     member(PU,L), PU = [_, _, _, _, _, _],
                     younger(P2,PU),
                     not(richer(P1, PU)).

%
% clue #2
% the banker, who earns more than the archiect, is
% neither the youngest nor the oldest
%

clue2(L) :- member(P1,L), member(P2,L),
            P1 = [_, banker, A1, I1, _, _],
            P2 = [_, architect, _, I2, _, _],
            richer(P1,P2),
            not( A1 = 1 ),
            not( A1 = 4 ).

%
% clue #3
% the doctor, who is a pooer golfer than the lawyer, is
% less conservative than the architect. 
%

clue3(L) :- member(P1, L), member(P2, L), member(P3,L),
            P1 = [_,doctor, _, _, L1, G1],
            P2 = [_,lawyer, _, _, _, G2],
            P3 = [_,architect, _, _, L3, _],
            golfier(P2,P1),
            liberaler(P1,P3).

%
% clue #4
% as might be expected, the oldest man is the most
% conservative and has the largest income, and the 
% youngest man is the best golfer.

clue4(L) :- member(P1,L), member(P2,L),
            P1 = [_, _, 4, 4, 1, _],
            P2 = [_, _, 1, _, _, 1].

%
% relations
%

younger(X,Y) :- X = [_, _, AX, _, _, _], Y = [_, _, AY, _, _, _], AX #< AY.

liberaler(X,Y) :- X = [_, _, _, _, LX, _], Y = [_, _, _, _, LY, _], LX #> LY.

golfier(X,Y) :- X = [_, _, _, _, _, GX], Y = [_, _, _, _, _, GY], GX #< GY.

richer(X,Y) :- X = [_, _, _, IX, _, _], Y = [_, _, _, IY, _, _], IX #> IY.

%
% constraints
%

constrained_profession(L) :-
    member(P1,L), member(P2,L), member(P3,L), member(P4,L),
    P1 = [_, banker, _, _, _, _],
    P2 = [_, lawyer, _, _, _, _],
    P3 = [_, doctor, _, _, _, _],
    P4 = [_, architect, _, _, _, _].

constrained_age(L) :-
    member(P1,L), member(P2,L), member(P3,L), member(P4,L),
    P1 = [_, _, 1, _, _, _],
    P2 = [_, _, 2, _, _, _],
    P3 = [_, _, 3, _, _, _],
    P4 = [_, _, 4, _, _, _].

constrained_income(L) :-
    member(P1,L), member(P2,L), member(P3,L), member(P4,L),
    P1 = [_, _, _, 1, _, _],
    P2 = [_, _, _, 2, _, _],
    P3 = [_, _, _, 3, _, _],
    P4 = [_, _, _, 4, _, _].

constrained_politics(L) :-
    member(P1,L), member(P2,L), member(P3,L), member(P4,L),
    P1 = [_, _, _, _, 1, _],
    P2 = [_, _, _, _, 2, _],
    P3 = [_, _, _, _, 3, _],
    P4 = [_, _, _, _, 4, _].

constrained_golf_rank(L) :-
    member(P1,L), member(P2,L), member(P3,L), member(P4,L),
    P1 = [_, _, _, _, _, 1],
    P2 = [_, _, _, _, _, 2],
    P3 = [_, _, _, _, _, 3],
    P4 = [_, _, _, _, _, 4].

% end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

但是,当我运行它时,它返回 false!

?- solutions(L).
false.

有人可以帮我吗?

4

1 回答 1

3

我不会为您解决整个问题,但我想解释一种通用方法,可以让您快速缩小此类问题的范围。

回顾一下,我们有以下主要谓词:

解决方案(L):-
        L = [[棕色,_,_,_,_,_],[克拉克,_,_,_,_,_],
              [琼斯,_,_,_,_,_],[史密斯,_,_,_,_,_]],
        线索1(L),
        线索2(L),
        线索3(L),
        线索4(L),
        受约束的职业(L),
        受约束的年龄(L),
        受约束的收入(L),
        受约束的政治(L),
        受约束的高尔夫排名(L)。

即使对于最一般的查询,它也会意外失败,其中所有参数都是新变量:

?- 解决方案(L)。
的。

为什么会失败?与GUPU 一样,我将使用,通过使用以下定义来概括目标:

:- op(950, fy, *).
*_.

如果您将其包含在您的程序中,则可以(*)/1在目标前面使用“删除它们”。这最多可以使生成的程序更通用

例如,现在让我们概括掉所有目标(我使用删除文本来表示目标不再限制解决方案,因为它被概括掉了):

解决方案(L):-
         *  L = [[棕色,_,_,_,_,_],[克拉克,_,_,_,_,_],[琼斯,_,_,_,_,_ ], [smith, _, _, _, _, _] ], 
        * 线索 1(L), 
        * 线索 2(L), 
        * 线索 3(L),
        ​​ * 线索 4(L), 
        * 受约束的职业(L), 
        *受约束的年龄 ( L), 
        *  constrained_income(L), 
        *  constrained_politics(L), 
        *  constrained_golf_rank(L)。

现在查询成功

?- 解决方案(L)。
真的

但是,该程序现在显然过于笼统了。现在重点:我们可以有选择地重新引入目标(= 约束)来定位导致程序意外失败的错误。

例如,我选择第一个目标和clue2/1目标,然后删除(*)/1它们前面的:

解决方案(L):-
         L = [[棕色,_,_,_,_,_],[克拉克,_,_,_,_,_],
              [琼斯,_,_,_,_,_],[史密斯,_,_,_,_,_]], 
        *线索1(L),
        线索2(L), 
        *线索3(L), 
        *线索4(L ), 
        * constrained_profession(L), 
        * constrained_age(L), 
        * constrained_income(L), 
        * constrained_politics(L), 
        * constrained_golf_rank(L)。

现在,我们又得到了:

?- 解决方案(L)。
的。

由此,你知道clue2/1 肯定包含一个错误。这是因为任何进一步的目标最多只能使谓词更加具体,并且它们无法消除该目标的失败。

让我们重新考虑 的定义clue2/1

线索2(L):-成员(P1,L),成员(P2,L),
            P1 = [_, 庄家, A1, I1, _, _],
            P2 = [_,建筑师,_,I2,_,_],
            更丰富(P1,P2),
            不是(A1 = 1),
            不是(A1 = 4)。

这里的错误在于使用非单调谓词not/1,在这种情况下会错误地删除解决方案。检查一下,即使是非常一般的查询,我们也没有从这个谓词中得到答案:

?-长度(Ls,4),线索2(Ls)。
的。

该怎么办?回答:

代替not/1or (\+)/1使用约束来表达不等式。

约束是真实的关系,可以在各个方向使用,即使它的部分或全部参数是自由变量!

在您的情况下,使用dif/2或在这种情况下更好的是使用CLP(FD) 约束 (#\=)/2来表示两个整数是不同的:

线索2(L):-
        成员(P1,L),成员(P2,L),
        P1 = [_, 庄家, A1, I1, _, _],
        P2 = [_,建筑师,_,I2,_,_],
        更丰富(P1,P2),
        A1 #\= 1,
        A1 #\= 4

通过这个简单的更改,谓词现在产生答案,并且缩小程序对于最一般的查询成功。

通过系统地应用这种声明性调试技术,您可以纠正其他谓词中的剩余错误。我把它留作练习。

于 2016-11-11T07:22:01.100 回答