public ConflictGraph(ConflictGraph other) { this.numOfEdges = other.numOfEdges; this.numOfNodes = other.numOfNodes; this.G = new bool[other.G.GetLength(0), other.G.GetLength(1)]; Array.Copy(other.G, G, G.Length); }
/// <summary> /// Return whether there exists a k-vertex (at most) cover solution (an NP-Complete question). /// This algorithm theoretically runs in O(2^(k-1)*2*n), or O(2^k*n). It was described in Parameterized /// Computational Feasibility (Downey and Fellows, 1995). /// The algorithm with the best asymptotic dependence on k was desribed in Improved /// Parameterized Upper Bounds for Vertex Cover (Cheng, Kanj and Xia 2006) and has a runtime of /// O(1.2738^k + kn). Even that algorithm can only find a vertex cover of size up to ~190 in /// reasonable time. /// </summary> private static bool KVertexCover(ConflictGraph CG, int k, int lastEdgeX = 0) { if (CG.numOfEdges == 0) { return(true); } else if (CG.numOfEdges > k * CG.numOfNodes - k) // |E| > K*(|V|-1), there are more edges // to cover than the maximum number of edges that could be covered with K vertices // (if every vertex chosen for the cover is connected to all other vertices in the graph), // so a K vertex cover is impossible { return(false); } // Choose an edge (u,v) - (this step is actually O(n^2) but the algorithm assumes is done in constant time) // TODO: Measure if this part is significant int[] edge = new int[2]; bool found = false; for (int i = lastEdgeX; i < CG.G.GetLength(0) - 1 && !found; i++) { for (int j = i + 1; j < CG.G.GetLength(1) && !found; j++) { if (CG.G[i, j]) { edge[0] = i; edge[1] = j; found = true; } } } // Recurse over KVertexCover(G-{u}, k-1) and KVertexCover(G-{v}, k-1). // If any are true, return true. Else return false. for (int i = 0; i < 2; i++) { ConflictGraph CG_copy = new ConflictGraph(CG); // TODO: This part also costs n^2 for (int j = 0; j < CG.G.GetLength(0); j++) { if (CG_copy.G[edge[i], j]) { CG_copy.G[edge[i], j] = false; CG_copy.G[j, edge[i]] = false; CG_copy.numOfEdges--; } } CG_copy.numOfNodes--; if (KVertexCover(CG_copy, k - 1, edge[0])) { return(true); } } return(false); }
/// <summary> /// Lazy version /// </summary> /// <param name="s"></param> /// <param name="target"></param> /// <returns></returns> public uint h(CbsNode s, int target) { Debug.WriteLine($"Computing heuristic estimate for node hash {s.GetHashCode()}"); if (target != int.MaxValue && ( (s.prev != null && s.prev.minimumVertexCover != (int)ConflictGraph.MinVertexCover.NOT_SET && target > s.prev.minimumVertexCover + 1) || (target > s.totalInternalAgentsThatConflict)) ) { Debug.WriteLine($"Target estimate {target} was too high!"); this.targetClearlyTooHigh++; return(0); // We can't give a higher estimate than the size of the parent's MVC + 1, // or the max number of vertices in this agent's conflict graph // see comments in ConflictGraph.MinimumVertexCover for details. // 0 just signals we couldn't raise the h enough. } ConflictGraph CardinallyConflictingAgents = new ConflictGraph(s.singleAgentPlans.Length); ISet <int>[] groups = s.GetGroups(); // Populate the cardinal conflict graph foreach (var agentIndex in Enumerable.Range(0, s.singleAgentPlans.Length)) { if (s.conflictTimesPerAgent[agentIndex].Count == 0) { continue; // Agent has no conflicts } bool hasMdd = s.mddNarrownessValues[agentIndex] != null; foreach (int conflictingAgentNum in s.conflictTimesPerAgent[agentIndex].Keys) { int conflictingAgentIndex = s.agentNumToIndex[conflictingAgentNum]; if (conflictingAgentIndex < agentIndex) // check later { continue; } bool otherHasMdd = s.mddNarrownessValues[conflictingAgentIndex] != null; foreach (int conflictTime in s.conflictTimesPerAgent[agentIndex][conflictingAgentNum]) { if (otherHasMdd == false || s.DoesAgentHaveNoOtherOption(conflictingAgentIndex, conflictTime, agentIndex, groups)) // Other agent's MDD is narrow at this timestep. { s.buildMddForAgentWithItsCurrentCost(agentIndex); hasMdd = true; } else { continue; } bool iNarrow = s.DoesAgentHaveNoOtherOption(agentIndex, conflictTime, conflictingAgentIndex, groups); if (iNarrow == false) { continue; } if (otherHasMdd == false) { s.buildMddForAgentWithItsCurrentCost(conflictingAgentIndex); otherHasMdd = true; } bool jNarrow = s.DoesAgentHaveNoOtherOption(conflictingAgentIndex, conflictTime, agentIndex, groups); if (jNarrow) // Cardinal conflict - both agent's MDDs are narrow at this timestep. { CardinallyConflictingAgents.Add(agentIndex, conflictingAgentIndex); } } } } if (s.prev == null || s.prev.minimumVertexCover == (int)ConflictGraph.MinVertexCover.NOT_SET) { s.minimumVertexCover = CardinallyConflictingAgents.MinimumVertexCover(); } else { s.minimumVertexCover = CardinallyConflictingAgents.MinimumVertexCover(s.prev.minimumVertexCover); } if (target != int.MaxValue) { if (s.minimumVertexCover >= target) { Debug.WriteLine($"Target estimate {target} reached"); this.targetReached++; } else { Debug.WriteLine($"Target estimate {target} not reached"); this.targetNotReached++; } } return((uint)s.minimumVertexCover); }