You selected traveler1.pl


headline:-
 model(D),
 figure(D),
 wn('%-----------------------------------------------------------'),
 wn('% shortest path algorithms by Ford-Bellman and Dijkstra'),
 wn('% 最短経路選択の問題'),
 wn('%-----------------------------------------------------------'),
 h0.

me:-
 wn('% file: search.pl (25 Nov 2001)'),
 wn('% file: traveler.pl (2-4 Mar 2003)'),
 wn('% modified: 4-5 Mar 2003  negative circuit case'),
 wn('% modified: 3 Apr 2003  bug fix. evaluate_path/7 '),
 wn('% author: Kenryo INDO  (Kanto Gakuen University)').

references:-
 wn('% references:'),
 wn('%  [1] 久保幹雄、『組合わせ最適化とアルゴリズム』、共立出版.'),
 wn('%  [Kubo, M. (2000). Combinatorial Optimization and Algorithms. Kyoritsu Shuppan. (Japanese)] '),
 wn('%  [2] 猪平進ら、『インターネット時代の情報管理概論』、共立出版.'),
 wn('%  [Inohira, S. et al.(1999). "Introductory Course of Information Management in the Era of Internet". Kyoritsu Shuppan. (Japanese)] '),
 wn('%  [3] Bellman, R.(1956). On a routing problem. Quarterly of Applied Mathematics 16: 87-93. '),
wn('%  [4] Dijkstra, E.(1959). A note on two problems in connection with graphs. Numerische Mathematics 1: 269-271. ').

h0:-
   wn('|  node(Name,Symbol)'),
   wn('|  arc(From,To, [Cost|_]): direct move'),
   wn('|  min_cost(M,Start,End,Path,Costs)'),
   wn('|   M: ford_bellman or dijkstra'),
   nl.

wn(Z):- write(Z), nl.

:- dynamic  potential /3.
:- dynamic  pred /3.
:- dynamic  model /1.
:- dynamic  detect_circuit_data /2.


% default model
model(Default):- Default = yado1.


% node, arc, network

node(A,B):- model(M), example(M,node(A,B)).

arc(A,B,C):- model(M), example(M,arc(A,B,C)).
arc(A,B,[infinite]):- model(M), \+ example(M,arc(A,B,_C)).

network(M,[N,E,C]):-
   model(M),
   nodes(N,_L),
   arcs_and_costs(E,C).

nodes(Ns,L):-
   findall(X, node(X,_), Ns),
   length(Ns,L).

arcs_and_costs(E,C):-
   findall((X,Y,Z), arc(X,Y,[Z|_]), C),
   findall((X,Y), member((X,Y,Z),C), E).

display_nodes:-
   wn('----node (name,  symbol)-------'),
   forall(node(X,Y),(write(Y),tab(5),wn(X))).

display_arcs:-
   wn('----arc (from,  to,  cost)-------'),
   forall(arc(X,Y,[C|_]),(write(Y),tab(5),wn(X),tab(5),wn(C))).


%-----------------------------------------------------------
% examples of network problem 
%-----------------------------------------------------------
%
% A network is a directed graph consists of the nodes, N, and the 
% arcs, E, and the arc costs per unit flow C(e), e in E.
% An arc is a pair of nodes (v,w) in E in the network (N,E,C) 
% which represents possible flow via the arc. 

% example 1.
%  transshipment system of spring water in Japan 
%  of 300 years ago.(cf.,[2]).
% 宿場町の例題(文献[1])
%------------------------------------------------------
% nodes (i.e.,vertics)
example(yado, node(s, '富士山')).
example(yado, node(1, '宿場町1')).
example(yado, node(2, '宿場町2')).
example(yado, node(3, '宿場町3')).
example(yado, node(t, '江戸')).
% arcs (i.e., edges)  with direction
example(yado, arc(s, 1, [10])).
example(yado, arc(2, 1, [3])).
example(yado, arc(s, 2, [5])).
example(yado, arc(1, 2, [2])).
example(yado, arc(2, 3, [2])).
example(yado, arc(1, t, [1])).
example(yado, arc(3, t, [6])).

% example 2.
%  adding an arc with negative cost to example 1. [1]
%------------------------------------------------------
example(yado1, node(A, B)):-
   example(yado, node(A, B)).
example(yado1, arc(A, B, C)):-
   example(yado, arc(A, B, C)).
example(yado1, arc(3, 1, [-5])).

