Recent

Author Topic: Dijkstra Shortest Path. How to get the result array in correct order.  (Read 3356 times)

quake004

  • New Member
  • *
  • Posts: 33
When I use the function BacktrackDijkstra(prevArray, dest) I'd like to get the array from source to destination in the correct order but I don't know how to do that in the recursive function.

Also it's giving me an error for passing a set as a parameter, how do I fix that?

BFS.pas(65,27) Error: Type identifier expected
BFS.pas(65,27) Fatal: Syntax error, ")" expected but "SET" found

Code: Pascal  [Select][+][-]
  1. program BFS;
  2.  
  3. {$MODE OBJFPC}
  4.  
  5. uses
  6.   Classes, SysUtils, StrUtils;
  7. type
  8.   TCity = (NY = 0, LONDON = 1, MOSCU = 2, OTHER = 3);
  9.  
  10.   TNode = record
  11.     Index: Integer;
  12.     Edges: Array of Integer;
  13.   end;
  14.   TGraph = Array of TNode;
  15.  
  16. const
  17.   TCities: Array[0..3] of TCity = (NY, LONDON, MOSCU, OTHER);
  18.   CityNames: Array[0..3] of String = ('new york','london','moscu','other city');
  19.   Destinations: Array[0..3] of String = ('london,moscu',
  20.     'moscu',
  21.     '"new york","other city"',
  22.     ''); // 'other city' doesn''t have destinations
  23.  
  24. function AnsiIndexStr(const AText: string; const AValues: array of string): Integer;
  25. var
  26.   i : longint;
  27. begin
  28.   Result := -1;
  29.   if (High(AValues) = -1) or (High(AValues) > MaxInt) Then
  30.     Exit;
  31.   for i := Low(AValues) to High(Avalues) do
  32.       if (avalues[i] = AText) Then
  33.         exit(i);                                 // make sure it is the first val.
  34. end;
  35.  
  36. function MakeGraph: TGraph;
  37. var
  38.   i, j: Integer;
  39.   Edge: Array of Integer;
  40.   DestList: TStringList;
  41.   Graph: TGraph;
  42. begin
  43.   SetLength(Graph, Length(TCities));
  44.   for  i := 0 to Length(TCities) - 1  do
  45.   begin
  46.     DestList := TStringList.Create;
  47.     DestList.Delimiter := ',';
  48.     DestList.DelimitedText := Destinations[i];
  49.     WriteLn('Destinations from ' + CityNames[ord(TCities[i])] + ': ');
  50.     Graph[i].Index := i;
  51.     SetLength(Edge, DestList.Count);
  52.  
  53.     for  j := 0 to pred(DestList.Count)  do
  54.     begin
  55.       WriteLn(DestList[j] + ' ' + IntToStr(AnsiIndexStr(DestList[j], CityNames)));
  56.       Edge[j] := AnsiIndexStr(DestList[j], CityNames);
  57.     end;
  58.  
  59.     WriteLN();
  60.   end;
  61.   Result := Graph;
  62. end;
  63.  
  64. // Returns the index of the lowest value in the array
  65. function MinDist(const q: Set of TNode; const dist: array of Integer): Integer;
  66. var
  67.   ValIdx: Integer;
  68.   MinIdx: Integer = 0;
  69. begin
  70.   if Length(dist) = 0 then Exit(-1);
  71.  
  72.   for ValIdx := 1 to High(dist) do
  73.     if  (ValIdx in q)  and  dist[ValIdx] < dist[MinIdx] then
  74.       MinIdx := ValIdx;
  75.  
  76.   Result := MinIdx;
  77. end;
  78.  
  79. {
  80.   Return an Array where each index position represents a node and the value
  81.   of that position represents the previous node to arrive at it through
  82.   the shortest path from the source node
  83. }
  84. function DijkstraAlgorithm(Graph: TGraph; Source: TNode): Array of Integer;
  85. var
  86.   Neighbor, NewDist: Integer;
  87.   CurrentNode, Node: TNode;
  88.   UnvisitedSet: Set of TNode;
  89.   Dist, Prev: Array of Integer;
  90. begin
  91.   SetLength(Dist, Length(Graph)); SetLength(Prev, Length(Graph));
  92.  
  93.   // Set all the node’s distances to infinity and add them to an unexplored set
  94.   for  Node in Graph  do
  95.   begin
  96.     Distance[Node.index] := MAXINT;
  97.     Previous[Node.index] := -1;
  98.     Include(UnvisitedSet, [Node]);
  99.   end;
  100.   Distance[Source.index] := 0;  // set the starting node’s distance to 0
  101.  
  102.   while  UnvisitedSet <> []  do  // not empty
  103.   begin
  104.     CurrentNode := MinDist(UnvisitedSet, Distance);
  105.     Exclude(UnvisitedSet, [CurrentNode]);
  106.  
  107.     for  Neighbor in CurrentNode.Edges  do
  108.     begin
  109.       if  not Neighbor in UnvisitedSet  then  Continue;
  110.       NewDist := Distance[CurrentNode.Index] + 1;
  111.       if  NewDist < Distance[Neighbor]  then;
  112.       begin
  113.         Distance[Neighbor] := NewDist;
  114.         Previous[Neighbor] := CurrentNode;
  115.       end;
  116.     end;
  117.   end;
  118.   Result := Previous;
  119. end;
  120.  
  121. function  BacktrackDijkstra(Previous: Array of Integer, Dest: Integer);
  122. begin
  123.   if  Previous[Dest] = -1  then
  124.     exit;
  125.  
  126.   // Recursive call
  127.   BacktrackDijkstra(Previous, Previous[Dest]);
  128.  
  129.   // Do whatever you want
  130.   Write(IntToStr(j) + ' ');
  131. end;
  132.  
  133. var
  134.   Graph: TGraph;
  135.   Prev: Array of Integer;
  136.  
  137. procedure Main;
  138. begin
  139.   Graph := MakeGraph();
  140.   Prev := DijkstraAlgorithm(Graph, 1);
  141.   BacktrackDijkstra(Prev, 0);
  142. end;
  143.  
  144. begin
  145.   Main()
  146. end.
  147.  

