2

I am new to Prolog

I am trying in Prolog a rule that gives me a given path from a node to another and also gives me the total weight of the path.

I have succeeded to get all the edges of the path but I am not able to show the weight of the path. I debbuged it and it is seen that variable S adds up to the whole weight of the path but in the way back, deletes all the elements. My idea is to add the total weight to P.

Code:

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

2 回答 2

4

您的谓词几乎可以工作。只有两个问题和一些我想解决的细节。首先,将具有不同参数的谓词分开会极大地提高可读性。所以让我们把 path/5 的一个规则放在 path/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)

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

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

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

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 的第四个参数0作为权重的起始值,您不妨在规则的单一目标中这样做,从而简化与路径的接口/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
于 2016-05-13T23:34:20.193 回答
2

以下是如何通过使用进行算术而不是改进@tas的答案(is)/2

:- 使用模块(库(clpfd))。

start_end_path_weight(X,Y,[X|Cs], P) :-
   路径(X,Y,[X],Cs,0,P)。

路径(X,X,_,[],P,P)。
路径(X,Y,已访问,[Z|Cs],S,P):-
    连接(X,Z,W),
    notIn(Z,Visited) maplist 
    (dif(Z),Visited) ,
     S1 是 S+W 
    S1 #= S+W , S1 #=< P ,
    路径(Z,Y,[Z|已访问],Cs,S1,P)。

限制最大成本?小菜一碟! 考虑以下InterRail子集...

在此处输入图像描述

...翻译成Prolog ...

连接(X,Y,D):- to_fro_dt(X,Y,D)。
连接(X,Y,D):- to_fro_dt(Y,X,D)。

