1 module des.math.graph.fw; 2 3 import std.range; 4 import std.math; 5 import std.traits; 6 import std.algorithm; 7 8 import des.math.graph.base; 9 10 bool hasValue(T)( T v ) @property 11 if( isFloatingPoint!T ) 12 { return abs(v) !is T.nan && abs(v) !is T.infinity; } 13 14 bool hasValue(T)( T v ) @property 15 if( isIntegral!T ) { return v != -1; } 16 17 /// Floyd–Warshall algorithm 18 auto findGraphShortestPathsFW(T)( WTable!T link_table ) 19 { 20 static struct Result 21 { 22 WTable!T W; 23 WTable!ptrdiff_t H; 24 25 auto opIndex( size_t from, size_t to ) const 26 { 27 Path!T ret; 28 if( !W[from,to].hasValue ) return ret; 29 30 ret.cost = W[from,to]; 31 auto s = from; 32 while( s != to ) 33 { 34 ret.nodes ~= s; 35 s = H[s,to]; 36 } 37 ret.nodes ~= to; 38 return ret; 39 } 40 } 41 42 auto N = link_table.size; 43 auto W = WTable!T( N, T.infinity ); 44 auto H = WTable!ptrdiff_t( N, -1 ); 45 46 foreach( from, to, w; link_table ) 47 { 48 if( w.hasValue ) 49 { 50 W[from,to] = w; 51 H[from,to] = to; 52 } 53 } 54 55 foreach( C; iota(N) ) 56 foreach( A; iota(N) ) 57 { 58 if( C == A ) continue; 59 foreach( B; iota(N) ) 60 { 61 if( B == C || B == A ) continue; 62 if( W[A,B] > W[A,C] + W[C,B] ) 63 { 64 W[A,B] = W[A,C] + W[C,B]; 65 H[A,B] = H[A,C]; 66 } 67 } 68 } 69 70 return Result( W, H ); 71 } 72 73 unittest 74 { 75 auto lt = WTable!float( 8, float.nan ); 76 77 lt[0,1] = lt[1,0] = 6.0; 78 lt[0,2] = lt[2,0] = 3.0; 79 lt[0,3] = lt[3,0] = 2.0; 80 81 lt[1,2] = lt[2,1] = 3.0; 82 lt[1,3] = lt[3,1] = 1.0; 83 lt[1,4] = lt[4,1] = 1.0; 84 85 lt[2,5] = lt[5,2] = 7.0; 86 lt[2,7] = lt[7,2] = 6.0; 87 88 lt[3,4] = lt[4,3] = 3.0; 89 90 lt[4,5] = lt[5,4] = 2.0; 91 92 lt[5,7] = lt[7,5] = 1.0; 93 lt[5,6] = lt[6,5] = 3.0; 94 95 lt[6,7] = lt[7,6] = 1.0; 96 97 auto fwr = findGraphShortestPathsFW( lt ); 98 99 auto path = fwr[0,6]; 100 101 assert( equal( path.nodes, [0,3,1,4,5,7,6] ) ); 102 }