1 /++ 2 Basic routines to work with graphs. 3 4 License: $(HTTP www.apache.org/licenses/LICENSE-2.0, Apache-2.0) 5 Copyright: 2020 Ilia Ki, Kaleidic Associates Advisory Limited, Symmetry Investments 6 Authors: Ilia Ki 7 8 Macros: 9 SUBREF = $(REF_ALTTEXT $(TT $2), $2, mir, graph, $1)$(NBSP) 10 T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) 11 +/ 12 13 module mir.graph; 14 15 import mir.math.common: fmamath; 16 17 import mir.series; 18 import mir.rc.array; 19 import mir.ndslice.iterator: ChopIterator; 20 21 /// 22 alias GraphIterator(I = uint, J = size_t) = ChopIterator!(size_t*, uint*); 23 /// 24 alias Graph(I = uint, J = size_t) = Slice!(GraphIterator!(I, J)); 25 /// 26 alias GraphSeries(T, I = uint, J = size_t) = Series!(T*, GraphIterator!(I, J)); 27 28 /// 29 alias RCGraphIterator(I = uint, J = size_t) = ChopIterator!(RCI!size_t, RCI!uint); 30 /// 31 alias RCGraph(I = uint, J = size_t) = Slice!(RCGraphIterator!(I, J)); 32 /// 33 alias RCGraphSeries(T, I = uint, J = size_t) = Series!(RCI!T, RCGraphIterator!(I, J)); 34 35 private static immutable exc_msg = "graphSeries: graph should contains keys for all vertixes"; 36 version(D_Exceptions) 37 { 38 private static immutable exception = new Exception(exc_msg); 39 } 40 41 /++ 42 Params: 43 aaGraph = graph that is represented as associative array 44 Returns: 45 A graph series composed of keys (sorted `.index`) and arrays of indeces (`.data`) 46 Complexity: `O(log(V) (V + E))` 47 +/ 48 @fmamath 49 GraphSeries!(T, I, J) graphSeries(I = uint, J = size_t, T, Range)(in Range[T] aaGraph) 50 { 51 import mir.array.allocation: array; 52 import mir.ndslice.sorting; 53 import mir.ndslice; 54 auto keys = aaGraph.byKey.array.sliced; 55 sort(keys); 56 size_t dataLength; 57 foreach (ref v; aaGraph) 58 dataLength += v.length; 59 auto data = uninitSlice!I(dataLength); 60 auto components = uninitSlice!J(keys.length + 1); 61 size_t dataIndex; 62 63 foreach (i; 0 .. keys.length) 64 { 65 components[i] = cast(J) dataIndex; 66 foreach(ref elem; aaGraph[keys[i]]) 67 { 68 import mir.ndslice.sorting: transitionIndex; 69 auto index = keys.transitionIndex(elem); 70 if (index >= keys.length) 71 { 72 version(D_Exceptions) 73 { import mir.exception : toMutable; throw exception.toMutable; } 74 else 75 assert(0, exc_msg); 76 } 77 data[dataIndex++] = cast(I) index; 78 } 79 } 80 components[keys.length] = dataIndex; 81 auto sliceable = (() @trusted => data.ptr)(); 82 return keys.series(sliceable.chopped(components)); 83 } 84 85 /// 86 pure version(mir_test) unittest 87 { 88 auto gs = [ 89 "b" : ["a"], 90 "a" : ["b", "c"], 91 "c" : ["b"], 92 ].graphSeries; 93 94 assert (gs.index == ["a", "b", "c"]); // sorted 95 assert (gs.data == [ 96 [1, 2], // a 97 [0], // b 98 [1], // c 99 ]); 100 } 101 102 /++ 103 Params: 104 graph = graph that is represented a series 105 Returns: 106 A graph as an arrays of indeces 107 Complexity: `O(log(V) (V + E))` 108 +/ 109 @fmamath 110 RCGraph!(I, J) rcgraph(I = uint, J = size_t, KeyIterator, RangeIterator)(Series!(KeyIterator, RangeIterator) graph) 111 { 112 import mir.array.allocation: array; 113 import mir.ndslice.sorting; 114 import mir.ndslice; 115 auto scopeGraph = graph.lightScope; 116 auto keys = scopeGraph.index; 117 auto graphData = scopeGraph.data; 118 size_t dataLength; 119 foreach (ref v; graphData) 120 dataLength += v.length; 121 auto data = rcslice!I(dataLength); 122 auto components = rcslice!J(keys.length + 1); 123 size_t dataIndex; 124 125 foreach (i; 0 .. keys.length) 126 { 127 components[i] = cast(J) dataIndex; 128 foreach(ref elem; graphData[i]) 129 { 130 import mir.ndslice.sorting: transitionIndex; 131 auto index = keys.transitionIndex(elem); 132 if (index >= keys.length) 133 { 134 version(D_Exceptions) 135 { import mir.exception : toMutable; throw exception.toMutable; } 136 else 137 assert(0, exc_msg); 138 } 139 data[dataIndex++] = cast(I) index; 140 } 141 } 142 components[keys.length] = dataIndex; 143 return data._iterator.chopped(components); 144 } 145 146 /// 147 @safe pure @nogc version(mir_test) 148 unittest 149 { 150 import mir.series: series; 151 152 static immutable keys = ["a", "b", "c"]; 153 static immutable data = [ 154 ["b", "c"], 155 ["a"], 156 ["b"], 157 ]; 158 159 static immutable graphValue = [ 160 [1, 2], // a 161 [0], // b 162 [1], // c 163 ]; 164 165 assert (series(keys, data).rcgraph == graphValue); 166 }