试图获得给定路径的成本

时间:2016-05-09 13:44:38

标签: path prolog clpfd prolog-dif

我是Prolog的新手

我在Prolog中尝试一条规则,它给出了从节点到另一个节点的给定路径,并且还给出了路径的总权重。

我已成功获得路径的所有边缘,但我无法显示路径的重量。我对它进行了重新划分,可以看出变量S加起来路径的整个权重,但在返回的路上,删除所有元素。我的想法是将总重量加到P。

代码:

notIn(A,[]).
notIn(A,[H|T]):- A\==H,notIn(A,T).

path(X,X,_,[], S, P).
path(X,Y,[X|Cs], S, P) :-
    path(X,Y,[X],Cs, S, P), P is S+W.
path(X,Y,Visited,[Z|Cs], S, P) :-
    connection(X,Z,W),
    notIn(Z,Visited),
    path(Z,Y,[Z|Visited],Cs, S+W, P).

? path(ori, dest, X, 0, P).

2 个答案:

答案 0 :(得分:4)

你的谓词几乎可以奏效。我只想解决两个问题和一些细节。首先,它有助于将可读性与不同的arities分开。所以让我们将路径/ 5的一个规则放在路径/ 6的两个规则之前,如下所示:

path(X,Y,[X|Cs], S, P) :-
    path(X,Y,[X],Cs, S, P),
    P is S+W.                          % <-(1)

path(X,X,_,[], S, P).
path(X,Y,Visited,[Z|Cs], S, P) :-
    connection(X,Z,W),
    notIn(Z,Visited),
    path(Z,Y,[Z|Visited],Cs, S+W, P).  % <-(2)

查看示例查询路径/ 5似乎是要调用以查找路径的谓词。在其单一规则的第二个目标(标记为% <-(1))中,您使用内置的是/ 2,右侧是表达式S+W。变量W首次出现在此处,因此未绑定。这会导致实例化错误,如以下示例所示:

   ?- X is 1+W.
     ERROR!!
     INSTANTIATION ERROR- in arithmetic: expected bound value

但是,由于您只使用path / 5来调用path / 6,因此不需要该目标。其次,在path / 6的第二个规则中,在最后一个目标中,您将S+W作为参数传递而不是首先对其进行评估。要查看会发生什么,让我们从路径/ 5中删除标记为% <-(1)的目标,并在代码中添加示例图表:

connection(ori,a,2).
connection(a,b,5).
connection(b,a,4).
connection(b,dest,1).

现在考虑一个额外目标的示例查询:

   ?- path(ori, dest, X, 0, P), Weight is P.
P = 0+2+5+1,
Weight = 8,
X = [ori,a,b,dest] ? ;
no

如您所见,参数S+W导致最终权重是表达而不是值。考虑在递归目标之前添加目标S1 is S+W并将S1作为参数传递。第三,你在谓词notIn / 2中使用内置的(\ ==)/ 2。这种比较成功或失败,没有副作用或统一。只要两个参数绑定到值但与未绑定变量一起使用时存在问题,这样就可以了。请考虑以下查询:

   ?- X=Y, X\==Y.
no

按预期失败但是:

   ?- X\==Y, X=Y.
X = Y

成功,因为X\==Y对变量没有影响,因此它们可以在下一个目标中统一。最好使用dif / 2:

   ?- X=Y, dif(X,Y).
no
   ?- dif(X,Y), X=Y.
no

最后,两个小建议:首先,因为你使用path / 5的第4个参数传递0作为权重的起始值,你可以在单个目标中做到这一点。规则,从而简化了path / 4的接口。其次,对于反映其声明性质的谓词有一个更具描述性的名称会很好,比如start_end_path_weight / 4。所以你的代码看起来像这样:

notIn(A,[]).
notIn(A,[H|T]):-
   dif(A,H),
   notIn(A,T).

start_end_path_weight(X,Y,[X|Cs], P) :-
   path(X,Y,[X],Cs, 0, P).

path(X,X,_,[], P, P).
path(X,Y,Visited,[Z|Cs], S, P) :-
    connection(X,Z,W),
    notIn(Z,Visited),
    S1 is S+W,
    path(Z,Y,[Z|Visited],Cs, S1, P).

通过这些修改,您的示例查询如下所示:

   ?- start_end_path_weight(ori,dest,X,W).
W = 8,
X = [ori,a,b,dest] ? ;
no

答案 1 :(得分:2)

以下是如何通过 @tas's answer使用代替(is)/2改进 InterRail

:- use_module(library(clpfd)).

start_end_path_weight(X,Y,[X|Cs], P) :-
   path(X,Y,[X],Cs, 0, P).

path(X,X,_,[], P, P).
path(X,Y,Visited,[Z|Cs], S, P) :-
    connection(X,Z,W),
    notIn(Z,Visited)
    maplist(dif(Z),Visited),
    S1 is S+W
    S1 #= S+W, S1 #=< P, 
    path(Z,Y,[Z|Visited],Cs, S1, P).

限制最高成本? 一块蛋糕! 考虑以下enter image description here子集...

JS Objects: Inherited a Mess

...翻译成Prolog ...

connection(X,Y,D) :- to_fro_dt(X,Y,D).
connection(X,Y,D) :- to_fro_dt(Y,X,D).