%
% example 3. Japanese railroad system of a few years ago. (cf.,[2]).
% 鉄道路線の例題(文献[2]参照。ただしデータは一部訂正した)
%------------------------------------------------------
% nodes (i.e., vertics)
example(eki, node(tokyo, '東京駅')).
example(eki, node(ueno, '上野駅')).
example(eki, node(kyoto, '京都駅')).
example(eki, node(sendai, '仙台駅')).
example(eki, node(niigata, '新潟駅')).
example(eki, node(mito, '水戸駅')).

% arcs (i.e., edges) with direction

example(eki, arc(tokyo, kyoto, [7800])).
example(eki, arc(tokyo, ueno, [300])).
example(eki, arc(tokyo, mito, [2500])).
example(eki, arc(tokyo, sendai, [5700])).

example(eki, arc(kyoto, tokyo, [7800])).
example(eki, arc(ueno, tokyo, [300])).
example(eki, arc(mito, tokyo, [2500])).
example(eki, arc(sendai, tokyo, [5700])).

example(eki, arc(kyoto, ueno, [8400])).
example(eki, arc(sendai, ueno, [5600])).
example(eki, arc(niigata, ueno, [5000])).

example(eki, arc(ueno, kyoto, [8400])).
example(eki, arc(ueno, niigata, [5000])).
example(eki, arc(ueno, sendai, [5600])).

example(eki, arc(sendai, niigata, [5300])).
example(eki, arc(kyoto, niigata, [8000])).

example(eki, arc(niigata, kyoto, [8000])).
example(eki, arc(niigata, sendai, [5300])).

example(eki, arc(mito, sendai, [3500])).
example(eki, arc(sendai, mito, [3500])).


figure(yado):-
  wn('%              [1]------------- [t]'),
  wn('%           10 /|          1   /'),
  wn('%             / |            6/ '),
  wn('%            / 3|            /  '),
  wn('%           /   |2          /   '),
  wn('%          /    |          /    '),
  wn('%      [s]-----[2]------[3]     '),
  wn('%             5       2         '),
  nl.

figure(yado1):-
  wn('%              [1]------------- [t]'),
  wn('%           10 /| |        1   /'),
  wn('%             / |  |-5       6/ '),
  wn('%            / 3|   |        /  '),
  wn('%           /   |2    |     /   '),
  wn('%          /    |       |  /    '),
  wn('%      [s]-----[2]------[3]     '),
  wn('%             5       2         '),
  nl.

figure(eki):-
  wn('%            [niigata]------ [sendai]'),
  wn('%              /   |          /'),
  wn('%             /     |     [mito]'),
  wn('%            /       |     / '),
  wn('%           /       [ueno]   '),
  wn('%          /           |     '),
  wn('%    [kyoto]----------[tokyo]'),
  wn('%  '),
  nl.          


%-----------------------------------------------------------
% algorithms for shortest path problem 
%-----------------------------------------------------------


% ==================================== %
%  Main Program
% ==================================== %

min_cost(Method,S,T,Path,CP):-
   member(Method,[ford_bellman, dijkstra]),
   initialize_potentials(0,S),
   initialize_predecessors(0,Method),
   initialize_circuit_data,
   iteratively_update_potentials(K,Method,S,T,[T|Path0]),
   display_tables(Method,K),
trace,
   evaluate_path(Method,S,T,Path0,Path,CP,Cir),
   (Cir = 0
     -> display_optimal_path(CP,[T|Path])
      ; display_circuit(K,CP,Path)
   ).

% ==================================== %
% Ford-Bellman's iterative method. [3]
% ==================================== %

% Two classical algorithms of Ford and Bellman [3]  use the 
% node potential functions
% P: N -> R, and 
% iteratively update them in finite steps ( in order of product of 
% nodes and arcs, O(nm), if no negative cost ).  
% Potential function of a network transshipment problem 
% is the Lagrange multiplier (of complementary slackness conditions)
% for the linear programming styled formalization of it. 

iteratively_update_potentials(0,ford_bellman,_,_,[]).

iteratively_update_potentials(K,ford_bellman,S,T,[N|Path]):-
   iteratively_update_potentials(K0,ford_bellman,S,T,Path),
   K is K0 + 1,
   nodes(Nodes,LN),
   subtract(Nodes,[T],Vs0),
   % stop condition
   ( K < LN -> nth1(K,Vs0,N); K is LN -> N = T; !,fail),
   initialize_potentials(K,S),
   initialize_predecessors(K,ford_bellman),
   % The following code is somewhat of forcing me to do procedurally.
   forall(arc(V,W,[Cvw|_]),
     (
      potential(K0,W,Yw0),
      potential(K0,V,Yv0),
      greater_than(Yw0, Yv0 + Cvw, Yvw, F),
      update_node_potential(K,W,Yw0->Yvw,F),
      update_node_predecessor(K,W,_Pw0->V,F)
     )
   ).

