我对prolog很新,我正在尝试编写一个谓词
distance_all(List, List_of_distances).
其输入是列表组合向量colhordinates的列表:
INPUT = [[1,2,3],[2,3,4],[1,7,3],[1,6,3]]
并输出一个列表,其中包含每个点与另一个点之间的所有距离。
我试着这样做但是(对不起伪代码)。 我真的不知道如何在Prolog中处理它!
距离(point1,point2)= D_1-2
距离(point1,point3)= D_1-3
直到距离(point1,last_point)= D_1-last
距离(point2,point3)= D_2-3
距离(point2,point4)= D_2-4
距离(point2,last_point)= D_2-last 如此...
所以输出就像
OUTPUT = [D_1-2,D_1-3,.....,D_1-last,D_2-3,D_2-4,...... D_2-last ...]。
我已经实现了一个谓词
距离(Vector1,Vector2,D)。
其中D是Vector1和Vector2之间的欧几里德距离(2D,3D或其他)
另一个问题
如果我想记住产生最小距离的原始矢量怎么办?
例如
? - distance_all([[1,1],[1,2],[6,3],[8,2]],Lo)。 Lo = [1.0,5.385164807134504,7.0710678118654755,5.0990195135927845,7.0,2.23606797749979]
最小距离是1.0 ......但是在哪个向量之间?比方说A和B
我需要在A B
上使用另一个谓词答案 0 :(得分:1)
怎么样?
distance_all_h(_, [], [], []).
distance_all_h(_, [], [Hn | Tn], Lo) :-
distance_all_h(Hn, Tn, Tn, Lo).
distance_all_h(V, [Hi | Ti], Ln, [Ho | Lo]) :-
distance(V, Hi, Ho),
distance_all_h(V, Ti, Ln, Lo).
distance_all([], []).
distance_all([Hi | Ti], Lo) :-
distance_all_h(Hi, Ti, Ti, Lo).
当输入列表为空时,输出列表为空。
否则,想法是创建一个接收
的辅助子句(distance_all_h / 3)1)输入列表的头部
2)输入列表的尾部(用头部校准距离)
3)再次输入列表的尾部(当第二个参数被消耗时用以下头重启)
4)输出列表
---编辑---
如果我想记住原始载体的原因,该怎么办? 最小距离?
返回最小距离的修改解(distance_all
中的第三个参数)和与最小距离对应的矢量耦合列表(第四个参数)
考虑到更多的矢量对可以对应相同的最小距离。
% 1000000000 is intended as a number bigger than every distance
distance_all_h(_, [], [], [], 1000000000, []).
distance_all_h(_, [], [Hn | Tn], Lo, Md, ABl) :-
distance_all_h(Hn, Tn, Tn, Lo, Md, ABl).
distance_all_h(V, [Hi | Ti], Ln, [Ho | Lo], Ho, [[V, Hi]]) :-
distance(V, Hi, Ho),
distance_all_h(V, Ti, Ln, Lo, Dd, _),
Ho < Dd.
distance_all_h(V, [Hi | Ti], Ln, [Ho | Lo], Dd, ABl) :-
distance(V, Hi, Ho),
distance_all_h(V, Ti, Ln, Lo, Dd, ABl),
Ho > Dd.
distance_all_h(V, [Hi | Ti], Ln, [Ho | Lo], Ho, [[V, Hi] | ABt]) :-
distance(V, Hi, Ho),
distance_all_h(V, Ti, Ln, Lo, Ho, ABt).
distance_all([], [], 0, []).
distance_all([Hi | Ti], Lo, Md, ABl) :-
distance_all_h(Hi, Ti, Ti, Lo, Md, ABl).
答案 1 :(得分:1)
如果你的Prolog有图书馆(aggregate),你不介意效率,你可以做
distance_min(List, MinDist,P1,P2) :-
aggregate(min(D,(X,Y)), R^(select(X,List,R),member(Y,R), distance(X,Y,D)), min(MinDist,(P1,P2))).
distance([X1,X2],[Y1,Y2],D) :-
D is sqrt((Y1-X1)*(Y1-X1)+(Y2-X2)*(Y2-X2)).
distance([X1,X2,X3],[Y1,Y2,Y3],D) :-
D is sqrt((Y1-X1)*(Y1-X1)+(Y2-X2)*(Y2-X2)+(Y3-X3)*(Y3-X3)).
?- distance_min([[1,1],[1,2],[6,3],[8,2]],D,X,Y).
D = 1.0,
X = [1, 1],
Y = [1, 2].
答案 2 :(得分:1)
在没有findall
和aggregate
的情况下编写它的中等简短基本方法就是这样的。
首先,一个谓词找到两个坐标列表之间的欧几里德距离:
d([P|Ps], [Q|Qs], D) :-
sum_diff_sq(Ps, Qs, (P-Q)^2, R),
D is sqrt(R).
sum_diff_sq([], [], V, V).
sum_diff_sq([P|Ps], [Q|Qs], V0, V+V0) :-
sum_diff_sq(Ps, Qs, (P-Q)^2, V).
这将计算一对坐标之间的距离,每个坐标都是一个数字列表。
?- d([1], [1], D).
D = 0.0.
?- d([1], [2], D).
D = 1.0.
?- d([1,1], [2,2], D).
D = 1.4142135623730951.
?- d([1,1,1], [2,2,2], D).
D = 1.7320508075688772.
?- d([1,1,1,1], [2,2,2,2], D).
D = 2.0.
然后,计算所有可能的距离:
points_distances([], []).
points_distances([P|Ps], Ds) :-
rest_distances(Ps, P, Ds, Ds0),
points_distances(Ps, Ds0).
points_distances/2
以递归方式列出头部与列表尾部中每个坐标之间的距离(因此,每对之间的距离将在结果中)。
rest_distances([], _, Back, Back).
rest_distances([P|Ps], X, [D|Ds], Back) :-
d(P, X, D),
rest_distances(Ps, X, Ds, Back).
这只是计算坐标列表和坐标之间的距离。结果是差异列表。
要使用它:
?- points_distances([[1,1],[1,2],[6,3],[8,2]], D).
D = [1.0, 5.385164807134504, 7.0710678118654755, 5.0990195135927845, 7.0, 2.23606797749979].
?- points_distances([[1,2,3],[2,3,4],[1,7,3],[1,6,3]], D).
D = [1.7320508075688772, 5.0, 4.0, 4.242640687119285, 3.3166247903554, 1.0].
如果您愿意,可以“保存”哪一对坐标彼此相距一段距离。例如,将rest_distances/4
的第二个子句的头部改为:
rest_distances([P|Ps], X, [D|Ds], Back)
为:
rest_distances([P|Ps], X, [D-pq(X,P)|Ds], Back)
现在,在重新加载程序之后,您可以对points_distances/2
的结果进行排序并获取其中的第一个元素,就像在另一个答案中一样:
?- points_distances( [[1,2,3],[2,3,4],[1,7,3],[1,6,3]] , D),
keysort(D, [Min_dist-pq(P,Q)|_]).
D = [1.7320508075688772-pq([1, 2, 3], [2, 3, 4]),
5.0-pq([1, 2, 3], [1, 7, 3]),
4.0-pq([1, 2, 3], [1, 6, 3]),
4.242640687119285-pq([2, 3, 4], [1, 7, 3]),
3.3166247903554-pq([2, 3|...], [1, 6|...]),
1.0-pq([1|...], [1|...])],
Min_dist = 1.0,
P = [1, 7, 3],
Q = [1, 6, 3].
答案 3 :(得分:0)
你可以写:
distance_all(Input_list,Output_list):-
findall(L,combinations(Input_list,L),List),
find_distances(List,Output_list).
combinations([],[]).
combinations(Lin,[Vector1,Vector2]):-choose(Vector1,Lin,L),choose(Vector2,L,_).
choose(H,[H|T],T).
choose(H1,[_|T],T1):-choose(H1,T,T1).
find_distances([],[]).
find_distances([[Vector1,Vector2]|T],[D|T1]):-
distance(Vector1,Vector2,D),
find_distances(T,T1).
更新
对于你可以改变的第二个问题:
find_distances([],[]).
find_distances([[Vector1,Vector2]|T],[D-[Vector1,Vector2]|T1]):-
distance(Vector1,Vector2,D),
find_distances(T,T1).
因此,不会返回距离列表,而是对其进行编码,以便每个元素都采用以下形式:D-[Vector-n,Vector-m]
要查找最小距离,请使用keysort / 2:
distance_all(Input_list,Output_list):-
findall(L,combinations(Input_list,L),List),
find_distances(List,L1),
keysort(L1,L2),
find_distances2(L2,Output_list).
Keysort对列表进行排序,以便第一个元素具有min d,您可以通过添加以上内容来获取它,例如:L1=[Dmin-[Vector1,Vector2]|_]
。
由于列表L1具有上述形式,为了获得第一个问题的输出列表,您可以通过写入来简单地保留输出列表中的距离:
find_distances([],[]).
find_distances([D-[Vector1,Vector2]|T],[D|T1]):-find_distances(T,T1).