to_fro_dt(aberdeen,edinburgh,140). to_fro_dt(amsterdam,berlin,370). to_fro_dt(amsterdam,brussels,113). to_fro_dt(amsterdam,cologne,158). to_fro_dt(amsterdam,copenhagen,675). to_fro_dt(ancona,igoumenitsa,900). to_fro_dt(athens,patras,215). to_fro_dt(athens,/* for consistency */piraeus,5). to_fro_dt(athens,thessaloniki,265). to_fro_dt(bar,belgrade,572). to_fro_dt(barcelona,madrid,170). to_fro_dt(barcelona,marseille,280). to_fro_dt(barcelona,sevilla,330). to_fro_dt(barcelona,valencia,175). to_fro_dt(bari,igoumenitsa,570). to_fro_dt(bari,rome,240). to_fro_dt(belfast,dublin,240). to_fro_dt(belgrade,bucharest,730). to_fro_dt(belgrade,budapest,450). to_fro_dt(belgrade,sarajevo,540). to_fro_dt(belgrade,skopje,525). to_fro_dt(belgrade,sofia,485). to_fro_dt(bergen,oslo,405). to_fro_dt(berlin,cologne,260). to_fro_dt(berlin,hamburg,95). to_fro_dt(berlin,munich,345). to_fro_dt(berlin,prague,275). to_fro_dt(berlin,warsaw,365). to_fro_dt(bern,frankfurt,235). to_fro_dt(bern,lyon,230). to_fro_dt(bern,milan,240). to_fro_dt(birmingham,edinburgh,265). to_fro_dt(birmingham,holyhead,245). to_fro_dt(birmingham,london,105). to_fro_dt(bologna,florence,37). to_fro_dt(bologna,milan,60). to_fro_dt(bordeaux,lyon,375). to_fro_dt(bordeaux,madrid,660). to_fro_dt(bordeaux,paris,180). to_fro_dt(bristol,london,105). to_fro_dt(brussels,cologne,107). to_fro_dt(brussels,frankfurt,190). to_fro_dt(brussels,london,140). to_fro_dt(brussels,paris,85). to_fro_dt(bucharest,budapest,830). to_fro_dt(bucharest,sofia,540). to_fro_dt(bucharest,zagreb,365). to_fro_dt(budapest,ljubljana,540). to_fro_dt(budapest,vienna,165). to_fro_dt(budapest,warsaw,680). to_fro_dt(budapest,zagreb,365). to_fro_dt(catania,naples,450). to_fro_dt(cologne,frankfurt,82). to_fro_dt(copenhagen,hamburg,270). to_fro_dt(copenhagen,oslo,520). to_fro_dt(copenhagen,stockholm,315). to_fro_dt(cork,dublin,165). to_fro_dt(dublin,holyhead,195). to_fro_dt(dublin,westport,210). to_fro_dt(edinburgh,glasgow,50). to_fro_dt(faro,lisbon,230). to_fro_dt(florence,rome,95). to_fro_dt(florence,venice,123). to_fro_dt(frankfurt,hamburg,220). to_fro_dt(frankfurt,munich,190). to_fro_dt(frankfurt,paris,235). to_fro_dt(hamburg,munich,350). to_fro_dt(helsinki,rovaniemi,570). to_fro_dt(helsinki,turku,110). to_fro_dt(heraklion,piraeus,390). to_fro_dt(igoumenitsa,patras,360). to_fro_dt(istanbul,sofia,775). to_fro_dt(istanbul,thessaloniki,720). to_fro_dt(kiruna,stockholm,960). to_fro_dt(lisbon,madrid,610). to_fro_dt(lisbon,porto,165). to_fro_dt(ljubljana,venice,540). to_fro_dt(ljubljana,zagreb,140). to_fro_dt(london,paris,135). to_fro_dt(london,penzance,305). to_fro_dt(lyon,marseille,100). to_fro_dt(lyon,paris,115). to_fro_dt(madrid,'málaga',165). to_fro_dt(madrid,pamplona,180). to_fro_dt(madrid,santander,270). to_fro_dt(madrid,santiago,425). to_fro_dt(madrid,sevilla,155). to_fro_dt(madrid,valencia,105). to_fro_dt(marseille,montpellier,140). to_fro_dt(marseille,nice,155). to_fro_dt(milan,munich,465). to_fro_dt(milan,nice,310). to_fro_dt(milan,venice,155). to_fro_dt(munich,prague,365). to_fro_dt(munich,venice,425). to_fro_dt(munich,vienna,250). to_fro_dt(naples,rome,70). to_fro_dt(oslo,stockholm,380). to_fro_dt(paris,rennes,120). to_fro_dt(piraeus,rhodes,710). to_fro_dt(prague,vienna,270). to_fro_dt(prague,warsaw,520). to_fro_dt(sarajevo,zagreb,550). to_fro_dt(skopje,sofia,540). to_fro_dt(skopje,thessaloniki,240). to_fro_dt(sofia,thessaloniki,400). to_fro_dt(split,zagreb,335). to_fro_dt(stockholm,/* added by hand */turku,725). to_fro_dt(stockholm,'östersund',420). to_fro_dt(trondheim,'östersund',230). to_fro_dt(venice,vienna,440). to_fro_dt(vienna,warsaw,450).

...让我们找到

的路径
  • 从维也纳开始

  • 包括至少2个其他城市

  • 累计旅行时间为10小时(或更短)!

?- W #=< 600, Path = [_,_,_|_], start_end_path_weight(vienna, _, Path, W).
W = 530, Path = [vienna,budapest,zagreb] ;
W = 595, Path = [vienna,munich,berlin] ;
W = 440, Path = [vienna,munich,frankfurt] ;
W = 522, Path = [vienna,munich,frankfurt,cologne] ;
W = 600, Path = [vienna,munich,hamburg] ;
W = 545, Path = [vienna,prague,berlin] ;
W = 563, Path = [vienna,venice,florence] ;
W = 600, Path = [vienna,venice,florence,bologna] ;
W = 595, Path = [vienna,venice,milan] ;
false.                                      % terminates universally fast