Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions source/mir/graph/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import mir.math.common: optmath;
@optmath:

import mir.series;
import mir.rc.array;
import mir.ndslice.iterator: ChopIterator;

///
Expand All @@ -26,6 +27,13 @@ alias Graph(I = uint, J = size_t) = Slice!(GraphIterator!(I, J));
///
alias GraphSeries(T, I = uint, J = size_t) = Series!(T*, GraphIterator!(I, J));

///
alias RCGraphIterator(I = uint, J = size_t) = ChopIterator!(RCI!size_t, RCI!uint);
///
alias RCGraph(I = uint, J = size_t) = Slice!(RCGraphIterator!(I, J));
///
alias RCGraphSeries(T, I = uint, J = size_t) = Series!(RCI!T, RCGraphIterator!(I, J));

/++
Param:
aaGraph = graph that is represented as associative array
Expand Down
94 changes: 66 additions & 28 deletions source/mir/graph/tarjan.d
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ The implementation is loop based. It does not use recursion and does not have st
Complexity: worst-case `O(|V| + |E|)`.

Params:
RC = nogc mode, refcounted output
graph = components (ndslice) sorted in the direction of traversal of the graph. Each component is an array of indeces.
Returns:
components (ndslice of arrays of indexes)
Expand All @@ -44,7 +45,7 @@ See_also:
$(SUBREF utility, graph)
+/
pragma(inline, false)
auto tarjan(G, I = Unqual!(ForeachType!(ForeachType!G)))(G graph)
auto tarjan(bool RC = false, G, I = Unqual!(ForeachType!(ForeachType!G)))(G graph)
if (isUnsigned!I)
{
import mir.utility: min;
Expand Down Expand Up @@ -87,35 +88,49 @@ auto tarjan(G, I = Unqual!(ForeachType!(ForeachType!G)))(G graph)
}
}

bool[] onStack = new bool[graph.length];
I[] stack;
IndexNode[] indeces;
LoopNode[] loopStack;
I index;

sizediff_t stackIndex;
sizediff_t backStackIndex = graph.length;
sizediff_t componentBackStackIndex = graph.length + 1;

if (__ctfe)
static if (RC)
{
stack = new I[graph.length];
indeces = new IndexNode[graph.length];
loopStack = new LoopNode[componentBackStackIndex];
import mir.rc.array;
auto onStack = RCArray!bool(graph.length);
auto stack = RCArray!I(graph.length, true);
auto indeces = RCArray!IndexNode(graph.length, true);
auto loopStack = RCArray!LoopNode(componentBackStackIndex, true);
}
else
{
() @trusted {
import std.array: uninitializedArray;
I[] stack;
IndexNode[] indeces;
LoopNode[] loopStack;

bool[] onStack = new bool[graph.length];
if (__ctfe)
{

stack = new I[graph.length];
indeces = new IndexNode[graph.length];
loopStack = new LoopNode[componentBackStackIndex];
}
else
{
() @trusted {
import std.array: uninitializedArray;

stack = uninitializedArray!(I[])(graph.length);
indeces = uninitializedArray!(IndexNode[])(graph.length);
loopStack = uninitializedArray!(LoopNode[])(componentBackStackIndex);
} ();
stack = uninitializedArray!(I[])(graph.length);
indeces = uninitializedArray!(IndexNode[])(graph.length);
loopStack = uninitializedArray!(LoopNode[])(componentBackStackIndex);
} ();
}
}

foreach(ref node; indeces)
node.index = undefined;

I index;
foreach(size_t v; 0u .. graph.length)
{
if (indeces[v].isUndefined)
Expand Down Expand Up @@ -191,26 +206,42 @@ auto tarjan(G, I = Unqual!(ForeachType!(ForeachType!G)))(G graph)
}
}

