【问题标题】:distances between vectors contained in a list in prologprolog中列表中包含的向量之间的距离
【发布时间】:2016-09-23 02:28:22
【问题描述】:

我对 prolog 很陌生,我正在尝试编写谓词

distance_all(List, List_of_distances).

其输入是包含向量坐标的列表列表:

输入 = [[1,2,3],[2,3,4],[1,7,3],[1,6,3]]

并输出一个列表,其中包含每个点到另一个点之间的所有距离。

我很想这样做,但是(抱歉伪代码不好)。 我真的不知道如何在 Prolog 中处理它!

  1. 距离(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 等等……

所以输出就像

输出 = [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 使用另一个谓词

【问题讨论】:

    标签: list vector prolog distance


    【解决方案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).
    

    【讨论】:

      【解决方案2】:

      如果你的 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].
      

      【讨论】:

        【解决方案3】:

        一个适度简短和基本的编写方式,没有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].
        

        【讨论】:

          【解决方案4】:

          你可以写:

          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).
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-08-22
            • 2013-10-03
            • 1970-01-01
            • 1970-01-01
            • 2020-09-03
            • 1970-01-01
            • 2018-08-07
            相关资源
            最近更新 更多