我正在尝试找出Prolog
中复杂关系的正确事实表示形式。
2行中有6个帐篷,表示为:
tent(color, orientation, place, mans name, womans name, surename, car)
一个叫彼得的人在 帐篷不在伊恩的帐篷前
。
彼得的妻子叫 不是安吗?
编辑:
哦,我在定义“前面”时并不清楚。在这种情况下,这不是常规的事情,我将尝试向您展示:
FOREST tent1 tent2 tent3 RIVER
FOREST tent4 tent5 tent6 RIVER
意思是tent1在tent4的前面。然后tent1的方向为“ NORTH”,位置为“ FOREST”。不在帐篷前面的帐篷将是帐篷5(方向“ SOUTH”,位置“ MIDDLE”)。
带有dif(Wife,'Ann')的东西很好用,谢谢。
我咨询了教授,我们同意,对于这项任务,我确实不需要事实否定,其目的是做出正确的决定,而忽略不必要的事实。
无论如何,感谢您的帮助。
答案 0 :(得分:0)
如果我们假设第三个参数“ place”是一个序数,并且“ X在Y前面”表示X
tent(_, _, Place_Peter, 'Peter', _, _, _),
tent(_, _, Place_Ian, 'Ian', _, _, _),
Place_Peter > Place_Ian
但是当然也可能是“ X是不位于Y前面的位置”表示
succ(Y0, Y),
X =\= Y0
我不确定。
第二个是:
tent(_, _, _, 'Peter', Wife, _, _),
dif(Wife, 'Ann')
但是请注意,这些不是事实,这些查询将基于表tent/7
的内容提供(或不提供)解决方案,或者成功或失败。
在两种情况下,我都对表中不同列的数据类型进行了一些假设。
答案 1 :(得分:0)
我对这个带有arity 7的帐篷谓词不满意。
该基本代码如何。我花了一些时间来恢复丢失的Prolog知识。我正在使用“否定失败”来确保遵守约束。它可以在SWISH中使用。
使用类似Prolog的语言来满足约束条件的满足(ECLiPSe或ASP/Potassco可能更容易编码),但我从未尝试这样做。)
写下来,事实证明
所以:
% Create tents and indicate their positions, too. These are basically "tent names"
% in the form of a literal where the name carries the x and y position.
% We won't need this but "in front of" means: in_front_of(tent(X,1),tent(X,2)).
tent(1,1).
tent(2,1).
tent(3,1).
tent(1,2).
tent(2,2).
tent(3,2).
% Create colors (just as an example)
color(blue).
color(red).
color(green).
color(white).
color(black).
color(mauve).
% Create cars (just as an example)
car(mazda).
car(ford).
car(renault).
car(tesla).
car(skoda).
car(unimog).
% Create surnames (just as an example)
surname(skywalker).
surname(olsndot).
surname(oneagle).
% Create names (just as an example) and give the traditional sex
name(peter,male).
name(marvin,male).
name(ian,male).
name(sheila,female).
name(mary,female).
name(ann,female).
% Give traditional family pair. male is first element in pair.
pair(Nm,Nf,Sn) :- name(Nm,male),name(Nf,female),surname(Sn).
% Our logic universe is now filled with floating stuff: tents, colors, cars, names.
% A "solution" consists in linking these together into a consistent whole respecting
% all the constraints given by the "zebra puzzle"
% A "solution" is a data structure like any other. We choose to have a big list with
% literals. Every literal expresses an assignment between a tent and an attribute:
%
% attribute_nameΔ(tent_x,tent_y,attribute_value)
%
% Other representations are possible. (Why the "Δ"? Because I like it!)
% We need a list of all tents over which to recurse/induct when generating a "solution".
% ... bagof provides!
% This could possibly be done by directly backtracking over the tent/2 predicate.
all_tents(LTs) :- bagof(tent(X,Y), tent(X,Y), LTs).
% We need a list of all pairs over which to recurse/induct when generating a "solution".
% ... bagof provides!
% This could possibly be done by directly backtracking over the pair/2 predicate.
all_pairs(Ps) :- bagof(pair(Nm,Nf,Sn), pair(Nm,Nf,Sn), Ps).
% Select possible assignments of "color<->tent", adding the possible assignments to
% an existing list of selected assignments.
%
% assign_colors(List-of-Tents-to-recurse-over,List-with-Assignments(In),List-with-more-Assignments(Out)).
assign_colors([],Bounce,Bounce).
assign_colors([tent(X,Y)|Ts], Acc, Out) :-
color(Co),
\+is_color_used(Acc,Co),
assign_colors(Ts, [colorΔ(X,Y,Co)|Acc], Out).
is_color_used([colorΔ(_,_,Co)|_],Co) :- !. % cut to make this deterministic
is_color_used([_|R],Co) :- is_color_used(R,Co).
% Select possible assignment of "car<->tent", adding the possible assignments to
% an existing list of selected assignments.
%
% assign_cars(List-of-Tents-to-recurse-over,List-with-Assignments(In),List-with-more-Assignments(Out)).
assign_cars([],Bounce,Bounce).
assign_cars([tent(X,Y)|Ts], Acc, Out) :-
car(Ca),
\+is_car_used(Acc,Ca),
assign_cars(Ts, [carΔ(X,Y,Ca)|Acc], Out).
is_car_used([carΔ(_,_,Ca)|_],Ca) :- !. % cut to make this deterministic
is_car_used([_|R],Ca) :- is_car_used(R,Ca).
% Select possible assignment of "name<->tent", adding the possible assignments to
% an existing list of selected assignments.
%
% In this case, we have to check additional constraints when choosing a possible assignment:
%
% 1) A name may only be used once
% 2) Ian and Peter's are not in front of each other
%
% assign_names(List-of-Tents-to-recurse-over,List-with-Assignments(In),List-with-more-Assignments(Out)).
assign_names([],Bounce,Bounce).
assign_names([tent(X,Y)|Ts], Acc, Out) :-
name(Na,_),
\+is_name_used(Acc,Na),
\+is_ian_in_front_of_peter([nameΔ(X,Y,Na)|Acc]),
assign_names(Ts, [nameΔ(X,Y,Na)|Acc], Out).
is_name_used([nameΔ(_,_,Na)|_],Na) :- !. % cut to make this deterministic
is_name_used([_|R],Na) :- is_name_used(R,Na).
is_ian_in_front_of_peter(S) :-
pick_name(S,nameΔ(X,_,_),peter),
pick_name(S,nameΔ(X,_,_),ian),
write("IAN vs PETER confirmed!\n").
pick_name([nameΔ(X,Y,Name)|_],nameΔ(X,Y,Name),Name).
pick_name([_|R],Found,Name) :- pick_name(R,Found,Name).
% Select possible pairs, adding the possible pairs to an existing list of selected pairs (the same
% as the list of selected assignments). The nature of this selection is **different than the two
% others** as we backtrack over the list of pairs, instead of just recursing over it. Hence,
% three clauses^and a verification that we have 3 pairs in the end.
%
% In this case, we have to check additional constraints when choosing a possible assignment:
%
% 1) Peter's wife name is not Ann
%
% assign_pairs(List-of-Pairs-to-recurse-over,List-with-Assignments(In),List-with-more-Assignments(Out)).
assign_pairs([],Bounce,Bounce) :- count_pairs(Bounce,3). % hardcoded number of surnames; we need 3 pairs!
assign_pairs([pair(Nm,Nf,Sn)|Ps], Acc, Out) :-
\+is_any_name_already_paired(Acc,Nm,Nf,Sn),
\+is_peter_married_ann([pairΔ(Nm,Nf,Sn)|Acc]),
assign_pairs(Ps, [pairΔ(Nm,Nf,Sn)|Acc], Out).
assign_pairs([_|Ps], Acc, Out) :- assign_pairs(Ps, Acc, Out).
is_any_name_already_paired([pairΔ(N,_,_)|_],N,_,_) :- !. % cut to make this deterministic
is_any_name_already_paired([pairΔ(_,N,_)|_],_,N,_) :- !. % cut to make this deterministic
is_any_name_already_paired([pairΔ(_,_,S)|_],_,_,S) :- !. % cut to make this deterministic
is_any_name_already_paired([_|R],Nm,Nf,Sn) :- is_any_name_already_paired(R,Nm,Nf,Sn).
count_pairs([],0).
count_pairs([pairΔ(_,_,_)|R],C) :- !,count_pairs(R,C2), C is C2+1. % red cut
count_pairs([_|R],C) :- count_pairs(R,C).
% this would be more advantageously done by eliminating that pair in the list of
% possible pairs; but leave it here to make the solution less "a bag of special cases"
is_peter_married_ann([pairΔ(peter,ann,_)|_]) :- !. % cut to make this deterministic
is_peter_married_ann([_|R]) :- is_peter_married_ann(R).
% Find a consistent solution by adding assignements for the various attributes
% while checking constraints
solution(SOut) :-
all_tents(Tents),
all_pairs(Pairs),
assign_colors(Tents,[],S1),
assign_cars(Tents,S1,S2),
assign_names(Tents,S2,S3),
assign_pairs(Pairs,S3,SOut).
运行
?- solution(SOut).
SOut = [pairΔ(ian, ann, oneagle), pairΔ(marvin, mary, olsndot),
pairΔ(peter, sheila, skywalker), nameΔ(3, 2, ann), nameΔ(2, 2, mary),
nameΔ(1, 2, sheila), nameΔ(3, 1, ian), nameΔ(2, 1, marvin),
nameΔ(1, 1, peter), carΔ(3, 2, unimog), carΔ(2, 2, skoda),
carΔ(1, 2, tesla), carΔ(3, 1, renault), carΔ(2, 1, ford),
carΔ(1, 1, mazda), colorΔ(3, 2, mauve), colorΔ(2, 2, black),
colorΔ(1, 2, white), colorΔ(3, 1, green), colorΔ(2, 1, red),
colorΔ(1, 1, blue)]