% ==================================== %
% Dijkstra's iterative method. [4]
% ==================================== %
% Although it can be applied only to networks without negative cost arc,
% the labeling method is efficiently (in the order of square of nodes) 
% than the method by Ford-Bellman.

iteratively_update_potentials(0,dijkstra,_,_,[]).

iteratively_update_potentials(K,dijkstra,S,T,[V|Path]):-
   iteratively_update_potentials(K0,dijkstra,S,T,Path),
   K is K0 + 1,
   nodes(Nodes,LN),
   subtract(Nodes,Path,Vs0),
   % select and stop condition
   G = find_min(P,potential(K0,V,P),member(V,Vs0)),
   ( K < LN -> G; K is LN -> V = T; !,fail),
   initialize_potentials(K,S),
   initialize_predecessors(K,dijkstra),
   subtract(Nodes,[V],Vs),
   forall((node(V,_),arc(V,W,[Cvw|_]),member(W,Vs)),
     (
      potential(K0,W,Yw0),
      potential(K0,V,Yv0),
      greater_than(Yw0, Yv0 + Cvw, Yvw, F),
      update_node_potential(K,W,Yw0->Yvw,F)
     )
   ).

% find the minimum of potential (is locally used)
%-----------------------------------------------
find_min(P,potential(L,W,P),member(W,Vs)):-
   potential(L,W,P),
   member(W,Vs),
   \+ (
     potential(L,X,Q),
     member(X,Vs),
     greater_than(P, Q + 0,_,yes)
   ).



% ==================================== %
%  Common Utilities
% ==================================== %


% initilization for potentials
%-----------------------------------------------------------
initialize_potentials(K,S):-
   node(S,_),
   (
    K = 0 -> abolish(potential /3)
    ;  clean_kth_potentials_up(K)
   ),
   initialize_potentials_0(K,S),
   initialize_potentials_1(K,S).

initialize_potentials_0(K,S):-
   assert(
     potential(K,S,0)  % fixed
   ).

initialize_potentials_1(0,S):-
   P = infinite,
   forall(
     (node(X,_), X \= S),
     assert(
       potential(0,X, P)
     )
   ).
initialize_potentials_1(K,S):-
   K > 0,
   K0 is K - 1,
   forall(
     (
      potential(K0,X,P),
      X \= S
     ),
     assert(
       potential(K,X, P)
     )
   ).

initialize_circuit_data:-
   abolish(detect_circuit_data /2),
   assert(detect_circuit_data(non,[])).

% initilization for predecessors
%-----------------------------------------------------------
initialize_predecessors(_,dijkstra).

initialize_predecessors(0,ford_bellman):-
   abolish(predecessor /3),
   forall(node(X,_),
     assert(
       predecessor(0,X, -)
     )
   ).

initialize_predecessors(K,ford_bellman):-
   K > 0,
   K0 is K - 1,
   clean_kth_predecessors_up(K),
   forall(
     predecessor(K0,X,V),
     assert(
       predecessor(K,X,V)
     )
   ).

% update potential of a node 
%-----------------------------------------------------------
update_node_potential(_K,_W,Y->Y, no).
update_node_potential(K,W,_Y0->Y, yes):-
   \+ K = 0,
   \+ var(K),
   \+ var(W),
   %Y = Yvw,
   erase_potential(K,W),
   assert(
     potential(K,W,Y)
   ).

erase_potential(K,N):-
   \+ clause(potential(K,N,_),true).

erase_potential(K,N):-
   \+ var(K),
   \+ var(N),
   clause(potential(K,N,_P),true),
   retractall(
     potential(K,N,_)
   ).

clean_kth_potentials_up(K):-
   \+ var(K),
   forall(node(N,_),
     erase_potential(K,N)
   ).


% update best predecessor of a node 
%-----------------------------------------------------------
update_node_predecessor(_K,_N,V->V,no).
update_node_predecessor(K,N,V0->V,yes):-
   \+ K = 0,
   \+ var(K),
   \+ var(N),
   K0 is K - 1,
   predecessor(K0,N,V0),
   erase_predecessor(K,N),
   assert(
     predecessor(K,N,V)
   ).

erase_predecessor(K,N):-
   \+ clause(predecessor(K,N,_),true).

erase_predecessor(K,N):-
   \+ var(K),
   \+ var(N),
   clause(predecessor(K,N,_),true),
   retractall(
     predecessor(K,N,_)
   ).

clean_kth_predecessors_up(K):-
   \+ var(K),
   forall(node(N,_),
     erase_predecessor(K,N)
   ).

