Skip to content

Commit fd349a1

Browse files
Merge pull request #100 from lifebeyondfife/tarjan-constant
chore(alldifferent): improve cycle detection
2 parents c6d8e52 + 90c3df6 commit fd349a1

3 files changed

Lines changed: 26 additions & 13 deletions

File tree

Csp/Global/CycleDetection.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ private void Connection(Node node, ref int cycles)
3333
node.Index = index;
3434
node.Link = index;
3535
index++;
36+
node.OnStack = true;
3637
nodeStack.Push(node);
3738

3839
foreach (var adjoiningNode in node.AdjoiningNodes)
@@ -42,7 +43,7 @@ private void Connection(Node node, ref int cycles)
4243
Connection(adjoiningNode, ref cycles);
4344
node.Link = Math.Min(node.Link, adjoiningNode.Link);
4445
}
45-
else if (nodeStack.Contains(adjoiningNode))
46+
else if (adjoiningNode.OnStack)
4647
{
4748
node.Link = Math.Min(node.Link, adjoiningNode.Index);
4849
}
@@ -56,6 +57,7 @@ private void Connection(Node node, ref int cycles)
5657
do
5758
{
5859
lastNode = nodeStack.Pop();
60+
lastNode.OnStack = false;
5961
lastNode.CycleIndex = cycles;
6062
stronglyConnectedComponent.Add(lastNode);
6163
} while (node != lastNode);

Csp/Global/Node.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ internal class Node
1313
{
1414
internal int Index { get; set; }
1515
internal int Link { get; set; }
16+
internal bool OnStack { get; set; }
1617
internal LinkedList<Node> AdjoiningNodes { get; set; }
1718
internal string Label { get; private set; }
1819
internal int CycleIndex { get; set; }

Performance/README.md

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,25 +57,35 @@ All benchmarks track the following metrics in the summary table:
5757
- Distinguishes algorithmic improvements (fewer backtracks) from implementation optimizations
5858
- Flags fragile speedups (more backtracks but cheaper per-node cost)
5959

60-
### Example Output
60+
### Latest Results
6161

62-
**Decider Benchmarks:**
62+
**Decider NQueens:**
6363
```
64-
| Method | BoardSize | Mean | Error | StdDev | Backtracks | Gen0 | Allocated |
65-
|---------------------- |---------- |---------:|--------:|--------:|-----------:|---------:|----------:|
66-
| SolveNQueens | 8 | 12.34 ms | 0.12 ms | 0.11 ms | 15,720 | 500.0000 | 4.12 MB |
67-
| SolveNQueens | 10 | 45.67 ms | 0.34 ms | 0.29 ms | 341,318 | 800.0000 | 12.45 MB |
68-
| SolveLeagueGeneration | - | 745.9 ms | 2.35 ms | 2.09 ms | 1,234,567 | 270000.0 | 2.11 GB |
64+
| Method | BoardSize | Mean | Error | StdDev | Backtracks | Gen0 | Gen1 | Gen2 | Allocated |
65+
|------------- |---------- |------------:|-----------:|----------:|-----------:|-------------:|-----------:|----------:|------------:|
66+
| SolveNQueens | 8 | 11.36 ms | 1.951 ms | 0.107 ms | 1,029 | 4765.6250 | 515.6250 | 500.0000 | 36.36 MB |
67+
| SolveNQueens | 10 | 200.58 ms | 5.170 ms | 0.283 ms | 14,036 | 73666.6667 | 1666.6667 | 333.3333 | 589.75 MB |
68+
| SolveNQueens | 12 | 5,098.02 ms | 183.319 ms | 10.048 ms | 278,540 | 1841000.0000 | 30000.0000 | 5000.0000 | 14667.94 MB |
6969
```
7070

71-
**OR-Tools Benchmarks:**
71+
**Decider LeagueGeneration:**
7272
```
73-
| Method | BoardSize | Mean | Error | StdDev | Conflicts | Branches | Gen0 | Allocated |
74-
|------------- |---------- |---------:|--------:|--------:|----------:|----------:|---------:|----------:|
75-
| SolveNQueens | 8 | 10.25 ms | 0.08 ms | 0.07 ms | 12,340 | 24,680 | 400.0000 | 3.45 MB |
76-
| SolveNQueens | 10 | 38.12 ms | 0.29 ms | 0.25 ms | 285,902 | 571,804 | 650.0000 | 10.23 MB |
73+
| Method | Mean | Error | StdDev | Backtracks | Gen0 | Gen1 | Gen2 | Allocated |
74+
|---------------------- |---------:|--------:|--------:|-----------:|------------:|----------:|----------:|----------:|
75+
| SolveLeagueGeneration | 761.9 ms | 7.78 ms | 0.43 ms | 6,249 | 259000.0000 | 2000.0000 | 1000.0000 | 2.07 GB |
7776
```
7877

78+
**OR-Tools NQueens:**
79+
```
80+
| Method | BoardSize | Mean | Error | StdDev | Conflicts | Branches | Allocated |
81+
|------------- |---------- |------------:|-----------:|---------:|----------:|---------:|----------:|
82+
| SolveNQueens | 8 | 12.75 ms | 0.111 ms | 0.006 ms | 650 | 7,238 | 40.68 KB |
83+
| SolveNQueens | 10 | 340.93 ms | 16.757 ms | 0.918 ms | 10,902 | 74,184 | 68.52 KB |
84+
| SolveNQueens | 12 | 4,979.17 ms | 125.127 ms | 6.859 ms | 133,379 | 669,397 | 96.77 KB |
85+
```
86+
87+
> **Note:** OR-Tools allocation figures only reflect .NET managed heap usage (the C# interop layer). The solver itself is written in C++ and allocates on the native heap, which is not tracked by BenchmarkDotNet's `MemoryDiagnoser`. Direct memory comparisons between Decider and OR-Tools are therefore not meaningful.
88+
7989
**Search Metrics Explained:**
8090
- **Backtracks** (Decider): Total backtracks during search - distinguishes algorithmic vs implementation improvements
8191
- **Conflicts** (OR-Tools): Similar to backtracks - number of conflicts encountered

0 commit comments

Comments
 (0)