Handoko

  • Hero Member
  • *****
  • Posts: 5558
  • My goal: build my own game engine using Lazarus
Re: Dijkstra Shortest Path. How to get the result array in correct order.
« Reply #1 on: April 17, 2020, 12:18:21 pm »
I haven't really tested, but as I as I know you cannot use set of or array of something as the type of a parameter.

Code: Pascal  [Select][+][-]
  1. function MinDist(const q: Set of TNode; const dist: array of Integer): Integer;

So the solution should be, declare a new type for them and use them in the parameter of the function:

Code: Pascal  [Select][+][-]
  1. type
  2.   TSetOfNode: set of TNode;
  3.   TArrayOfInteger: array of Integer;
  4.  
  5. function MinDist(q: TSetOfTNode; dist: TArrayOfInteger): Integer;

Also, I'm not very sure but I believe you don't need to use const for the parameters.
« Last Edit: April 17, 2020, 12:25:44 pm by Handoko »

quake004

  • New Member
  • *
  • Posts: 33
Re: Dijkstra Shortest Path. How to get the result array in correct order.
« Reply #2 on: April 17, 2020, 01:22:56 pm »
You mean
Code: Pascal  [Select][+][-]
  1. type
  2.   TSetOfNode = set of TNode;
  3.  

Apparently Set only works for an enumeration so I have to look for another way to group the TNode records.
« Last Edit: April 17, 2020, 01:36:16 pm by quake004 »

Handoko

  • Hero Member
  • *****
  • Posts: 5558
  • My goal: build my own game engine using Lazarus
Re: Dijkstra Shortest Path. How to get the result array in correct order.
« Reply #3 on: April 17, 2020, 01:31:24 pm »
Choosing/creating a suitable data type, can be difficult sometimes. Maybe you can check this:

https://wiki.freepascal.org/Data_Structures,_Containers,_Collections

quake004

  • New Member
  • *
  • Posts: 33
Re: Dijkstra Shortest Path. How to get the result array in correct order.
« Reply #4 on: April 17, 2020, 11:44:02 pm »
I only need the methods Insert, Delete and Contains but I don't know which data structure I can use that accepts my type Record. I've made a priority queue, I have to test it with some sample data.

Handoko

  • Hero Member
  • *****
  • Posts: 5558
  • My goal: build my own game engine using Lazarus
Re: Dijkstra Shortest Path. How to get the result array in correct order.
« Reply #5 on: April 18, 2020, 03:27:52 am »
I knew what Dijkstra Shortest Path is, unfortunately I haven't really explore it. But if you're interested, I found these source codes:

https://ideone.com/Dnh5Zw
http://delphiforfun.org/programs/Math_Topics/ShortestPath.htm
https://github.com/litwr2/dijkstra-algorithm-programs

Thaddy

  • Hero Member
  • *****
  • Posts: 19470
  • Glad to be alive.
Re: Dijkstra Shortest Path. How to get the result array in correct order.
« Reply #6 on: April 18, 2020, 08:21:06 am »
For the set part you can use TSortedHashSet from generics.collections (requires 3.2.0+ or a separate install.)
Here's an example unit that uses it. This one is for large sets, but TSortedHashSet can also be used with Tnode, e.g:
Code: Pascal  [Select][+][-]
  1. TNodeSet  = specialize TSortedHashSet<Tnode >;
This unit merely shows how to extend it with Pascal set operators and serves as an example how to use it
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$inline on}
  2. { A simple way to implement large or huge sets.
  3.  (c) 2019 Thaddy de Koning. No license and not
  4.  re-licensable (except like sqlite licence): free for all to use.
  5.  Copyright holds:
  6.  You can not claim license nor copyrigths }
  7. unit largesets;
  8. { Operator      Action
  9.   ---------------------------------------------
  10.   +             Union
  11.   -             Difference
  12.   *             Intersection
  13.   ><        Symmetric difference
  14.   <=        Contains
  15.   include   Include an element in the set
  16.   exclude   Exclude an element from the set
  17.   in        Check if an element is in a set
  18. }
  19. interface
  20. uses
  21.   generics.collections;
  22.  
  23. type
  24.   TWordSet  = specialize TSortedHashSet<word >;
  25.   { The next two can cause some real memory pressure, be careful }
  26.   TDWordSet = specialize TSortedHashSet<dword>;
  27.   TQWordSet = specialize TSortedHashSet<Qword>;
  28.  
  29.   { union }
  30.   operator + (const a,b:TWordset ):TWordSet;
  31.   operator + (const a,b:TDWordset):TDWordSet;
  32.   operator + (const a,b:TQWordset):TQWordSet;
  33.  
  34.   { difference }
  35.   operator - (const a,b:Twordset ):TWordSet;
  36.   operator - (const a,b:TDwordset):TDWordSet;
  37.   operator - (const a,b:TQwordset):TQWordSet;
  38.  
  39.   { intersection }
  40.   operator * (const a,b:TwordSet ):TWordSet;
  41.   operator * (const a,b:TDwordSet):TDWordSet;
  42.   operator * (const a,b:TQwordSet):TQWordSet;
  43.  
  44.   { symmetric difference }
  45.   operator >< (const a,b:TWordSet ):TWordSet;
  46.   operator >< (const a,b:TDWordSet):TDWordSet;
  47.   operator >< (const a,b:TQWordSet):TQWordSet;
  48.  
  49.   { contains }
  50.   operator <= (const a,b:TWordSet ):Boolean;
  51.   operator <= (const a,b:TDWordSet):Boolean;
  52.   operator <= (const a,b:TQWordSet):Boolean;
  53.  
  54.   { in }
  55.   operator in (const a:word; const b:TWordset ):Boolean;
  56.   operator in (const a:dword;const b:TDWordset):Boolean;
  57.   operator in (const a:qword;const b:TQWordset):Boolean;
  58.  
  59.   { include }
  60.   procedure include(const a:TWordSet; const b:Word);
  61.   procedure include(const a:TDWordSet;const b:DWord);
  62.   procedure include(const a:TQWordSet;const b:QWord);
  63.  
  64.   { exclude }
  65.   procedure exclude(const a:TWordSet;const  b:Word);
  66.   procedure exclude(const a:TDWordSet;const b:DWord);
  67.   procedure exclude(const a:TQWordSet;const b:QWord);
  68.  
  69. implementation
  70.  
  71.   { union }
  72.   operator + (const a,b:TWordset):TWordSet;
  73.   begin  
  74.     b.UnionWith(a);
  75.     Result := b;
  76.   end;  
  77.  
  78.   operator + (const a,b:TDWordset):TDWordSet;
  79.   begin
  80.     b.UnionWith(a);
  81.     Result := b;
  82.   end;
  83.  
  84.   operator + (const a,b:TQWordset):TQWordSet;
  85.   begin
  86.     b.UnionWith(a);
  87.     Result := b;
  88.   end;
  89.  
  90.   { difference }
  91.   operator -(const a,b:Twordset):TWordSet;
  92.   begin
  93.     b.ExceptWith(a);
  94.     result:=b;
  95.   end;
  96.  
  97.   operator -(const a,b:TDwordset):TDWordSet;
  98.   begin
  99.     b.ExceptWith(a);
  100.     result:=b;
  101.   end;
  102.  
  103.   operator -(const a,b:TQwordset):TQWordSet;
  104.   begin
  105.     b.ExceptWith(a);
  106.     result:=b;
  107.   end;
  108.  
  109.   { intersection }
  110.   operator *(const a,b:TwordSet):TWordSet;
  111.   begin
  112.     b.IntersectWith(a);
  113.     Result := b;
  114.   end;
  115.  
  116.   operator *(const a,b:TDwordSet):TDWordSet;
  117.   begin
  118.     b.IntersectWith(a);
  119.     Result := b;
  120.   end;
  121.  
  122.   operator *(const a,b:TQwordSet):TQWordSet;
  123.   begin
  124.     b.IntersectWith(a);
  125.     Result := b;
  126.   end;
  127.  
  128.   { symmetric difference }
  129.   operator ><(const a,b:TWordSet):TWordSet;
  130.   begin
  131.     b.SymmetricExceptWith(a);
  132.     Result := b;
  133.   end;
  134.  
  135.   operator ><(const a,b:TDWordSet):TDWordSet;
  136.   begin
  137.     b.SymmetricExceptWith(a);
  138.     Result := b;
  139.   end;
  140.  
  141.   operator ><(const a,b:TQWordSet):TQWordSet;
  142.   begin
  143.     b.SymmetricExceptWith(a);
  144.     Result := b;
  145.   end;
  146.  
  147.   { contains }
  148.   operator <=(const a,b:TWordSet):Boolean;
  149.   var
  150.     c:word;
  151.   begin
  152.     Result := true;
  153.     for c in a do
  154.     if not b.contains(c) then
  155.     begin
  156.       Result := False;
  157.       break;
  158.     end;
  159.   end;
  160.  
  161.   operator <=(const a,b:TDWordSet):Boolean;
  162.   var
  163.     c:word;
  164.   begin
  165.     Result := true;
  166.     for c in a do
  167.     if not b.contains(c) then
  168.     begin
  169.       Result := False;
  170.       break;
  171.     end;
  172.   end;
  173.  
  174.   operator <=(const a,b:TQWordSet):Boolean;
  175.   var
  176.     c:word;
  177.   begin
  178.     Result := true;
  179.     for c in a do
  180.     if not b.contains(c) then
  181.     begin
  182.       Result := False;
  183.       break;
  184.     end;
  185.   end;
  186.  
  187.   { in }
  188.   operator in (const a:word;const b:TWordset):Boolean;
  189.   begin
  190.     Result := b.Contains(a);
  191.   end;  
  192.  
  193.   operator in (const a:dword;const b:TDWordset):Boolean;
  194.   begin
  195.     Result := b.Contains(a);
  196.   end;
  197.  
  198.   operator in (const a:qword;const b:TQWordset):Boolean;
  199.   begin
  200.     Result := b.Contains(a);
  201.   end;
  202.  
  203.   { include }
  204.   procedure include(const a:TWordSet;const b:Word);
  205.   begin
  206.     a.Add(b);
  207.   end;
  208.  
  209.   procedure include(const a:TDWordSet;const b:DWord);
  210.   begin
  211.     a.Add(b);
  212.   end;
  213.  
  214.   procedure include(const a:TQWordSet;const b:QWord);
  215.   begin
  216.     a.Add(b);
  217.   end;
  218.  
  219.   { exclude }
  220.   procedure exclude(const a:TWordSet;const b:Word);
  221.   begin
  222.     a.Remove(b);
  223.   end;
  224.  
  225.   procedure exclude(const a:TDWordSet;const b:DWord);
  226.   begin
  227.     a.Remove(b);
  228.   end;
  229.  
  230.   procedure exclude(const a:TQWordSet;const b:QWord);
  231.   begin
  232.     a.Remove(b);
  233.   end;
  234. end.

With TSortedHashSet you are already halfway Dijkstra's shortest path. 8-)
« Last Edit: April 18, 2020, 10:07:29 am by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

 

TinyPortal © 2005-2018