to_fro_dt(阿伯丁,爱丁堡,140)。to_fro_dt(阿姆斯特丹,柏林,370)。to_fro_dt(阿姆斯特丹,布鲁塞尔,113)。to_fro_dt(阿姆斯特丹,科隆,158)。to_fro_dt(阿姆斯特丹,哥本哈根,675)。to_fro_dt(ancona,igoumenitsa,900)。to_fro_dt(雅典,帕特雷,215)。to_fro_dt(athens,/* 保持一致性 */piraeus,5)。to_fro_dt(雅典,塞萨洛尼基,265)。to_fro_dt(酒吧,贝尔格莱德,572)。to_fro_dt(巴塞罗那,马德里,170)。to_fro_dt(巴塞罗那,马赛,280)。to_fro_dt(巴塞罗那,塞维利亚,330)。to_fro_dt(巴塞罗那,瓦伦西亚,175)。to_fro_dt(bari,igoumenitsa,570)。to_fro_dt(巴里,罗马,240)。to_fro_dt(贝尔法斯特,都柏林,240)。to_fro_dt(贝尔格莱德,布加勒斯特,730)。to_fro_dt(贝尔格莱德,布达佩斯,450)。to_fro_dt(贝尔格莱德,萨拉热窝,540)。to_fro_dt(贝尔格莱德,斯科普里,525)。to_fro_dt(贝尔格莱德,索非亚,485)。to_fro_dt(卑尔根,奥斯陆,405)。to_fro_dt(柏林,科隆,260)。to_fro_dt(柏林,汉堡,95)。to_fro_dt(柏林,慕尼黑,345)。to_fro_dt(柏林,布拉格,275)。to_fro_dt(柏林,华沙,365)。to_fro_dt(伯尔尼,法兰克福,235)。to_fro_dt(伯尔尼,里昂,230)。to_fro_dt(伯尔尼,米兰,240)。to_fro_dt(伯明翰,爱丁堡,265)。to_fro_dt(伯明翰,霍利黑德,245)。to_fro_dt(伯明翰,伦敦,105)。to_fro_dt(博洛尼亚,佛罗伦萨,37)。to_fro_dt(博洛尼亚,米兰,60)。to_fro_dt(波尔多,里昂,375)。to_fro_dt(波尔多,马德里,660)。to_fro_dt(波尔多,巴黎,180)。to_fro_dt(布里斯托尔,伦敦,105)。to_fro_dt(布鲁塞尔,科隆,107)。to_fro_dt(布鲁塞尔,法兰克福,190)。to_fro_dt(布鲁塞尔,伦敦,140)。to_fro_dt(布鲁塞尔,巴黎,85)。to_fro_dt(布加勒斯特,布达佩斯,830)。to_fro_dt(布加勒斯特,索非亚,540)。to_fro_dt(布加勒斯特,萨格勒布,365)。to_fro_dt(布达佩斯,卢布尔雅那,540)。to_fro_dt(布达佩斯,维也纳,165)。to_fro_dt(布达佩斯,华沙,680)。to_fro_dt(布达佩斯,萨格勒布,365)。to_fro_dt(卡塔尼亚,那不勒斯,450)。to_fro_dt(科隆,法兰克福,82)。to_fro_dt(哥本哈根,汉堡,270)。to_fro_dt(哥本哈根,奥斯陆,520)。to_fro_dt(哥本哈根,斯德哥尔摩,315)。to_fro_dt(软木,都柏林,165)。to_fro_dt(都柏林,圣黑德,195)。to_fro_dt(都柏林,西港,210)。to_fro_dt(爱丁堡,格拉斯哥,50)。to_fro_dt(法鲁,里斯本,230)。to_fro_dt(佛罗伦萨,罗马,95)。to_fro_dt(佛罗伦萨,威尼斯,123)。to_fro_dt(法兰克福,汉堡,220)。to_fro_dt(法兰克福,慕尼黑,190)。to_fro_dt(法兰克福,巴黎,235)。to_fro_dt(汉堡,慕尼黑,350)。to_fro_dt(赫尔辛基,罗瓦涅米,570)。to_fro_dt(赫尔辛基,图尔库,110)。to_fro_dt(伊拉克利翁,比雷埃夫斯,390)。to_fro_dt(igoumenitsa,patras,360)。to_fro_dt(伊斯坦布尔,索非亚,775)。to_fro_dt(伊斯坦布尔,塞萨洛尼基,720)。to_fro_dt(基律纳,斯德哥尔摩,960)。to_fro_dt(里斯本,马德里,610)。to_fro_dt(里斯本,波尔图,165)。to_fro_dt(卢布尔雅那,威尼斯,540)。to_fro_dt(卢布尔雅那,萨格勒布,140)。to_fro_dt(伦敦,巴黎,135)。to_fro_dt(伦敦,彭赞斯,305)。to_fro_dt(里昂,马赛,100)。to_fro_dt(里昂,巴黎,115)。to_fro_dt(马德里,'马拉加',165)。to_fro_dt(马德里,潘普洛纳,180)。to_fro_dt(马德里,桑坦德,270)。to_fro_dt(马德里,圣地亚哥,425)。to_fro_dt(马德里,塞维利亚,155)。to_fro_dt(马德里,瓦伦西亚,105)。to_fro_dt(马赛,蒙彼利埃,140)。to_fro_dt(马赛,尼斯,155)。to_fro_dt(米兰,慕尼黑,465)。to_fro_dt(米兰,尼斯,310)。to_fro_dt(米兰,威尼斯,155)。to_fro_dt(慕尼黑,布拉格,365)。to_fro_dt(慕尼黑,威尼斯,425)。to_fro_dt(慕尼黑,维也纳,250)。to_fro_dt(那不勒斯,罗马,70)。to_fro_dt(奥斯陆,斯德哥尔摩,380)。to_fro_dt(巴黎,雷恩,120)。to_fro_dt(比雷埃夫斯,罗得岛,710)。to_fro_dt(布拉格,维也纳,270)。to_fro_dt(布拉格,华沙,520)。to_fro_dt(萨拉热窝,萨格勒布,550)。to_fro_dt(斯科普里,索非亚,540)。to_fro_dt(斯科普里,塞萨洛尼基,240)。to_fro_dt(索非亚,塞萨洛尼基,400)。to_fro_dt(分裂,萨格勒布,335)。to_fro_dt(stockholm,/* 手工添加 */turku,725)。to_fro_dt(斯德哥尔摩,'östersund',420)。to_fro_dt(特隆赫姆,'östersund',230)。to_fro_dt(威尼斯,维也纳,440)。to_fro_dt(维也纳,华沙,450)。

...让我们找到路径

  • 从维也纳开始

  • 包括至少 2 个其他城市

  • 并且累积旅行时间为 10 小时(或更少)!

?- W #=< 600 , 路径 = [_,_,_|_], start_end_path_weight(vienna, _, Path, W)。
W = 530,路径 = [维也纳,布达佩斯,萨格勒布];
W = 595,路径 = [维也纳、慕尼黑、柏林];
W = 440,路径 = [维也纳,慕尼黑,法兰克福];
W = 522,路径 = [维也纳、慕尼黑、法兰克福、科隆];
W = 600,路径 = [维也纳,慕尼黑,汉堡];
W = 545,路径 = [维也纳,布拉格,柏林];
W = 563,路径 = [维也纳,威尼斯,佛罗伦萨];
W = 600,路径 = [维也纳,威尼斯,佛罗伦萨,博洛尼亚];
W = 595,路径 = [维也纳,威尼斯,米兰];
错误的。% 普遍快速终止
于 2016-05-30T03:59:06.627 回答