more GC optimizations

master
Evan Hemsley 2019-10-23 17:31:22 -07:00
parent a08a39c353
commit 6b257a9661
5 changed files with 74 additions and 41 deletions

View File

@ -280,7 +280,7 @@ namespace MoonTools.Core.Graph
s.Remove(neighbor); s.Remove(neighbor);
t.Add(neighbor); t.Add(neighbor);
if (s.Count == 0) { lexicographicSets.Remove(s); replacedSets.Remove(s); } if (s.Count == 0) { lexicographicSets.Remove(s); replacedSets.Remove(s); s.Dispose(); }
} }
} }
} }
@ -298,20 +298,20 @@ namespace MoonTools.Core.Graph
{ {
return PostorderNodeDFS().Reverse(); return PostorderNodeDFS().Reverse();
} }
List<PooledList<TNode>> sccs = new List<PooledList<TNode>>();
readonly Dictionary<TNode, uint> preorder = new Dictionary<TNode, uint>();
readonly Dictionary<TNode, uint> lowlink = new Dictionary<TNode, uint>();
readonly Dictionary<TNode, bool> sccFound = new Dictionary<TNode, bool>();
readonly Stack<TNode> sccQueue = new Stack<TNode>();
readonly List<List<TNode>> sccResult = new List<List<TNode>>();
public IEnumerable<IEnumerable<TNode>> StronglyConnectedComponents() public IEnumerable<IEnumerable<TNode>> StronglyConnectedComponents()
{ {
preorder.Clear(); foreach (var scc in sccs)
lowlink.Clear(); {
sccFound.Clear(); scc.Dispose();
sccQueue.Clear(); }
sccResult.Clear(); sccs.Clear();
var preorder = new PooledDictionary<TNode, uint>();
var lowlink = new PooledDictionary<TNode, uint>();
var sccFound = new PooledDictionary<TNode, bool>();
var sccQueue = new PooledStack<TNode>();
uint preorderCounter = 0; uint preorderCounter = 0;
@ -364,7 +364,7 @@ namespace MoonTools.Core.Graph
if (lowlink[v] == preorder[v]) if (lowlink[v] == preorder[v])
{ {
sccFound[v] = true; sccFound[v] = true;
var scc = new List<TNode> var scc = new PooledList<TNode>
{ {
v v
}; };
@ -374,7 +374,9 @@ namespace MoonTools.Core.Graph
sccFound[k] = true; sccFound[k] = true;
scc.Add(k); scc.Add(k);
} }
sccResult.Add(scc);
sccs.Add(scc);
yield return scc;
} }
else else
{ {
@ -384,8 +386,6 @@ namespace MoonTools.Core.Graph
} }
} }
} }
return sccResult;
} }
public IEnumerable<IEnumerable<TNode>> SimpleCycles() public IEnumerable<IEnumerable<TNode>> SimpleCycles()

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Collections.Pooled;
using MoreLinq; using MoreLinq;
namespace MoonTools.Core.Graph namespace MoonTools.Core.Graph
@ -12,13 +13,6 @@ namespace MoonTools.Core.Graph
protected Dictionary<(TNode, TNode), TEdgeData> edgeToEdgeData = new Dictionary<(TNode, TNode), TEdgeData>(); protected Dictionary<(TNode, TNode), TEdgeData> edgeToEdgeData = new Dictionary<(TNode, TNode), TEdgeData>();
protected Dictionary<(TNode, TNode), int> weights = new Dictionary<(TNode, TNode), int>(); protected Dictionary<(TNode, TNode), int> weights = new Dictionary<(TNode, TNode), int>();
// store search sets to prevent GC
protected HashSet<TNode> openSet = new HashSet<TNode>();
protected HashSet<TNode> closedSet = new HashSet<TNode>();
protected Dictionary<TNode, int> gScore = new Dictionary<TNode, int>();
protected Dictionary<TNode, int> fScore = new Dictionary<TNode, int>();
protected Dictionary<TNode, TNode> cameFrom = new Dictionary<TNode, TNode>();
public IEnumerable<TNode> Nodes => nodes; public IEnumerable<TNode> Nodes => nodes;
public void AddNode(TNode node) public void AddNode(TNode node)
@ -107,7 +101,7 @@ namespace MoonTools.Core.Graph
return edgeToEdgeData[(v, u)]; return edgeToEdgeData[(v, u)];
} }
private IEnumerable<(TNode, TNode)> ReconstructPath(Dictionary<TNode, TNode> cameFrom, TNode currentNode) private IEnumerable<(TNode, TNode)> ReconstructPath(PooledDictionary<TNode, TNode> cameFrom, TNode currentNode)
{ {
while (cameFrom.ContainsKey(currentNode)) while (cameFrom.ContainsKey(currentNode))
{ {
@ -121,11 +115,11 @@ namespace MoonTools.Core.Graph
{ {
CheckNodes(start, end); CheckNodes(start, end);
openSet.Clear(); var openSet = new PooledSet<TNode>(ClearMode.Always);
closedSet.Clear(); var closedSet = new PooledSet<TNode>(ClearMode.Always);
gScore.Clear(); var gScore = new PooledDictionary<TNode, int>(ClearMode.Always);
fScore.Clear(); var fScore = new PooledDictionary<TNode, int>(ClearMode.Always);
cameFrom.Clear(); var cameFrom = new PooledDictionary<TNode, TNode>(ClearMode.Always);
openSet.Add(start); openSet.Add(start);
@ -138,7 +132,19 @@ namespace MoonTools.Core.Graph
if (currentNode.Equals(end)) if (currentNode.Equals(end))
{ {
return ReconstructPath(cameFrom, currentNode).Reverse(); openSet.Dispose();
closedSet.Dispose();
gScore.Dispose();
fScore.Dispose();
foreach (var edge in ReconstructPath(cameFrom, currentNode).Reverse())
{
yield return edge;
}
cameFrom.Dispose();
yield break;
} }
openSet.Remove(currentNode); openSet.Remove(currentNode);
@ -163,7 +169,13 @@ namespace MoonTools.Core.Graph
} }
} }
return Enumerable.Empty<(TNode, TNode)>(); openSet.Dispose();
closedSet.Dispose();
gScore.Dispose();
fScore.Dispose();
cameFrom.Dispose();
yield break;
} }
} }
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Collections.Pooled;
using MoreLinq; using MoreLinq;
namespace MoonTools.Core.Graph namespace MoonTools.Core.Graph
@ -120,7 +121,7 @@ namespace MoonTools.Core.Graph
return edgeToEdgeData[id]; return edgeToEdgeData[id];
} }
private IEnumerable<Guid> ReconstructPath(Dictionary<TNode, Guid> cameFrom, TNode currentNode) private IEnumerable<Guid> ReconstructPath(PooledDictionary<TNode, Guid> cameFrom, TNode currentNode)
{ {
while (cameFrom.ContainsKey(currentNode)) while (cameFrom.ContainsKey(currentNode))
{ {
@ -135,11 +136,11 @@ namespace MoonTools.Core.Graph
{ {
CheckNodes(start, end); CheckNodes(start, end);
openSet.Clear(); var openSet = new PooledSet<TNode>(ClearMode.Always);
closedSet.Clear(); var closedSet = new PooledSet<TNode>(ClearMode.Always);
gScore.Clear(); var gScore = new PooledDictionary<TNode, int>(ClearMode.Always);
fScore.Clear(); var fScore = new PooledDictionary<TNode, int>(ClearMode.Always);
cameFrom.Clear(); var cameFrom = new PooledDictionary<TNode, Guid>(ClearMode.Always);
openSet.Add(start); openSet.Add(start);
@ -152,7 +153,19 @@ namespace MoonTools.Core.Graph
if (currentNode.Equals(end)) if (currentNode.Equals(end))
{ {
return ReconstructPath(cameFrom, currentNode).Reverse(); openSet.Dispose();
closedSet.Dispose();
gScore.Dispose();
fScore.Dispose();
foreach (var edgeID in ReconstructPath(cameFrom, currentNode).Reverse())
{
yield return edgeID;
}
cameFrom.Dispose();
yield break;
} }
openSet.Remove(currentNode); openSet.Remove(currentNode);
@ -178,7 +191,13 @@ namespace MoonTools.Core.Graph
} }
} }
return Enumerable.Empty<Guid>(); openSet.Dispose();
closedSet.Dispose();
gScore.Dispose();
fScore.Dispose();
cameFrom.Dispose();
yield break;
} }
} }
} }

View File

@ -218,7 +218,8 @@ namespace Tests
.And .And
.HaveCount(3); .HaveCount(3);
myGraph.Invoking(x => x.AStarShortestPath('a', 'z', (x, y) => 15)).Should().Throw<System.ArgumentException>(); // have to call Count() because otherwise the lazy evaluation wont trigger
myGraph.Invoking(x => x.AStarShortestPath('a', 'z', (x, y) => 1).Count()).Should().Throw<System.ArgumentException>();
} }
} }
} }

View File

@ -248,7 +248,8 @@ namespace Tests
.And .And
.HaveCount(3); .HaveCount(3);
myGraph.Invoking(x => x.AStarShortestPath('a', 'z', (x, y) => 15)).Should().Throw<System.ArgumentException>(); // have to call Count() because otherwise the lazy evaluation wont trigger
myGraph.Invoking(x => x.AStarShortestPath('a', 'z', (x, y) => 1).Count()).Should().Throw<System.ArgumentException>();
} }
} }
} }