// Tests whether a vertex is simplicial public bool TestSimplicial(FVertex v) { #if !DFS_SIMPLICIALRULE return(false); #else // Signal edges: we remember which edges are currently missing to hopefully speed the check up if (v.SignalA != null && v.SignalB != null && IsVertex(v.SignalA) && IsEdge(v, v.SignalA) && IsEdge(v, v.SignalB) && IsVertex(v.SignalB) && !IsEdge(v.SignalA, v.SignalB)) { return(false); } for (int i = 0; i < v.Degree; i++) { for (int j = 0; j < i; j++) { if (!IsEdge(v.AdjList[i], v.AdjList[j])) { v.SignalA = baseVertices[v.AdjList[i]]; v.SignalB = baseVertices[v.AdjList[j]]; return(false); } } } return(true); #endif }
// Undoes the elimination (or contraction) of a vertex public void Uneliminate() { FVertex restoreVertex = baseVertices[undoStack.Pop().a]; foreach (int u in restoreVertex.Adj) { AddAdj(baseVertices[u], restoreVertex); } currentVertices[vertexCount] = currentVertices[restoreVertex.ListLocation]; currentVertices[restoreVertex.ListLocation].ListLocation = vertexCount; currentVertices[restoreVertex.ListLocation] = restoreVertex; vertexPresent[restoreVertex.Id] = true; vertexCount++; while (undoStack.Count > 0) { UndoInfo ui = undoStack.Peek(); if (ui.b < 0) { break; } undoStack.Pop(); RemoveEdge(ui.a, ui.b); } }
public FastGraph(Graph G) { Vertex[] temp = G.vertices.Keys.ToArray(); vertexCount = temp.Length; vertexPresent = new BitArray(vertexCount); baseVertices = new FVertex[vertexCount]; currentVertices = new FVertex[vertexCount]; adjMatrix = new int[vertexCount, vertexCount]; layerData = new DFSData[vertexCount]; rep = new FVertex[vertexCount]; rank = new int[vertexCount]; degreeLists = new List <int> [vertexCount]; //commonNeighbors = new int[vertexCount, vertexCount]; for (int i = 0; i < vertexCount; i++) { baseVertices[i] = new FVertex(i, i, vertexCount, temp[i]); currentVertices[i] = baseVertices[i]; vertexPresent[i] = true; layerData[i] = new DFSData(vertexCount); degreeLists[i] = new List <int>(); } foreach (Edge e in G.edges) { AddEdge(Array.IndexOf(temp, e.a), Array.IndexOf(temp, e.b)); } }
// Find with path compression FVertex Find(FVertex cur) { if (rep[cur.Id] != cur) { rep[cur.Id] = Find(rep[cur.Id]); } return(rep[cur.Id]); }
// Remove b from a's adj list public void RemoveAdj(FVertex a, FVertex b) { a.AdjVector[b.Id] = false; a.Degree--; a.AdjList[adjMatrix[a.Id, b.Id]] = a.AdjList[a.Degree]; adjMatrix[a.Id, a.AdjList[a.Degree]] = adjMatrix[a.Id, b.Id]; //foreach (int c in b.Adj) //commonNeighbors[a.Id, c]--; }
// Add b to a's adj list public void AddAdj(FVertex a, FVertex b) { a.AdjVector[b.Id] = true; a.AdjList[a.Degree] = b.Id; adjMatrix[a.Id, b.Id] = a.Degree; a.Degree++; //foreach (int c in b.Adj) //commonNeighbors[a.Id, c]++; }
// Adds an edge between a and b, returns true if the edge was added, false if the edge already existed public bool AddEdge(FVertex a, FVertex b) { if (IsEdge(a, b)) { return(false); } AddAdj(a, b); AddAdj(b, a); return(true); }
// Attempts to remove the edge between a and b, returns true if the edge was removed, false if the edge does not exist public bool RemoveEdge(FVertex a, FVertex b) { if (!IsEdge(a, b)) { return(false); } RemoveAdj(a, b); RemoveAdj(b, a); return(true); }
// Remove vertex and incident edges public void RemoveVertex(FVertex a) { foreach (int u in a.Adj) { RemoveAdj(baseVertices[u], a); } vertexCount--; currentVertices[a.ListLocation] = currentVertices[vertexCount]; currentVertices[vertexCount].ListLocation = a.ListLocation; vertexPresent[a.Id] = false; undoStack.Push(new UndoInfo(a.Id, -1)); }
// Eliminate a vertex public void EliminateVertex(FVertex a) { foreach (int u in a.Adj) { foreach (int v in a.Adj) { if (u < v && AddEdge(u, v)) { undoStack.Push(new UndoInfo(u, v)); } } } RemoveVertex(a); }
// Union by rank void Union(FVertex x, FVertex y) { x = Find(x); y = Find(y); if (rank[x.Id] < rank[y.Id]) { rep[x.Id] = y; } else { rep[y.Id] = x; if (rank[x.Id] == rank[y.Id]) { rank[x.Id]++; } } }
// Tests whether a vertex is almost simplicial public bool TestAlmostSimplicial(FVertex v, int upper) { #if !DFS_ALMOSTSIMPLICIALRULE return(false); #else if (v.Degree >= upper) { return(false); } int sa = v.SignalA.Id, sb = v.SignalB.Id; for (int i = 0; i < v.Degree; i++) { for (int j = 0; j < i; j++) { if (!IsEdge(v.AdjList[i], v.AdjList[j])) { if ((i == sa && j == sb) || (j == sa && i == sb)) { continue; } else if (i == sa || j == sa) { sb = sa; } else if (i == sb || j == sb) { sa = sb; } else { return(false); } } } } return(true); #endif }
public List <int> DFS(int upper, FVertex prev) { // Keep track of current elimination order if (prev != null) { currentOrder.RemoveRange(baseVertices.Length - vertexCount - 1, currentOrder.Count - (baseVertices.Length - vertexCount - 1)); currentOrder.Add(prev); } // Apply DVS pruning rule currentLayer.DVS.Clear(); if (!ComputeDVS(true)) { return(null); } ComputeDVS(false); // Use MMW or not #if DFS_MMW int lb = MMW(upper); #elif DFS_MMW_LIMITED int lb = baseVertices.Length - vertexCount < 7 ? MMW(upper) : 0; #else int lb = 0; #endif Program.TotalExpanded++; // Statistics //if (Program.TotalExpanded % 100000 == 1) Console.WriteLine(Program.TotalExpanded / 1000 + ",000 " + upper + " " + baseVertices.Length + " " + lb + " " + vertexCount + " " + currentLayer.DVS.Count()); // Inreasible? if (lb > upper) { return(null); } // Are we done because any order will work from this point? if (vertexCount <= upper) { return(Vertices.Select(v => v.Id).ToList()); } // Try to find the highest-degree (almost)-simplicial vertex FVertex simplicialVertex = null; foreach (FVertex v in Vertices) { if ((simplicialVertex == null || v.Degree > simplicialVertex.Degree) && (TestSimplicial(v) || TestAlmostSimplicial(v, upper))) { simplicialVertex = v; if (v.Degree >= upper) { return(null); } } } // We found a simplicial vertex if (simplicialVertex != null) { // Pruned due to nogoods if (currentLayer.nogoods.Contains(simplicialVertex)) { return(null); } // A nogood vertex becomes good if we eliminate a vertex adjacent to it List <FVertex> newnogoods = nextLayer.nogoods; newnogoods.Clear(); foreach (FVertex u in currentLayer.nogoods) { if (!IsEdge(u, simplicialVertex)) { newnogoods.Add(u); } } // Eliminate and go deeper EliminateVertex(simplicialVertex); EdgeAddition(upper); List <int> result = DFS(upper, simplicialVertex); Uneliminate(); // Feasible if (result != null) { result.Add(simplicialVertex.Id); return(result); } // Not feasible return(null); } // Branching! foreach (FVertex v in Vertices) { // Check nogoods, and we never need to eliminate two adjacent vertices subsequently (note that we can not apply this latter rule to prune simplicial vertices) if (currentLayer.nogoods.Contains(v) || (prev != null && IsEdge(prev, v))) { continue; } if (v.Degree < upper) { // A nogood vertex becomes good if we eliminate a vertex adjacent to it List <FVertex> newnogoods = nextLayer.nogoods; newnogoods.Clear(); foreach (FVertex u in currentLayer.nogoods) { if (!IsEdge(u, v)) { newnogoods.Add(u); } } // Eliminate and go deeper EliminateVertex(v); EdgeAddition(upper); List <int> result = DFS(upper, v); Uneliminate(); // Found a solution if (result != null) { result.Add(v.Id); return(result); } // In next layers, do not eliminate v before eliminating a neighbor of v currentLayer.nogoods.Add(v); } } // We didn't manage to find a solution in this branch return(null); }
// Computes the minor-min-width LB heuristic public int MMW(int upper) { int oldCount = vertexCount; foreach (FVertex v in Vertices) { degreeLists[v.Degree].Add(v.Id); } int min = 0; int lb = upper; while (vertexCount > 0) { // We won't be able to find a better bound this way (max degree = upper - 1) if (vertexCount <= lb) { break; } // We use a priority queue implemented by having a list for each priority, to find the smallest vertex more quickly // Idea due to Dow and Korf FVertex minDegree = null; while (true) { while (degreeLists[min].Count == 0) { min++; } minDegree = baseVertices[degreeLists[min][degreeLists[min].Count - 1]]; degreeLists[min].RemoveAt(degreeLists[min].Count - 1); if (minDegree.Degree == min && IsVertex(minDegree)) { break; } } lb = Math.Max(lb, minDegree.Degree + 1); // We already found a good enough bound if (lb > upper) { break; } // Find neighbor with least number of common edges FVertex minNb = null; int mintersect = int.MaxValue; foreach (int v in minDegree.Adj) { int mytersect = CommonNB(minDegree, baseVertices[v]); if (mytersect < mintersect || (mytersect == mintersect && baseVertices[v].Degree > minNb.Degree)) { mintersect = mytersect; minNb = baseVertices[v]; } } // We are going to contract minDegree into minNb foreach (int u in minDegree.Adj) { if (u == minNb.Id) { continue; } if (AddEdge(u, minNb.Id)) { undoStack.Push(new UndoInfo(u, minNb.Id)); } else { degreeLists[baseVertices[u].Degree - 1].Add(u); min = Math.Min(min, baseVertices[u].Degree - 1); } } RemoveVertex(minDegree); degreeLists[minNb.Degree].Add(minNb.Id); min = Math.Min(min, minNb.Degree); } // Restore the damage while (vertexCount < oldCount) { Uneliminate(); } while (min < vertexCount) { degreeLists[min++].Clear(); } return(lb); }
// Tests whether a given vertex is currently in the graph public bool IsVertex(FVertex v) { return(IsVertex(v.Id)); }
public bool IsEdge(FVertex a, FVertex b) { return(IsEdge(a.Id, b.Id)); }
public int CommonNB(FVertex a, FVertex b) { return(a.AdjVector.XORCount(b.AdjVector)); }