如何将最小距离返回到某一点?

时间:2012-08-29 22:53:13

标签: lambda prolog

我正在尝试解决一个问题,即我有一个坐标列表,并希望得到最接近一个点。

实施例: 我得到了坐标[[1,2],[3,4],[10,3]],并希望得到距离原点[0,0]最近的点。 [1,2]在这个例子中。

我写了这个:

list_min([H|T], Min):-
   list_min(T, H, Min).

list_min([], H, H).

list_min([L|Ls], Min0, Min) :-
    point(P),
    distance(Min0,P,D0),
    distance(L,P,D1),
    Lower is min(D0, D1),
    assert(candidate(Min0)),
    assert(candidate(L)),
    forall(candidate(X),distance(X,P,Lower)),
    retractall(candidate(_)),
    list_min(Ls, X, Min).

distance(A,B,D):-
    A = [A1,A2],
    B = [B1,B2],
    Y is B2 - A2,
    X is B1 - A1,
    D is sqrt(X*X + Y*Y).

然而,看起来它总是在forall线上失败。我做错了什么?有没有更好的方法来做到这一点?

4 个答案:

答案 0 :(得分:2)

您可以使用库(aggregate):

distance_min(L, MinXY) :-
    distance_min(L, 0, 0, MinXY).
distance_min(L, X0, Y0, MinXY) :-
    aggregate(min(D, [X,Y]),
              (member([X,Y], L), D is sqrt((X-X0)^2+(Y-Y0)^2)),
              MinXY).

试验:

?- distance_min([[1,2],[3,4],[10,3]], R).
R = min(2.23606797749979, [1, 2]).

修改

....
assert(candidate(Min0)),
assert(candidate(L)),
forall(candidate(X),distance(X,P,Lower)),
retractall(candidate(_)),
...

我没有评论你的代码,但现在这里有一个暗示:这些线条真的很糟糕,而且真的没用。承认forall / 2成功,您期望得到什么结果?

无论如何,forall / 2失败是因为Lower它已经从上面的语句(Lower is min(D0, D1))实例化了,因此距离/ 3将在D不匹配的地方失败。

答案 1 :(得分:2)

使用SWI-Prolog,您还可以使用功能样式:

:- use_module(library(lambda)).


point([0,0]). % The reference point

% Entry point predicate
% First parameter : a list of points
% Second parameter (result) : the point closest to the reference point
list_min([H|Tail], Min) :-
  point(Reference),
  distance(H, Reference, D),

  foldl(\X^Y^Z^(distance(X, Reference, DX),
                Y = [Cur_D, _Cur_P],
                (   DX < Cur_D
                ->  Z = [DX, X]
                ;   Z = Y)),
    Tail, [D, H], Min).


distance(A,B,D):- % copy-pasted from your version
  A = [A1,A2],
  B = [B1,B2],
  Y is B2 - A2,
  X is B1 - A1,
  D is sqrt(X*X + Y*Y).

答案 2 :(得分:1)

我提出了一个没有建议的库或四叉树的解决方案,我保留在基本的序言中(我在SWI中写道)。

如果我正确理解您的问题,实际上不需要assert / retract / forall。我假设point(P)说P是我们计算距离的唯一定义的参考点,但它有点奇怪(我会将它用作参数,以确保它是唯一的)。

point([0,0]). % The reference point

% Entry point predicate
% First parameter : a list of points
% Second parameter (result) : the point closest to the reference point
list_min([H|Tail], Min) :-
  point(Reference),
  distance(H, Reference, D),
  list_min(Tail, H, D, Min).

% First parameter : the list remaining to consider
% Second parameter : the closest point, at this point of the computation
% Third parameter : the corresponding (minimum) distance, at this point of the computation
% Fourth parameter : the result (one point, to be bound at the end of computation)
list_min([], CurrentMin, _, CurrentMin). % Stop condition : list processed
list_min([Candidate|Tail], CurrentMin, CurrentDist, Min) :-
  point(Reference),
  distance(Candidate, Reference, CandidateDist),
  (
   % if the new candidate is not better, keep the current candidate
   CurrentDist < CandidateDist ->
   list_min(Tail, CurrentMin, CurrentDist, Min)
  ;
   % if the new candidate is better, take it as the current candidate
   list_min(Tail, Candidate, CandidateDist, Min) 
   ).

distance(A,B,D):- % copy-pasted from your version
  A = [A1,A2],
  B = [B1,B2],
  Y is B2 - A2,
  X is B1 - A1,
  D is sqrt(X*X + Y*Y).

答案 3 :(得分:0)

使用四叉树进行2D http://en.wikipedia.org/wiki/Quadtree