% decision tree (including the cases of infinite values)

greater_than(Yw0, Yv0 + Cvw, Z, F):-
   Case1 = (Yv0 = infinite; Cvw = infinite), % RHS=infinite
   Case2 = (Yw0 = infinite; Yw0 > Yvw),
   (
    Case1-> (Z=Yw0, F=no)
     ;
      (
       Yvw is Yv0 + Cvw,
       (
        Case2 -> (Z=Yvw, F=yes)
         ;
          (Z=Yw0, F=no)
       )
      )
   ).


% evaluation of the found route
%----------------------------------------------------------
% modified: 3 Apr 2003.  final_time_of_potentials/1

final_time_of_potentials(L):-
   findall(T,potential(T,_N,_P),Ts),
   max_of(L,Ts),
   !.

evaluate_path(Method, S,T,Path0,Path,CP,Cir):-
  %nodes(_N,L),
  final_time_of_potentials(L),
   (Method = dijkstra -> Path = Path0 ; true),
   (evaluate_path_0(Method, L,S, T, [T|Path], CP)
    -> Cir=0
     ; Cir=1
   ).

evaluate_path_0(ford_bellman, _K, S, S, [S], [0]).

evaluate_path_0(ford_bellman, K, S, W, [W|[V|Path]], [P|CP]):-
   predecessor(K,W,V),
   potential(K,W,P),
   detect_circuit(W,DC),
   (DC= no -> true; !,fail),
   evaluate_path_0(ford_bellman, K, S, V, [V|Path], CP).

evaluate_path_0(dijkstra, _K, S, S, [S], [0]).

evaluate_path_0(dijkstra, K, S, W, [W|Path], [P|CP]):-
   evaluate_path_0(dijkstra, K, S, _V, Path, CP),
   potential(K,W,P).

evaluate_path_0(circuit, _K, S, S, [S], [0]).

evaluate_path_0(circuit, K, S, W, [W|Path], [P|[P1|CP]]):-
   evaluate_path_0(circuit, K, S, V, Path, [P1|CP]),
   arc(V,W,[C|_]),
   P is P1 + C.


% detection of negative cycle by Ford-Bellman method
%-----------------------------------------------------
detect_circuit_data(non,[]).

detect_circuit(V,yes):-
   detect_circuit_data(non,Path),
   member(V,Path),
   update_circuit_data(V,Path).

detect_circuit(V,no):-
   detect_circuit_data(non,Path),
   \+ member(V,Path),
   update_circuit_data(non,[V|Path]).

update_circuit_data(A,D):-
   retractall(detect_circuit_data(_,_)),
   assert(detect_circuit_data(A,D)).


% display for the results
%----------------------------------------------------------

display_tables(dijkstra,K):-
   wn('---- potentials -------------------------------------'),
   forall(potential(K,A,B),wn(((t=K),(node=A),(pot=B)))).
   
display_tables(ford_bellman,K):-
   wn('---- potentials -------------------------------------'),
   forall(potential(K,A,B),wn(((t=K),(node=A),(pot=B)))),
   wn('---- predecessors -----------------------------------'),
   forall(predecessor(K,A,B),wn(((t=K),(node=A),(pred=B)))),
   wn('---- end -------------------------------------').

display_optimal_path(CP,Path):-
   CP = [V|_],
   nl,write('optimal cost='(V)),
   reverse(Path,Path0),
   reverse(CP,CP0),
   findall('->'(X/Y),(nth1(I,Path0,X),nth1(I,CP0,Y)),Path1),
   nl,write('optimal route/cumulative cost='),nl,
   tab(2),forall(member(W,Path1),write(W)),nl.

display_circuit(K,CP,Circ):-
   wn('  The circuit of negative or zero cost has detected : '),
   detect_circuit_data(V,Path),
   wn([V|Path]),
   findall(X,
     (
      nth1(J,Path,V),
      nth1(I,Path,X),
      I =< J
     ),
   Circ0),
   reverse(Circ0,Circ1),
   append(Circ1,[V],Circ),
   evaluate_path_0(circuit, K, V, V, Circ,CP).


:- headline.


% max,min
% -----------------------------------------------------------  %
% added: 3 Apr 2003. cited from math1.pl

max_of(X,[X]).
max_of(Z,[X|Y]):-
   max_of(Z1,Y),
   (X > Z1 -> Z=X; Z=Z1).
min_of(X,[X]).
min_of(Z,[X|Y]):-
   min_of(Z1,Y),
   (X < Z1 -> Z=X; Z=Z1).


%end



return to front page.