S[] pairwiseIndex;
if (__ctfe)
const indexLength = graph.length + 1 - componentBackStackIndex + 1;
static if (RC)
{
pairwiseIndex = new S[graph.length - componentBackStackIndex + 1];
auto pairwiseIndex = RCArray!S(indexLength, true);
}
else
{
() @trusted {
import std.array: uninitializedArray;
pairwiseIndex = uninitializedArray!(S[])(graph.length + 1 - componentBackStackIndex + 1);
} ();
S[] pairwiseIndex;
if (__ctfe)
{
pairwiseIndex = new S[indexLength];
}
else
{
() @trusted {
import std.array: uninitializedArray;
pairwiseIndex = uninitializedArray!(S[])(indexLength);
} ();
}
}
foreach (i, ref e; loopStack[componentBackStackIndex .. $])
foreach (i, ref e; loopStack[][componentBackStackIndex .. $])
{
pairwiseIndex[i] = e.index;
}
pairwiseIndex[$ - 1] = cast(I) graph.length;

import mir.ndslice.topology: chopped;
return (()@trusted {return stack.ptr; }()).chopped(pairwiseIndex);
static if (RC)
{
import core.lifetime: move;
return chopped(RCI!I(stack.move), pairwiseIndex.asSlice);
}
else
{
return (()@trusted {return stack.ptr; }()).chopped(pairwiseIndex);
}
}

/++
Expand Down Expand Up @@ -241,14 +272,21 @@ pure version(mir_test) unittest
"11": [],
].graphSeries;

auto components = gs.data.tarjan;

assert(components == [
static immutable result = [
[0],
[1, 2, 5, 4, 3, 6],
[10],
[7, 8, 9],
[11]]);
[11]];

// chec GC interface
auto components = gs.data.tarjan;
assert(components == result);
// check @nogc interface
// Note: The lambda function is used here to show @nogc mode explicitly.
auto rccomponents = (() @nogc => gs.data.tarjan!true )();
assert(rccomponents == result);
}

/++
Expand Down
4 changes: 2 additions & 2 deletions source/mir/ndslice/topology.d
Original file line number Diff line number Diff line change
Expand Up @@ -3209,7 +3209,7 @@ in
assert(b);
}
do {

import core.lifetime: move;
sizediff_t length = bounds._lengths[0] <= 1 ? 0 : bounds._lengths[0] - 1;
static if (hasLength!Sliceable)
{
Expand All @@ -3222,7 +3222,7 @@ do {
}
}

return typeof(return)([size_t(length)], ChopIterator!(Iterator, Sliceable)(bounds._iterator, sliceable));
return typeof(return)([size_t(length)], ChopIterator!(Iterator, Sliceable)(bounds._iterator.move, sliceable.move));
}

/// ditto
Expand Down
33 changes: 33 additions & 0 deletions source/mir/rc/array.d
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,9 @@ Thread safe reference counting iterator.
+/
struct mir_rci(T)
{
import mir.ndslice.slice: Slice;
import mir.ndslice.iterator: IotaIterator;

///
T* _iterator;

Expand Down Expand Up @@ -479,6 +482,36 @@ struct mir_rci(T)
return _iterator[index];
}

/// Returns: slice type of `Slice!(IotaIterator!size_t)`
Slice!(IotaIterator!size_t) opSlice(size_t dimension)(size_t i, size_t j) @safe scope const
if (dimension == 0)
in
{
assert(i <= j, "RCI!T.opSlice!0: the left opSlice boundary must be less than or equal to the right bound.");
}
body
{
return typeof(return)(j - i, typeof(return).Iterator(i));
}

/// Returns: ndslice on top of the refcounted iterator
auto opIndex(Slice!(IotaIterator!size_t) slice)
{
import core.lifetime: move;
auto it = this;
it += slice._iterator._index;
return Slice!(RCI!T)(slice.length, it.move);
}

/// ditto
auto opIndex(Slice!(IotaIterator!size_t) slice) const
{
import core.lifetime: move;
auto it = lightConst;
it += slice._iterator._index;
return Slice!(RCI!(const T))(slice.length, it.move);
}

///
void opUnary(string op)() scope
if (op == "--" || op == "++")
Expand Down