Prolog-给定不同的出行方式,计算两个位置之间的最快行进速度

问题描述 投票:2回答:1

我正在尝试在给定不同的出行方式的情况下,如何计算两个地方之间的最快旅程。我的事实库以谓词route(Src, Dest, Distance, TravelMode)开头,并且通过谓词journey(Src, Dest, TravelMode)输入,该谓词应输出要使用的最快行驶模式。 (基本上是时间最短的那个。)

[但是,它说TravelMode是一个字符串,如果包含f,则表示路径可以步行,c用于汽车,t用于火车,p用于飞机。这让我感到困惑,因为我不太了解如何搜索字符串TravelMode,只为包含的旅行模式运行相应的时间函数。

下面是我的代码,现在,它只能计算位置之间的时间(time_f等),尽管我认为我的时间谓词是错误的,因为我认为这应该只是一个通用函数。

[我也曾尝试对journey谓词进行编码,但是似乎只输出true / false,没有值可能意味着我的route / speed谓词是错误的。

我在正确的道路上吗?我一直坚持这一点,非常感谢能帮助我朝正确方向前进的任何帮助,也可以帮助您解释我在这里犯错的地方。

不确定每个人是否都理解,但我只是添加了程序规范,以便更清楚地理解

Problem Statement

/* Sample set of facts */
route(dublin, cork, 200, 'fct').
route(cork, dublin, 200, 'fct').
route(cork, corkAirport, 20, 'fc').
route(corkAirport, cork, 25, 'fc').
route(dublin, dublinAirport, 10, 'fc').
route(dublinAirport, dublin, 20, 'fc').
route(dublinAirport, corkAirport, 225, 'p').
route(corkAirport, dublinAirport, 225, 'p').

/* Speed of mode of transport used */
speed(foot, 5).
speed(car, 80).
speed(train, 100).
speed(plane, 500).

/* Time between 2 cities, given specified transportation mode */
time_f(City1, City2, Time) :-
    route(City1, City2, Distance, _),
    speed(foot, Speed),
    Time is (Distance / Speed), 
    write('Time travelling between '), write(City1), write(' and '), write(City2), write(' via foot is: '), write(Time), nl.

time_c(City1, City2, Time) :-
    route(City1, City2, Distance, _),
    speed(car, Speed),
    Time is (Distance / Speed), 
    write('Time travelling between '), write(City1), write(' and '), write(City2), write(' via car is: '), write(Time), nl.

time_t(City1, City2, Time) :-
    route(City1, City2, Distance, _),
    speed(train, Speed),
    Time is (Distance / Speed), 
    write('Time travelling between '), write(City1), write(' and '), write(City2), write(' via train is: '), write(Time), nl.

time_p(City1, City2, Time) :-
    route(City1, City2, Distance, _),
    speed(plane, Speed),
    Time is (Distance / Speed), 
    write('Time travelling between '), write(City1), write(' and '), write(City2), write(' via plane is: '), write(Time), nl.


/* Solve for fastest journey */
journey(City1, City2, TravelModes) :-
    route(City1, City2, Distance, TravelModes),
    speed('TravelModes', Speed),
    Time is (Distance / Speed), 
    write('Time travelling between '), write(City1), write(' and '), write(City2), write(' via '), write(TravelModes), 
    write(' is: '), write(Time), nl.

编辑:

我试图实施一些更改。特别是检测模式是否为字符串的一部分。

/* Sample set of facts */
route(dublin, cork, 200, fct).
route(dublin, dublinAirport, 10, fc).
route(dublinAirport, corkAirport, 225, p).

/* Speed of mode of transport used */
speed(f, 5).
speed(c, 80).
speed(t, 100).
speed(p, 500). 

/* Program Flow 
1. Input journey(City1, City2, TravelModes).
2. Check if City1 and City2 can be traveled (or path exists between them)
3. Access time function
4. Get travel time between City1 and City2 for TravelModes used
5. Select lowest travel time and output it.
*/

/* Checks if mode is in string */
availableMode(Mode, TravelModes) :- forall(sub_atom(Mode,_,1,_,C), sub_atom(TravelModes,_,1,_,C)).

/* Check mode of transport */

journey(City1, City2, TravelModes) :-
    route(City1, City2, Distance, TravelModes),
    availableMode(Mode, TravelModes),
    speed(Mode, Speed),
    Time is (Distance / Speed),
    write('Time between '), write(City1), write(' and '), write(City2), write(' via '), write(Mode), write(' is: '),
    write(Time), n1.

编辑2:

当前,它可以检查TravelMode输入并计算所需的时间。但是,它不会将输出存储在列表中,该列表的目标是选择路线之间的最短时间并输出该时间。

/* Sample set of facts */
route(dublin, cork, 200, fct).
route(dublin, dublinAirport, 10, fc).
route(dublinAirport, corkAirport, 225, p).

/* Speed of mode of transport used */
speed(f, 5).
speed(c, 80).
speed(t, 100).
speed(p, 500). 

/* Checks if mode is in string */
availableMode(Mode, TravelModes) :- sub_atom(TravelModes,_,1,_,Mode).

/* Read journey user input */
journey(City1, City2, TravelModes) :-
    route(City1, City2, Distance, TravelModes),
    availableMode(Mode, TravelModes),
    speed(Mode, Speed),
    Time is (Distance / Speed),
    write('Time between '), write(City1), write(' and '), write(City2), write(' via '), write(Mode), write(' is: '),
    write(Time), nl.

编辑3:

将时间变量实现为辅助journey predicate。试图实现all(Solutions)并找到最小变量,尽管我相信我仍然会遗漏一些东西,因为它仅输出true / false

/* Sample set of facts */
route(dublin, cork, 200, fct).
route(dublinAirport, dublin, 20, fc).
route(dublinAirport, corkAirport, 225, p).

/* Speed of mode of transport used */
speed(f, 5).
speed(c, 80).
speed(t, 100).
speed(p, 500). 

/* Checks if mode is in string */
availableMode(Mode, TravelModes) :- sub_atom(TravelModes,_,1,_,Mode).

journey(City1, City2, TravelModes) :-
    route(City1, City2, Distance, TravelModes),
    availableMode(Mode, TravelModes),
    speed(Mode, Speed),
    Time is (Distance / Speed),
    write('Time between '), write(City1), write(' and '), write(City2), write(' via '), write(Mode), write(' is: '),
    write(Time), nl.

/* Keep definition of journey but include a time variable that can be utilized */
journey(City1, City2, TravelModes) :- journey(City1, City2, TravelModes, _Time).

/* journey using time variable */
journey(City1, City2, TravelModes, Time) :- 
    route(City1, City2, Distance, TravelModes),
    availableMode(Mode, TravelModes),
    speed(Mode, Speed),
    Time is (Distance / Speed).

/* Collecting all solutions */
all(Solutions) :- findall([City1, City2, TravelModes, Time], journey(City1, City2, TravelModes, Time), Solutions).

/* Finding minimum solution */
find_min(S, Solutions) :- all(Solutions).

编辑4:

已实现(递归解决方案并将其存储在列表中)。还删除了冗余journey/3。当前正在修复代码以仅显示一个解决方案集(也就是使用最短时间的最终解决方案)的过程。

/* Sample set of facts */
route(dublin, cork, 200, fct).
route(cork, dublin, 200, fct).
route(cork, corkAirport, 20, fc).
route(corkAirport, cork, 25, fc).
route(dublin, dublinAirport, 10, fc).
route(dublinAirport, dublin, 20, fc).
route(dublinAirport, corkAirport, 225, p).
route(corkAirport, dublinAirport, 225, p).

/* Speed of mode of transport used */
speed(f, 5).
speed(c, 80).
speed(t, 100).
speed(p, 500). 

/* Checks if mode is in string */
availableMode(Mode, TravelModes) :- sub_atom(TravelModes,_,1,_,Mode).

/* Keep definition of journey but include a time variable that can be utilized */
journey(City1, City2, TravelModes) :- journey(City1, City2, TravelModes, _Time).

/* journey using time variable */
journey(City1, City2, TravelModes, Time) :- 
    route(City1, City2, Distance, TravelModes),
    availableMode(Mode, TravelModes),
    speed(Mode, Speed),
    Time is (Distance / Speed),
    write('Time between '), write(City1), write(' and '), write(City2), write(' via '), write(Mode), write(' is: '),
    write(Time), nl.

/* Collecting all solutions */
all(Solutions) :- findall([City1, City2, TravelModes, Time], journey(City1, City2, TravelModes, Time), Solutions).

/* Recursion to find minimum travel time */
% Using the \+ (not provable operator) which discards the unnecessary solution
% Allowing us to retain the solutions with lowest time
% After recursively going thru the list, the accumulator list is set to the final solution list (aka the lowest time)
minimize([],Sol,Sol).
minimize([S|Ss],SolAcc,FinSol) :- S = [Cy1, Cy2, _, _],
                                  \+ member([Cy1, Cy2, _, _], SolAcc),
                                  minimize(Ss,[S|SolAcc],FinSol).
minimize([S|Ss],SolAcc,FinSol) :- S = [Cy1, Cy2, _MyMd, MyTi],
                                  member([Cy1, Cy2, _OtherMd, OtherTi], SolAcc),
                                  OtherTi < MyTi,
                                  minimize(Ss,SolAcc,FinSol).
minimize([S|Ss],SolAcc,FinSol) :- S = [Cy1, Cy2, _MyMd, MyTi],
                                  member([Cy1, Cy2, _OtherMd, OtherTi], SolAcc),
                                  OtherTi >= MyTi,
                                  delete(SolAcc, [Cy1, Cy2,_,_], SolAcc2),
                                  minimize(Ss,[S|SolAcc2],FinSol).

/* Finding minimum solution */
find_min(MinimizedSolutions) :- all(Solutions),minimize(Solutions,[],MinimizedSolutions).
search prolog
1个回答
0
投票

添加“最小化”谓词的答案,该谓词选择那些具有最短时间的城市路径。 (此谓词现在在问题的“编辑4”中)

findallbagof的SWI Prolog文档为here

请注意,下面的findall被赋予表达式journey(City1, City2, TravelModes, Time)作为term,但将其“提升”为goal(即可调用谓词)。这是meta-call功能,非常超出一阶逻辑,类似于通过字符串追加来构建Java代码,对其进行编译然后运行。编辑者应以反色突出显示该部分...

/* Collecting all solutions */
all(Solutions) :- findall([City1, City2, TravelModes, Time], journey(City1, City2, TravelModes, Time), Solutions).

minimize([],Sol,Sol).
minimize([S|Ss],SolAcc,FinSol) :- S = [Cy1, Cy2, _, _],
                                  \+ member([Cy1, Cy2, _, _], SolAcc),
                                  minimize(Ss,[S|SolAcc],FinSol).
minimize([S|Ss],SolAcc,FinSol) :- S = [Cy1, Cy2, _MyMd, MyTi],
                                  member([Cy1, Cy2, _OtherMd, OtherTi], SolAcc),
                                  OtherTi < MyTi,
                                  minimize(Ss,SolAcc,FinSol).
minimize([S|Ss],SolAcc,FinSol) :- S = [Cy1, Cy2, _MyMd, MyTi],
                                  member([Cy1, Cy2, _OtherMd, OtherTi], SolAcc),
                                  OtherTi >= MyTi,
                                  delete(SolAcc, [Cy1, Cy2,_,_], SolAcc2),
                                  minimize(Ss,[S|SolAcc2],FinSol).


/* Finding minimum solution */
find_min(MinimizedSolutions) :- all(Solutions),minimize(Solutions,[],MinimizedSolutions).

澄清评论中的问题

如果您认为程序定义了数据流(请参见下面的手绘图),那么首先将Solutions设置为(或“统一为”)所有journey(C1,C2,Tm,Ti)可能的解决方案的列表],它们各自格式化为列表[C1,C2,Tm,Ti]

列表Solutions流入代表minimize的框。该框还带有一个空列表[],旨在将其第三个参数与最终解决方案MinimizedSolutions统一起来。 minimize会自我调用(在其内部创建一个新的minimize框),并且在四种输入情况下,其行为都可能不同,它们可以作为SolutionsSolAcc的值来接收。

想法是minimize从其第一个输入值(一个列表)中删除一个元素,并在其第二个输入值即累加器(也是一个列表)中添加1或0个元素,然后再调用自身。这样,当第一个输入值最终变为[]时,minimize只需将第二个值(输入)短路到第三个值(输出),然后通过递归纤维化盒向外流向最高目标。

prolog data flow

实际上,Prolog允许编写讨厌的(但紧凑的)代码,因为它允许将minimze/3中区分大小写的表达式插入规则头。为了使minimize更清楚并显示意图,在一个假想的Prolog中,该Prolog仅允许变量作为规则头中的谓词参数,并具有“保护表达式”以在规则正文中|的左侧执行案例测试。具有以下代码:

% Hide the fact that we need an accumulator value by
% defining minimize/2 which calls minimize/3
% This is the "public" part of minimize and can also be done in Prolog. 

minimize(SolIn,SolOut) :- minimize(SolIn,[],SolOut).  

% This is the "private" part of minimize and uses non-Prolog "guard" syntax

minimize(SolIn,SolAcc,SolOut) :- SolIn = [] | 
                                 SolOut = SolAcc.
minimize(SolIn,SolAcc,SolOut) :- SolIn = [S|Ss],
                                 S = [Cy1, Cy2, _, _],
                                 \+ member([Cy1, Cy2, _, _], SolAcc) |
                                 minimize(Ss,[S|SolAcc],SolOut).
minimize(SolIn,SolAcc,SolOut) :- SolIn = [S|Ss],
                                 S = [Cy1, Cy2, _MyMd, MyTi],
                                 member([Cy1, Cy2, _OtherMd, OtherTi], SolAcc),
                                 OtherTi < MyTi |
                                 minimize(Ss,SolAcc,FinSol).

% etc. for the other two cases

minimize(SolIn,SolOut)规则只是向要保持此状态的下一个人显示,arity-2谓词minimize/2是“客户端代码”将使用的规则。 minimize/2将工作直接传递给实际的“实现”,该实现是arity-3谓词minimize/3minimize(SolIn,SolAcc,SolOut)

对于后者,通过SolIn列表开始进行递归遍历。

如果程序为minimize(SolIn,[],SolOut),则modularized将是模块正在导出的内容。还可以根据minimize(SolIn,SolOut)mode flags

标记实现所考虑的变量“ in”和“ out”(仅在注释中,编译器不处理这些变量)。

再次,这具有命令式编程风格的“过程调用”,但是我总是可视化线程或信息流在某些参数位置进入“谓词框”,然后在另一位置返回,就像缝合一样。 (添加minimize(+SolIn,-SolOut)之类的内容,线程也需要使令牌沿其移动,但这是另一次)

© www.soinside.com 2019 - 2024. All rights reserved.