private void ENUM_MAXIMUM_MATCHINGS(BipartiteGraph G, bool getAllMatchings) { /*------------------------------------------------------------------------------------------------------------------- * Step1: Find a maximum matching M of G and output M. * ------------------------------------------------------------------------------------------------------------------*/ EdgeList M = MaximumMatching.Get(G); //Edges of Matching MatchingList matching = EdgeListToMatching(M); matching.Sort(); FindOverconstrainedModelsReversalCost(matching); if (OverConstrainedModels.Count > 0) { OverConstrained = true; return; } AddMatching(matching); if (MinimumCost > minimumAchievableCost) { /*------------------------------------------------------------------------------------------------------------------- * Step2: Trim unnecessary arcs from D(G,M) by a strongly connected component decomposition algorithm. * ------------------------------------------------------------------------------------------------------------------*/ //Need further action on this to trim edges after finding SCCs in a D(G,M). Here only SCCs are found. Edges are not trimmed yet. //Graph D_GM = Get_D_GM(G.Clone(), M); //Directed graph is obtained here with reversing edges of matchingEdges. //List<List<GraphNode>> sCCs = TarjanCycleDetect.DetectCycle(D_GM); /*------------------------------------------------------------------------------------------------------------------- * Step3: Call ENUM_MAXIMUM_MATCHINGS_ITER(G, M, D(G,M)) * ------------------------------------------------------------------------------------------------------------------*/ if (getAllMatchings) { ENUM_MAXIMUM_MATCHINGS_ITER(G.Clone(), M, matching, 0); } } FilterDuplicateMatchings(); }
//This method find the corresponding edges of matching M(which contains edges from other Graph) for the given Graph G private static EdgeList CorrespondingEdgeList(BipartiteGraph G, EdgeList M) { var corresponding = new EdgeList(); foreach (Edge edge in M) { GraphNode from = G.GetNode(edge.FromNode.Value); GraphNode to = G.GetNode(edge.ToNode.Value); if (from == null && to == null) { continue; } if (G.Edges.FindByNodes(from, to) != null) { corresponding.Add(G.Edges.FindByNodes(from, to)); } else { corresponding.Add(G.Edges.FindByNodes(to, from)); } } return(corresponding); }
private EdgeList MatchingToEdgeList(BipartiteGraph G, MatchingList M_String) { var edgeList = new EdgeList(); foreach (string edg in M_String) { GraphNode node1 = G.GetNode(edg.Split('-')[0]); GraphNode node2 = G.GetNode(edg.Split('-')[1]); if (G.Contains(node1, node2)) { edgeList.Add(G.Edges.FindByNodes(node1, node2)); } else if (G.Contains(node2, node1)) { edgeList.Add(G.Edges.FindByNodes(node2, node1)); } //else //{ // M_to_EdgeListM.Add(new Edge(nd1,nd2,0)); //} } return(edgeList); }
private static EdgeList CorrespondingListForTheGraph(BipartiteGraph G, EdgeList M) //This method find the corresponding edges of matching M(which contains edges from other Graph) for the given Graph G { var M_corresp = new EdgeList(); foreach (Edge edg in M) { GraphNode frm = G.GetNode(edg.FromNode.Value); GraphNode to = G.GetNode(edg.ToNode.Value); if (frm == null && to == null) { goto xyz; } if (G.Edges.FindByNodes(frm, to) != null) { M_corresp.Add(G.Edges.FindByNodes(frm, to)); } else { M_corresp.Add(G.Edges.FindByNodes(to, frm)); } xyz :; } return(M_corresp); }
//Here matching edges nodes are checked if it is model or variable //And then directed graph is created, where matching edges are oriented from model to variable whereas, //other graph edges(original graph edges) are from variable to model. public BipartiteGraph GetDirectedGraphAsPerMatching(EdgeList M) { foreach (Edge edge in M) { GraphNode from = edge.FromNode; GraphNode to = edge.ToNode; if (from != null && to != null) { if (from.NodeType == GraphNode.Type.Type2) { if (Contains(from, to)) { RemoveDirectedEdge(to, from); } else if (Contains(to, from)) { RemoveDirectedEdge(to, from); AddDirectedEdge(from, to, 0, 0); } } else { if (Contains(from, to)) { RemoveDirectedEdge(from, to); AddDirectedEdge(to, from, 0, 0); } else if (Contains(to, from)) { RemoveDirectedEdge(from, to); } } } } return(this); }
//This code has been tested and works fine for test-case under consideration private void ENUM_MAXIMUM_MATCHINGS_ITER(BipartiteGraph G, EdgeList M, MatchingList matching, int recursionLevel) { //System.Console.WriteLine(recursionLevel); //System.Console.WriteLine(recursionLevel); if (recursionLevel >= MaximumRecursionLevel) { return; } /*------------------------------------------------------------------------------------------------------------------- * Step1: If G has no edge, stop. * ------------------------------------------------------------------------------------------------------------------*/ if (G.Edges.Count <= 1) { return; } /*------------------------------------------------------------------------------------------------------------------- * Step2: If D(G,M) contains no cylce, Go to Step8. * ------------------------------------------------------------------------------------------------------------------*/ BipartiteGraph directedGraph = G.Clone().GetDirectedGraphAsPerMatching(M); var CIDG = new CycleInDirectedGraph(directedGraph); //Class object containing Method to detect and get cycle in a grah Edge e; MatchingList Mdash; BipartiteGraph Gplus, Gminus; if (CIDG.HasCycle) { /*------------------------------------------------------------------------------------------------------------------- * Step3 & 4: Choose an edge e as the same manner in ENUM_PERFECT_MATCHINGS_ITER. * Find a cycle containing e by a depth-first-search algorithm. * ------------------------------------------------------------------------------------------------------------------*/ // Cycle is found using DFS algorithm and edge-e is chosen such that it is in cycle and in matching M // ( and not in M'(which is found next)) of the directed graph(DG) List <GraphNode> cycle = CIDG.Cycle; //returns here cycle in a directed graph DG //'Cycle': Vertices can not repeate and Edges can not repeat EdgeList cycleEdges = directedGraph.ToEdges(cycle); //cycleInDG is list of nodes in a Cycle . Here this list is converted into edges in the Cycle. EdgeList MEdgeList = CorrespondingEdgeList(directedGraph, M); e = ChooseEdge(MEdgeList, cycleEdges); //Edge - e is chosen here. /*------------------------------------------------------------------------------------------------------------------- * Step5: Exchange edges along the cycle and output the obtained maximum matching M'. * ------------------------------------------------------------------------------------------------------------------*/ Mdash = ExchangeEdgesAlongCycleOrPath(matching, CycleToMatching(cycle)); //this.matchingToStringList(M) Mdash.Sort(); AddMatching(Mdash); if (MinimumCost > minimumAchievableCost) { /*------------------------------------------------------------------------------------------------------------------- * Step6: Enumerate all maximum matchings including e by ENUM_MAXIMUM_MATCHINGS_ITER with G+(e), M and trimmed D(G+(e), M\e). * ------------------------------------------------------------------------------------------------------------------*/ Gplus = BuildGplus(G, e); //G+(e) is obtained here //!! here G+(e) graph will not have edge which is there in matching ENUM_MAXIMUM_MATCHINGS_ITER(Gplus, M, matching, recursionLevel + 1); //recursive call with G+(e) and M /*------------------------------------------------------------------------------------------------------------------- * Step7: Enumerate all maximum matchings not including e by ENUM_MAXIMUM_MATCHINGS_ITER with G-(e), M' and trimmed D(G-(e), M'). Stop. * ------------------------------------------------------------------------------------------------------------------*/ Gminus = BuildGminus(G, e); //G-(e) is obtained here ENUM_MAXIMUM_MATCHINGS_ITER(Gminus, MatchingToEdgeList(Gminus, Mdash), Mdash, recursionLevel + 1); //recursive call with G-(e) and M } return; } /*---------------------------------------------------------------------------------------------------------------------- * Step8: Find a feasible path with length 2 and generate a new maximum matching M'. * Let e be the edge of the path not included in M. * ------------------------------------------------------------------------------------------------------------------*/ //'Feasible Path': NodeList unmatchedVertices = directedGraph.GetUnmatchedVertices(matching); var path = new MatchingList(); foreach (GraphNode node in directedGraph) { if (node.NodeType == GraphNode.Type.Type1 || node.NodeType == GraphNode.Type.Type2 && !unmatchedVertices.Contains(node)) { var dfs = new DepthFirstSearch(directedGraph, node, unmatchedVertices); path = dfs.length2Path; if (path.Count == 3 && IsFeasiblePath(directedGraph, path, unmatchedVertices)) { break; } } } if (path.Count != 3) { return; } e = GetEdgeInPathNotInM(G, matching, PathToMatching(G, path)); Mdash = ExchangeEdgesAlongCycleOrPath(matching, PathToMatching(G, path)); Mdash.Sort(); AddMatching(Mdash); if (MinimumCost > minimumAchievableCost) { /*------------------------------------------------------------------------------------------------------------------- * Step9: Call ENUM_MAXIMUM+MATCHINGS_ITER(G+(e), M', theta). * -* ------------------------------------------------------------------------------------------------------------------*/ Gplus = BuildGplus(G, e); //G+(e) is obtained here ENUM_MAXIMUM_MATCHINGS_ITER(Gplus, MatchingToEdgeList(Gplus, Mdash), Mdash, recursionLevel + 1); /*------------------------------------------------------------------------------------------------------------------- * Step10: Call ENUM_MAXIMUM+MATCHINGS_ITER(G-(e), M, theta). * ------------------------------------------------------------------------------------------------------------------*/ Gminus = BuildGminus(G, e); //G-(e) is obtained here ENUM_MAXIMUM_MATCHINGS_ITER(Gminus, M, matching, recursionLevel + 1); } }
private void ENUM_PERFECT_MATCHINGS_ITER(BipartiteGraph G, EdgeList M, List <string> M_String) { /*------------------------------- * Step1: If G has no edge, stop. * ---------------------------------*/ if (G.Edges.Count == 0) { return; } /*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Step2 & Step3: Choosing Edge-e and Finding Cycle. //Cycle is found using DFS algorithm and edge-e is chosen such that it is in cycle and in matching M ( and not in M'(which is found next)) of the directed graph(DG) * ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ BipartiteGraph d_G = G.Clone().GetDirectedGraphAsPerMatching(M); var CIDG = new CycleInDirectedGraph(d_G); //Class object containing Method to detect and get cycle in a grah if (!CIDG.HasCycle) { return; } List <GraphNode> cycleInDG = CIDG.Cycle; //returns here cycle in a directed graph DG //Cycle: Vertices can not repeate and Edges can not repeat EdgeList cycleInDG_Edges = d_G.ToEdges(cycleInDG); //cycleInDG is list of nodes in a Cycle . Here this list is converted into edges in the Cycle. List <string> cycleInDG_EdgesAsStrings = d_G.ToEdgesAsStrings(cycleInDG); EdgeList M_corresp = CorrespondingListForTheGraph(d_G, M); Edge e = chooseEdge(M_corresp, cycleInDG_Edges); //Edge - e is chosen here. ////String e_string = chooseEdgeStringVersion(M_String, cycleInDG_EdgesAsStrings); //Edge - e is chosen here. /*--------------------------------------------------------------------------------- * Step4: Find a perfect matching M' by exchanging edges along the cycle. Output M'. * ------------------------------------------------------------------------------------*/ EdgeList M_dash = ExchangingEdgesAlongCycle(M_corresp, cycleInDG_Edges); /* Write code here to find M' here */ List <string> M_dash_String = ExchangingEdgesAlongCycleStringVersion(M_String, cycleToStringList(cycleInDG)); //this.matchingToStringList(M) //list_PerfectMatchings.Add(M_dash); list_AllPerfectMatchings.Add(M_dash_String); /*----------------------------------------------------------------------------------------- * Step5: Find G+(e), trim unnecessary edges of G+(e) using SCC decomposition algorithm. * ------------------------------------------------------------------------------------------*/ //Graph<T> G_plus = G_plus_e(DG.Clone(), e); //G+(e) is obtained here BipartiteGraph G_plus = G_plus_e(G.Clone(), e); List <List <GraphNode> > sCCs_G_plus = TarjanCycleDetect.DetectCycle(G_plus); // /SCCs in G+(e) to trim unnecessary edges /* Write code for trimming edges here*/ /*----------------------------------------------------------------------------------------------------------- * Step6: Enumerate all perfect matchings including e by ENUM_PERFECT_MATCHING_ITER with obtained graph and M * ------------------------------------------------------------------------------------------------------------*/ ENUM_PERFECT_MATCHINGS_ITER(G_plus, M, M_String); //recursive call with G+(e) and M // !! here G+(e) graph will not have edge which is there in matching /*----------------------------------------------------------------------------------------- * Step7: Find G-(e), trim unnecessary edges of G-(e) using SCC decomposition algorithm. * -----------------------------------------------------------------------------------------*/ BipartiteGraph G_minus = G_minus_e(G.Clone(), e); //G+(e) is obtained here ////G_minus.plotMethod(this.goView1); List <List <GraphNode> > sCCs_G_minus = TarjanCycleDetect.DetectCycle(G_minus); // SCCs in G-(e) to trim unnecessary edges /* Write code for trimming edges here*/ /*--------------------------------------------------------------------------------------------------------------- * Step8: Enumerate all perfect matchings not including e by ENUM_PERFECT_MATCHING_ITER with obtained graph and M' * ---------------------------------------------------------------------------------------------------------------*/ ENUM_PERFECT_MATCHINGS_ITER(G_minus, matchingStringsToEdgeList(G_minus, M_dash_String), M_dash_String); //recursive call with G+(e) and M }
private void ENUM_MAXIMUM_MATCHINGS_ITER(BipartiteGraph G, EdgeList M, List <String> M_String, int recursionLevel) { if (recursionLevel > MaximumRecursionLevel) { return; } //This code has been tested and works fine for test-case under consideration /*------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Step1: If G has no edge, stop. * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ if (G.Edges.Count <= 1) { return; } /*------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Step2: If D(G,M) contains no cylce, Go to Step8. * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ BipartiteGraph d_G = G.Clone().GetDirectedGraphAsPerMatching(M); var CIDG = new CycleInDirectedGraph(d_G); //Class object containing Method to detect and get cycle in a grah if (!CIDG.HasCycle) { goto Step8; } /*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Step3 & 4: Choose an edge e as the same manner in ENUM_PERFECT_MATCHINGS_ITER. Find a cycle containing e by a depth-first-search algorithm. * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ //Cycle is found using DFS algorithm and edge-e is chosen such that it is in cycle and in matching M ( and not in M'(which is found next)) of the directed graph(DG) List <GraphNode> cycleInDG = CIDG.Cycle; //returns here cycle in a directed graph DG //'Cycle': Vertices can not repeate and Edges can not repeat EdgeList cycleInDG_Edges = d_G.ToEdges(cycleInDG); //cycleInDG is list of nodes in a Cycle . Here this list is converted into edges in the Cycle. List <String> cycleInDG_EdgesAsStrings = d_G.ToEdgesAsStrings(cycleInDG); EdgeList M_corresp = CorrespondingListForTheGraph(d_G, M); Edge e = chooseEdge(M_corresp, cycleInDG_Edges); //Edge - e is chosen here. /*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Step5: Exchange edges along the cycle and output the obtained maximum matching M'. * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ List <String> M_dash_String = ExchangingEdgesAlongCycleOrPathStringVersion(M_String, cycleToStringList(cycleInDG));//this.matchingToStringList(M) M_dash_String.Sort(); list_AllMaximumMatchings.Add(M_dash_String); /*------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Step6: Enumerate all maximum matchings including e by ENUM_MAXIMUM_MATCHINGS_ITER with G+(e), M and trimmed D(G+(e), M\e). * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ BipartiteGraph G_plus = G_plus_e(G.Clone(), e); ENUM_MAXIMUM_MATCHINGS_ITER(G_plus, M, M_String, ++recursionLevel); //recursive call with G+(e) and M // !! here G+(e) graph will not have edge which is there in matching /*------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Step7: Enumerate all maximum matchings not including e by ENUM_MAXIMUM_MATCHINGS_ITER with G-(e), M' and trimmed D(G-(e), M'). Stop. * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ BipartiteGraph G_minus = G_minus_e(G.Clone(), e); //G-(e) is obtained here ENUM_MAXIMUM_MATCHINGS_ITER(G_minus, matchingStringsToEdgeList(G_minus, M_dash_String), M_dash_String, ++recursionLevel); //recursive call with G-(e) and M return; /*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Step8: Find a feasible path with length 2 and generate a new maximum matching M'. Let e be the edge of the path not included in M. * ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ //'Feasible Path': Step8 :; NodeList unmatchedVertices = d_G.GetUnmatchedVertices(M_String); var path = new List <String>(); foreach (GraphNode Gn in d_G) { if (Gn.NodeType == GraphNode.Type.Type1) { var dfs = new DepthFirstSearch(d_G, Gn, unmatchedVertices); path = dfs.length2Path; if (path.Count == 3 && isFeasiblePath(d_G, path, unmatchedVertices)) { break; } } if ((Gn.NodeType == GraphNode.Type.Type2) && !(unmatchedVertices.Contains(Gn))) { var dfs = new DepthFirstSearch(d_G, Gn, unmatchedVertices); path = dfs.length2Path; if (path.Count == 3 && isFeasiblePath(d_G, path, unmatchedVertices)) { break; } } } if (path.Count != 3) { return; } e = getEdgeInPathNotInM(G, M_String, pathToEdgesAsStrings(G, path)); M_dash_String = ExchangingEdgesAlongCycleOrPathStringVersion(M_String, pathToEdgesAsStrings(G, path)); M_dash_String.Sort(); list_AllMaximumMatchings.Add(M_dash_String); /*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Step9: Call ENUM_MAXIMUM+MATCHINGS_ITER(G+(e), M', theta). * ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ G_plus = G_plus_e(G.Clone(), e); ENUM_MAXIMUM_MATCHINGS_ITER(G_plus, matchingStringsToEdgeList(G_plus, M_dash_String), M_dash_String, ++recursionLevel); /*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Step10: Call ENUM_MAXIMUM+MATCHINGS_ITER(G-(e), M, theta). * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ G_minus = G_minus_e(G.Clone(), e); //G-(e) is obtained here ENUM_MAXIMUM_MATCHINGS_ITER(G_minus, M, M_String, ++recursionLevel); }
} //here this class constructor is called with inputs as null nodeSet and edgeSet. Here NodeList and EdgeList are created if they are null public BipartiteGraph(NodeList nodeSet, EdgeList edgeSet) { Nodes = nodeSet ?? new NodeList(); Edges = edgeSet ?? new EdgeList(); }