必须在Prolog中使用约束

时间:2018-12-22 04:12:00

标签: prolog constraints clpfd

我目前正试图仅使用clpfd序言库提供的约束来解决这个难题houses,这意味着我无法使用回溯功能!

基本上,我想找出应该建造哪些房屋,以便所有连接之间只有2个距离。

我的输入是一个像[[0,0],[0,3],[2,0],[3,0],[2,1],[3,1],[2,2],[3,3]]这样的坐标列表,解决方案是:

[
   [[0,0],[0,3]],
   [[2,0],[3,1]],
   [[2,1],[3,0]],
   [[2,2],[3,3]]
]

我当前的进度是这个:

connect(Houses):-
    %There are only 2 distances and they're different
    length(Distances, 2),
    all_distinct(Distances),

    %One connection per 2 houses (pairs) means half the number of houses as connections
    length(Houses, NHouses),
    NConnections #= NHouses // 2,
    length(Connections, NConnections),

    restrictDistances(Connections, Distances), %restrict every connection to have one of the two distances


    %All the houses must be connected
    append(Connections, ConnectedHouses),
    ensureAllConnected(Houses, ConnectedHouses), %table

    removeSymmetries(Connections), %avoid symmetries

    %flatten list and labeling
    append(ConnectedHouses, HousesCoordinates),
    labeling([], HousesCoordinates),
    write(Connections).

/*
    All distances of all connections are one of the two distances
    Distance is kept squared to keep it an integer i.e. dist(connection) = dist([[x1, y1], [x2, y2]]) = (x2-x1)^2 + (y2-y1)^2
*/
restrictDistances([], _).
restrictDistances([[[X1, Y1], [X2, Y2]]|Connections], Distances):-
    DiffX #= X2 - X1,
    DiffY #= Y2 - Y1,
    Dis #= DiffX * DiffX + DiffY * DiffY,
    % element(Idx, Distances, Dis), %element
    member(Dis, Distances), %element
    restrictDistances(Connections, Distances).

/*
    Ensures all houses are connected
*/
ensureAllConnected([], _).
ensureAllConnected([H|Houses], ConnectedHouses):-
    member(H, ConnectedHouses),
    % element(_, ConnectedHouses, H),
    ensureAllConnected(Houses, ConnectedHouses).

/*
    Remove symmetries and connection permutations in final result
*/
removeSymmetries([_]).
removeSymmetries([[[X1, _], [X2, _]], [[X3, Y3], [X4, Y4]]|Connections]):-
    X1 #=< X2,
    X1 #=< X3,
    X3 #=< X4,
    removeSymmetries([[[X3, Y3], [X4, Y4]]|Connections]).

最糟糕的部分是此代码有效,但是无法使用谓词member,因为它使用了回溯功能。是的,谓词element存在,但是我无法替换它,因为如果替换第一个,则输出是不同的;如果替换第二个,则会出现实例化错误。

1 个答案:

答案 0 :(得分:4)

严格来说,该问题未得到充分说明,因为存在多种距离,例如欧几里得距离和哈密顿距离。显然,预期的是欧几里得距离,否则您将为此实例获得多个解决方案。

对于这个难题,考虑使用全局约束编码哪些子任务会很有用。这里有一些提示:

  • 您需要找到一个匹配项-可以使用 assignment(Xs,Xs)
  • 您可以使用table/2(房屋,房屋,距离)关系进行编码。
  • 您可以使用nvalue/2进行约束 不同距离的数量。

这些是SICStus Prolog中的全局约束。