public EdgeList matchingStringsToEdgeList(BipartiteGraph G, List <string> M_String) { var M_to_EdgeListM = new EdgeList(); GraphNode nd1, nd2; foreach (string edg in M_String) { nd1 = G.GetNode(edg.Split('-')[0]); nd2 = G.GetNode(edg.Split('-')[1]); if (G.Contains(nd1, nd2)) { M_to_EdgeListM.Add(G.Edges.FindByNodes(nd1, nd2)); } else if (G.Contains(nd2, nd1)) { M_to_EdgeListM.Add(G.Edges.FindByNodes(nd2, nd1)); } //else //{ // M_to_EdgeListM.Add(new Edge(nd1,nd2,0)); //} } return(M_to_EdgeListM); }
private void ENUM_PERFECT_MATCHINGS(BipartiteGraph G) { /*------------------------------------------------------------------------------- * Step1: Find a perfect matching M of G and output M. If M is not found, stop. * ---------------------------------------------------------------------------------*/ //////G.GetAdjListInTheFormOfIntegers(); //Graph is converted to AdjList containing integers which are assigned to each model type node in a graph //////IList<int> match = HopcroftKarp.GetMatching(G.AdjList, G.ModSet.Count); //Max. matching algorithm is called here with above AdjList of graph and number of model type nodes in a graph as input //This returns matching as IList of integers associated with models throw new NotImplementedException(); EdgeList M = null; //G.MatchingToEdgeList(); //Edges of Matching //// List<List<T>> M_String = G.MatchingToEdgeListAsValues();//Matching Edges as Strings( "Node - Node") list_AllPerfectMatchings.Add(matchingToStringList(M)); /*----------------------------------------------------------------------------------------------------------- * Step2: Trim unnecessary edges from G by a strongly connected component decomposition algorithm with D(G,M) * -------------------------------------------------------------------------------------------------------------*/ ////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); //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. /*---------------------------------------- * Step3: Call ENUM_PERFECT_MATCHINGS_ITER * ------------------------------------------*/ ENUM_PERFECT_MATCHINGS_ITER(G.Clone(), M, matchingToStringList(M)); //list_AllPerfectMatchings.Add(M_String); }
//YHB: this method find the graph G_plus by deleting given edge-e, its end vertices and edges associated with the end vertices private static BipartiteGraph BuildGplus(BipartiteGraph G, Edge e) { BipartiteGraph Gplus = G.Clone(); Gplus.Remove(e.FromNode.Value); Gplus.Remove(e.ToNode.Value); return(Gplus); }
public MaximumMatchings(BipartiteGraph G, bool getAllMatchings = false) { list_AllMaximumMatchings.Clear(); this.G = G; this.G.UpdateAddingDuplicateNodes(); edgePrims = this.G.edgeNodesCost; ENUM_MAXIMUM_MATCHINGS(this.G.Clone(), getAllMatchings); }
private bool IsFeasiblePath(BipartiteGraph G, MatchingList path, NodeList unmatchedNodes) { if (unmatchedNodes.Contains(G.GetNode(path[0])) || unmatchedNodes.Contains(G.GetNode(path[2]))) { return(true); } return(false); }
public MaximumMatchings2(BipartiteGraph G, bool getAllMatchings = false) { this.G = G; this.G.UpdateAddingDuplicateNodes(); edgePrims = this.G.edgeNodesCost; minimumAchievableCost = 0; ENUM_MAXIMUM_MATCHINGS(this.G.Clone(), getAllMatchings); }
private bool isFeasiblePath(BipartiteGraph G, List <String> path, NodeList unmatchedNodes) { bool isFeasiblePath = false; if (unmatchedNodes.Contains(G.GetNode(path[0])) || unmatchedNodes.Contains(G.GetNode(path[2]))) { isFeasiblePath = true; } return(isFeasiblePath); }
private readonly GraphNode _s; //source vertex public DepthFirstDirectedPaths(BipartiteGraph G, GraphNode s) { _marked = new Dictionary <string, bool>();//create dictionary containing vertex, statur(true/false) wehter marked or not for all vertices foreach (GraphNode item in G) { _marked.Add(item.Value.ToString(), false); } _edgeTo = new Dictionary <String, GraphNode>(); //create a boolean array for all vertices _s = s; //mark the source vertex DFS(G, s); }
public static EdgeList Get(BipartiteGraph bipartiteGraph) { NodeList models = bipartiteGraph.ModelsSet; if (models is null) { throw new ArgumentException("Graph has no models", nameof(bipartiteGraph)); } NodeList variables = bipartiteGraph.VariablesSet; if (variables is null) { throw new ArgumentException("Graph has no variables", nameof(bipartiteGraph)); } //Assigning int values to each node in the graph starting from 0. var modNodeIntMap = models.Select((m, i) => new KeyValuePair <string, int>(m.Value, i)).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); //Creating Adjacency List var adjacencyList = new List <int[]>(variables.Count); foreach (GraphNode variable in variables) { adjacencyList.Add(variable.Neighbors.Select(n => modNodeIntMap[n.Value]).ToArray()); } // Get Match IList <int> match = new HopcroftKarpClass(adjacencyList, models.Count).GetMatching(); // Format the match var MatchingEdgeList = new EdgeList(); int idx = 0; foreach (Node variable in variables) { int matchedModelIndex = match[idx]; if (matchedModelIndex != -1) { string modelValue = modNodeIntMap.FirstOrDefault(x => x.Value == matchedModelIndex).Key; //matching edge list contains edges having direction from MatchingEdgeList.Add(bipartiteGraph.Edges.FindByNodes(variable, bipartiteGraph.GetNode(modelValue))); // 'variables set' to 'model set' idx++; } else { idx++; /*variable associated at that location is unmatched*/ //Implement to store unmatched variable information if required } } return(MatchingEdgeList); }
/* * A recursive function to do depth first search. * We start with the source vertex s, find all vertices connected to it and recursively call * DFS as move out from s to connected vertices. We avoid "going backwards" or needlessly looking * at all paths by keeping track of which vertices we've already visited using the _marked[] array. * We keep track of how we're moving through the graph (from s to v) using _edgeTo[]. */ private void DFS(BipartiteGraph G, GraphNode v) { _marked[v.Value.ToString()] = true; foreach (GraphNode w in v.Neighbors) { if (!_marked[w.Value.ToString()]) { _edgeTo[w.Value.ToString()] = v; DFS(G, w); } } }
private static BipartiteGraph G_plus_e(BipartiteGraph G, Edge e) {//YHB: this method find the graph G_plus by deleting given edge-e, its end vertices and edges associated with the end vertices BipartiteGraph G_plus = G; foreach (GraphNode item in G.Nodes) { } G_plus.Remove(e.FromNode.Value); G_plus.Remove(e.ToNode.Value); return(G_plus); }
public DFSDirectedCycle(BipartiteGraph g, GraphNode s) { this.g = g; this.s = s; marked = new Dictionary <string, bool>(); onStack = new Dictionary <string, bool>(); foreach (GraphNode item in g.Nodes) { marked.Add(item.Value.ToString(), false); onStack.Add(item.Value.ToString(), false); } findCycle(g, s); }
private static BipartiteGraph dg; //graph directed graph(dg) public static List <List <GraphNode> > DetectCycle(BipartiteGraph g) { StronglyConnectedComponents = new List <List <GraphNode> >(); index = 0; S = new Stack <GraphNode>(); dg = g; foreach (GraphNode v in g.Nodes) { if (v.index < 0) { strongconnect(v); } } return(StronglyConnectedComponents); }
private static BipartiteGraph G_minus_e(BipartiteGraph G, Edge e) {//YHB: this method find the graph G_minus by deleting given edge-e from the G i.e. given graph BipartiteGraph G_minus = G; if (G.Contains(G.GetNode(e.FromNode.Value), G.GetNode(e.ToNode.Value))) { G_minus.RemoveDirectedEdge(G.GetNode(e.FromNode.Value), G.GetNode(e.ToNode.Value)); } else { G_minus.RemoveDirectedEdge(G.GetNode(e.ToNode.Value), G.GetNode(e.FromNode.Value)); } return(G_minus); }
// A recursive function to find which vertices are connected. private void DFS(BipartiteGraph G, GraphNode v) { length2Path.Add(v.Value); if (_path2Count++ == 2) { return; } _count++; //mark this vertex as being visited _marked.Add(v.Value.ToString(), true); /* * for each vertex w in the linked list for vertex v * there exists an edge between v and w * if it is not in _marked it hasn't been visited * yet so mark it then check all the vertices * in it's linked list (it has edges to). * */ foreach (GraphNode w in v.Neighbors) { if (!_marked.ContainsKey(w.Value.ToString())) { if (_path2Count < 2) { DFS(G, w); } else if (_path2Count == 2) { if (unmatchedVertices.Contains(w) || unmatchedVertices.Contains(G.GetNode(length2Path[0]))) { DFS(G, w); } else { goto nextNeighbour; } } } else { goto nextNeighbour; } nextNeighbour :; } return; }
private bool AllSetMappedCheck(Combination combination) { if (Type == ReversalType.Inputs) { BipartiteGraph <Data, Data> G = GraphBuilder.BipartiteFromTwoSets(RequestedInputsToReverse, combination, i => GetDependenciesFromInput(i), i => GetDependenciesFromInput(i)); List <(Data, Data)> Matching = MaximumMatching.Get(G); return(Matching.Count == NinRequest); } else { BipartiteGraph <Data, Data> G = GraphBuilder.BipartiteFromTwoSets(RequestedOutputsToReverse, combination, o => GetDependenciesFromOutput(o), o => GetDependenciesFromOutput(o)); List <(Data, Data)> Matching = MaximumMatching.Get(G); return(Matching.Count == NoutRequest); } }
//YHB: this method find the graph G_minus by deleting given edge-e from the G i.e. given graph private static BipartiteGraph BuildGminus(BipartiteGraph G, Edge e) { BipartiteGraph Gminus = G.Clone(); GraphNode from = G.GetNode(e.FromNode.Value); GraphNode to = G.GetNode(e.ToNode.Value); if (G.Contains(from, to)) { Gminus.RemoveDirectedEdge(from, to); } else { Gminus.RemoveDirectedEdge(to, from); } return(Gminus); }
private Edge getEdgeInPathNotInM(BipartiteGraph G, List <String> M, List <String> path) { Edge e = null; String eString = path.Except(M).ToList()[0]; String[] eNodes = eString.Split('-'); GraphNode nd1 = G.GetNode(eNodes[0]); GraphNode nd2 = G.GetNode(eNodes[1]); if (G.Contains(nd1, nd2)) { e = G.Edges.FindByNodes(nd1, nd2); } else if (G.Contains(nd2, nd1)) { e = G.Edges.FindByNodes(nd2, nd1); } return(e); }
private Edge GetEdgeInPathNotInM(BipartiteGraph G, MatchingList M, MatchingList path) { Edge e = null; string edge = path.Except(M).ToList()[0]; string[] nodes = edge.Split('-'); GraphNode node1 = G.GetNode(nodes[0]); GraphNode node2 = G.GetNode(nodes[1]); if (G.Contains(node1, node2)) { e = G.Edges.FindByNodes(node1, node2); } else if (G.Contains(node2, node1)) { e = G.Edges.FindByNodes(node2, node1); } return(e); }
private static BipartiteGraph Get_D_GM(BipartiteGraph G, EdgeList M) {//Get directed graph from given Graph G and matchings(list of matched edges) M BipartiteGraph D_GM = G; //D_GM.GetAdjListInTheFormOfIntegers(); //Graph is converted to AdjList containing integers which are assigned to each model type node in a graph //IList<int> match = HopcroftKarp.GetMatching(D_GM.AdjList, D_GM.ModSet.Count); //Max. matching algorithm is called here with above AdjList of graph and number of model type nodes in a graph as input //EdgeList<T> M = D_GM.MatchingToEdgeList(match); //Edges of Matching foreach (var edge in M) { D_GM.ReverseEdgeDirection(edge); //getting directed graph with matched edges with direction from v1 -> v2 and other edges from v2 -> v1 } return(D_GM); }
private MatchingList PathToMatching(BipartiteGraph G, MatchingList path) { var matching = new MatchingList(); string edge; for (int i = 0; i < path.Count() - 1; i++) { if (G.GetNode(path[i]).NodeType == GraphNode.Type.Type2) { edge = EdgeString(path[i], path[i + 1]); } else { edge = EdgeString(path[i + 1], path[i]); } matching.Add(edge); } return(matching); }
private List <String> pathToEdgesAsStrings(BipartiteGraph G, List <String> path) //04-01-2017 Added for MaximumMatchings { var pathAsStrings = new List <String>(); String str; for (int i = 0; i < path.Count() - 1; i++) { if (G.GetNode(path[i]).NodeType == GraphNode.Type.Type2) { str = path[i] + '-' + path[i + 1]; } else { str = path[i + 1] + '-' + path[i]; } pathAsStrings.Add(str); } return(pathAsStrings); }
//public bool hasCycle() //{ // return hasCycle; //} public void findCycle(BipartiteGraph g, GraphNode v) { marked[v.Value.ToString()] = true; onStack[v.Value.ToString()] = true; foreach (GraphNode w in v.Neighbors) { if (!marked[w.Value.ToString()]) { findCycle(g, w); } else if (onStack[w.Value.ToString()]) { hasCycle = true; return; } } onStack[v.Value.ToString()] = false; }
private void ENUM_MAXIMUM_MATCHINGS(BipartiteGraph G, bool getAllMatchings) { /*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Step1: Find a maximum matching M of G and output M. * --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ // The maximum mathing EdgeList M = MaximumMatching.Get(G); List <string> M_String = matchingToStringList(M); M_String.Sort(); findOverconstrainedModelsReversalCost(M_String, out OverConstrainedModels, out unmappedVariables, out revCost); if (OverConstrainedModels.Count > 0) { returnTrue = true; return; } list_AllMaximumMatchings.Add(M_String); /*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * 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, matchingToStringList(M), 0); } //list_AllPerfectMatchings.Add(M_String); filterDuplicateMatchings(); }
} = new List <GraphNode>(); //YHB stores cycle in sequence public CycleInDirectedGraph(BipartiteGraph graph) { var whiteSet = new HashSet <GraphNode>(graph.Nodes.Select(n => n as GraphNode)); //unvisited var graySet = new HashSet <GraphNode>(); //visiting var blackSet = new HashSet <GraphNode>(); //visite4 HasCycle = false; while (whiteSet.Count > 0) { stack.Clear(); GraphNode current = whiteSet.First(); //ElementAt(random.Next(whiteSet.Count)); if (DepthFirstSearch(current, whiteSet, graySet, blackSet)) { Cycle.Add(stack.Pop()); Cycle.AddRange(stack.TakeWhile(n => n != Cycle[0])); Cycle.Add(Cycle[0]); HasCycle = true; break; } } }
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); }
//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); } }