/// <summary> /// Parse the given string into a matching instance. /// </summary> /// <param name="Input"></param> /// <returns></returns> private Instance Parse(string Input) { string[] Prios = Input.Split('-'); List<Tuple<int, int>>[] PrioList = new List<Tuple<int, int>>[Prios.Length - 1]; List<int> Posts = new List<int>(); for (int i = 0; i < Prios.Length - 1; i++) { PrioList[i] = new List<Tuple<int, int>>(); string[] Targets = Prios[i].Split(','); int RankCounter = 0; foreach (string Target in Targets) { string[] Parts = Target.Split('.'); int ID = int.Parse(Parts[0]); int Rank; if (Parts.Length == 1) Rank = RankCounter++; else Rank = int.Parse(Parts[1]); PrioList[i].Add(new Tuple<int, int>(ID, Rank)); if (!Posts.Contains(ID)) Posts.Add(ID); } } int Capacity = int.Parse(Prios[Prios.Length - 1]); Instance Result = new Instance(Prios.Length - 1, Posts.Count, Capacity, PrioList); return Result; }
/// <summary> /// Prints the given instance into a string. /// </summary> /// <param name="input"></param> /// <returns></returns> private string Output(Instance input) { string Result = ""; if (input == null) Result = "No popular matching."; else { int[] Matching = new int[input.Applicants.Length]; for (int i = 0; i < input.Posts.Length; i++) { if (input.Posts[i].NrMatchings > 0) Matching[input.Posts[i].Matchings[0]] = i; } for (int j = 0; j < Matching.Length; j++) { Result += j.ToString() + " -> " + Matching[j].ToString() + "; "; } } return Result; }
public SwitchingGraph(Instance instance) { BaseInstance = instance; Component.statID = 0; Nodes = new List<Node>(); foreach (Instance.Post p in instance.Posts) { Node Temp = new Node(p); Nodes.Add(Temp); } int Counter = 0; foreach (Instance.Post p in instance.Posts) { // create edges in the switching graph if (p.Matchings.Count > 0) { Instance.Applicant Partner = instance.Applicants[p.Matchings[0]]; Node Start; Node End; if (instance.Posts[Partner.Priorities[0].Target].ID == p.ID && Partner.Priorities[0].Rank == 0) { Start = Nodes[Counter]; Start.IsS = false; End = Nodes[Partner.Priorities[1].Target]; End.IsS = true; } else { Start = Nodes[Counter]; Start.IsS = true; End = Nodes[Partner.Priorities[0].Target]; End.IsS = false; } Nodes[Counter].Outgoing.Add(new Edge(Start, End, Partner)); } Counter++; } IdentifiyComponents(); }
public Edge(Node start, Node end, Instance.Applicant app) { Applicant = app; Start = start; End = end; }
/// <summary> /// Check for applicant complete matching /// </summary> /// <param name="instance"></param> /// <returns></returns> private Instance GetApplicantComplete(Instance instance) { List<int>[] Suitors = new List<int>[instance.Posts.Length]; for (int i = 0; i < instance.Posts.Length; i++) { Suitors[i] = new List<int>(); } // create suitors list for (int i = 0; i < instance.Applicants.Length; i++) { for (int j = 0; j < instance.Applicants[i].Priorities.Count; j++) { Suitors[instance.Applicants[i].Priorities.ElementAt(j).Target].Add(i); } } int Unmatched = instance.Posts.Length; // # of not full posts int UnmatchedApplicants = instance.Applicants.Length; // # unmatched applicants for (int i = 0; i < instance.Posts.Length; i++) { // if a post is connected to only one not matched applicant, match this if (Suitors[i].Count == 1 && !instance.Posts[i].Matched && !instance.Applicants[Suitors[i].ElementAt(0)].Matched) { instance.Posts[i].Matched = true; instance.AddMatch(i, Suitors[i].ElementAt(0)); UnmatchedApplicants--; int Applicant = Suitors[i].ElementAt(0); for (int j = 0; j < instance.Posts.Length; j++) { Suitors[j].Remove(Applicant); } } } for (int i = 0; i < instance.Posts.Length; i++) { // delete not connected posts if (Suitors[i].Count == 0) { instance.Posts[i].Matched = true; Unmatched--; } } // check if there is enough space for the remaining applicants if (Unmatched < UnmatchedApplicants) return null; else { // if yes, walk over the disjoint cycle and take every second edge for (int i = 0; i < instance.Applicants.Length; i++) { instance = GoPath(instance, i); if (instance == null) instance = null; } } return instance; }
public Instance Match(Instance instance, string path, bool print) { Instance oldcopy = instance.Copy(); if (!System.IO.Directory.Exists(path) && print) System.IO.Directory.CreateDirectory(path); if (print) { Bitmap Bmp1 = instance.Draw(); Bmp1.Save(path + "/0Start.bmp"); Bmp1.Dispose(); } instance = GetReduced(instance); if (print) { Bitmap Bmp2 = instance.Draw(); Bmp2.Save(path + "/1Reduced.bmp"); Bmp2.Dispose(); } if (print) { Bitmap Bmp3 = instance.Draw(); Bmp3.Save(path + "/2Inflated.bmp"); Bmp3.Dispose(); } // check for applicant-complete matching instance = GetApplicantComplete(instance); if (instance == null) { if (print) { Bitmap Result = new Bitmap(1000, 1000); Graphics G = Graphics.FromImage(Result); Pen P = new Pen(new SolidBrush(Color.Black)); G.DrawString("No Popular Matching", new Font("Arial", 36), new SolidBrush(Color.Black), 100, 100); Result.Save(path + "/3NoPop.bmp"); G.Dispose(); Result.Dispose(); } return null; } else { if (print) { Bitmap Bmp4 = instance.Draw(); Bmp4.Save(path + "/3ApplicantComplete.bmp"); Bmp4.Dispose(); } } List<int>[] FPosts = new List<int>[instance.Posts.Length]; for (int i = 0; i < instance.Posts.Length; i++) { FPosts[i] = new List<int>(); } for (int i = 0; i < instance.Applicants.Length; i++) { FPosts[instance.Applicants[i].Priorities.ElementAt(0).Target].Add(i); } for (int i = 0; i < instance.Posts.Length; i++) { if (FPosts[i].Count > 0 && instance.Posts[i].NrMatchings == 0) { instance.DeleteMatch(FPosts[i][0]); instance.AddMatch(i, FPosts[i][0]); } } if (print) { Bitmap Bmp4 = instance.Draw(); Bmp4.Save(path + "/4AllFPostsMatched.bmp"); Bmp4.Dispose(); } return instance; }
public Instance Copy() { Instance result = new Instance(n, m); for (int i = 0; i < Applicants.Length; i++) { result.Applicants[i] = new Applicant(i); for (int j = 0; j < Applicants[i].Priorities.Count; j++) { result.Applicants[i].Priorities.Add(new Priority(Applicants[i].Priorities[j].Target, Applicants[i].Priorities[j].Rank)); } } for (int i = 0; i < Posts.Length; i++) { result.Posts[i] = new Post(i, Posts[i].Capacity); } return result; }
/// <summary> /// Recursively create all possible instances by creating all possible combinations of priority lists. /// </summary> /// <param name="depth"></param> /// <param name="n"></param> /// <param name="seeds"></param> /// <param name="start"></param> /// <param name="print"></param> /// <param name="path"></param> private void RecPrios(int depth, int n, List<int> seeds, int start, bool print, string path) { if (depth < n) { // call the next level with every possible priority configuration for (int a = 0; a < (int)Factorial((ulong)(n)); a++) { List<int> dummy = Copy(seeds); dummy.Add(a); RecPrios(depth + 1, n, dummy, a, print, path); } } else { // if final level reached, create instance List<Tuple<int, int>>[] Prios = new List<Tuple<int, int>>[n]; for (int i = 0; i < n; i++) { Prios[i] = new List<Tuple<int, int>>(); } for (int i = 0; i < n; i++) { for (int x = 0; x < Perms[seeds[i]].Count; x++) { Prios[i].Add(new Tuple<int, int>(Perms[seeds[i]][x], x)); } } Instance Temp = new Instance(n, n, 1, Prios); // check for popular matching Temp = ChosenSolver.Match(Temp, path, print); // multiply this value by Factor, since the first applicant always gets the same priority seed - this way, a permutation less has to be examined double Factor = Factorial((ulong)n); if (Temp == null) { NotPop += (long)Factor; } CC += (long)Factor; } }
private Instance GetReduced(Instance instance) { for (int i = 0; i < instance.n; i++) { int HighestSecond = int.MaxValue; for (int j = 0; j < instance.Applicants[i].Priorities.Count; j++) { if (instance.Applicants[i].Priorities.ElementAt(j).Rank != 0 && instance.Posts[instance.Applicants[i].Priorities.ElementAt(j).Target].Type != 1) { instance.Applicants[i].Priorities.RemoveAt(j); j--; } else { if (instance.Applicants[i].Priorities[j].Rank < HighestSecond && instance.Posts[instance.Applicants[i].Priorities[j].Target].Type == 1) { HighestSecond = (instance.Applicants[i].Priorities[j].Rank); } } } for (int j = 0; j < instance.Applicants[i].Priorities.Count; j++) { if (instance.Applicants[i].Priorities.ElementAt(j).Rank > HighestSecond) { instance.Applicants[i].Priorities.RemoveAt(j); j--; } } } // now every applicant has only 2 edges, to his f- and s-post return instance; }
private Instance DeleteEdges(Instance instance) { for (int i = 0; i < instance.Applicants.Length; i++) { for (int j = 0; j < instance.Applicants[i].Priorities.Count; j++) { if ((instance.Applicants[i].Type == 0 && instance.Posts[instance.Applicants[i].Priorities[j].Target].Type == 0) || (instance.Applicants[i].Type == 0 && instance.Posts[instance.Applicants[i].Priorities[j].Target].Type == 2) || (instance.Applicants[i].Type == 2 && instance.Posts[instance.Applicants[i].Priorities[j].Target].Type == 0)) { instance.Applicants[i].Priorities.RemoveAt(j); j--; } } } return instance; }
public Instance Match(Instance instance, string path, bool print) { if (!System.IO.Directory.Exists(path) && print) System.IO.Directory.CreateDirectory(path); if (print) { Bitmap Bmp1 = instance.Draw(); Bmp1.Save(path + "/0Start.bmp"); Bmp1.Dispose(); } instance = Inflate(instance); if (print) { Bitmap Bmp1 = instance.Draw(); Bmp1.Save(path + "/1Inflated.bmp"); Bmp1.Dispose(); } instance = MaxMatching(instance, 0); if (print) { Bitmap Bmp1 = instance.Draw(); Bmp1.Save(path + "/2FirstMax.bmp"); Bmp1.Dispose(); } instance = DetermineTypes(instance); if (print) { Bitmap Bmp3 = instance.Draw(); Bmp3.Save(path + "/3Types.bmp"); Bmp3.Dispose(); } instance = GetReduced(instance); if (print) { Bitmap Bmp4 = instance.Draw(); Bmp4.Save(path + "/4Reduced.bmp"); Bmp4.Dispose(); } instance = DeleteEdges(instance); if (print) { Bitmap Bmp5 = instance.Draw(); Bmp5.Save(path + "/5EdgesDeleted.bmp"); Bmp5.Dispose(); } instance = MaxMatching(instance, -1); if (print) { Bitmap Bmp6 = instance.Draw(); Bmp6.Save(path + "/6GeneralMaxMatching.bmp"); Bmp6.Dispose(); } for (int i = 0; i < instance.Applicants.Length; i++) { if (!instance.Applicants[i].Matched) { if (print) { Bitmap Bmp7 = instance.Draw(); Bmp7.Save(path + "/7NoPopularMatching.bmp"); Bmp7.Dispose(); } return null; } } return instance; }
private void button1_Click(object sender, EventArgs e) { textBox2.Text = ""; string Input = textBox1.Text.Replace(" ", ""); Instance Test = Parse(Input); Instance Result; if (radioButton1.Checked) { PopSolver poppi = new PopSolver(); Result = poppi.Match(Test, Path, checkBox1.Checked); } else { PopSolver2 poppi = new PopSolver2(); Result = poppi.Match(Test, Path, checkBox1.Checked); } textBox2.Text = Output(Result); GlobalResult = Result; }
/// <summary> /// DFS to find an augmenting path /// </summary> /// <param name="graph"></param> /// <param name="inst"></param> /// <returns></returns> private List<int> DFS(DirectedGraph graph, Instance inst) { Stack<DirectedGraph.Node> Stack = new Stack<DirectedGraph.Node>(); for (int i = 0; i < graph.Nodes.Count; i++) { if (graph.Nodes[i].Type == 0 && !inst.Applicants[graph.Nodes[i].ID - inst.Posts.Length].Matched) { Stack.Push(graph.Nodes[i]); } } while (Stack.Count > 0) { DirectedGraph.Node n = Stack.Pop(); if (n.Type == 1 && inst.Posts[n.ID].NrMatchings == 0) { List<int> Path = new List<int>(); DirectedGraph.Node Current = n; Path.Insert(0, n.ID); while (Current.PrevId != -1) { Current = graph.Nodes[Current.PrevId]; if (Current.Type == 0) Path.Insert(0, Current.ID - inst.Posts.Length); else Path.Insert(0, Current.ID); } return Path; } for (int j = 0; j < n.Outgoing.Count; j++) { int Target = n.Outgoing[j]; int Prev = n.ID; if (!graph.Nodes[Target].Marked) { graph.Nodes[Target].PrevId = Prev; Stack.Push(graph.Nodes[Target]); graph.Nodes[Target].Marked = true; } } } return null; }
public DirectedGraph(Instance inst, int useOnly) { Nodes = new List<Node>(); for (int j = 0; j < inst.Posts.Length; j++) { Nodes.Add(new Node(1, j)); } for (int i = 0; i < inst.Applicants.Length; i++) { Nodes.Add(new Node(0, inst.Posts.Length + i)); for (int k = 0; k < inst.Applicants[i].Priorities.Count; k++) { if (useOnly != -1 && inst.Applicants[i].Priorities[k].Rank != useOnly) continue; if (inst.Posts[inst.Applicants[i].Priorities[k].Target].Matchings.Contains(i)) { Nodes.ElementAt(inst.Applicants[i].Priorities[k].Target).Outgoing.Add(inst.Posts.Length + i); } else { Nodes.ElementAt(inst.Posts.Length + i).Outgoing.Add(inst.Applicants[i].Priorities[k].Target); } } } }
/// <summary> /// Completess the applicant-complete matching, by traversing the disjoint cycle and taking every second edge. /// </summary> /// <param name="instance"></param> /// <param name="start"></param> /// <returns></returns> private Instance GoPath(Instance instance, int start) { if (instance.Applicants[start].Matched) return instance; else { int Target = -1; if (!instance.Posts[instance.Applicants[start].Priorities.ElementAt(0).Target].Full) { instance.AddMatch(instance.Applicants[start].Priorities.ElementAt(0).Target, start); Target = instance.Applicants[start].Priorities.ElementAt(0).Target; } else { if (!instance.Posts[instance.Applicants[start].Priorities.ElementAt(1).Target].Full) { instance.AddMatch(instance.Applicants[start].Priorities.ElementAt(1).Target, start); Target = instance.Applicants[start].Priorities.ElementAt(1).Target; } else return instance; } for (int j = 0; j < instance.Applicants.Length; j++) { if (instance.Applicants[j].Priorities.ElementAt(0).Target == Target || instance.Applicants[j].Priorities.ElementAt(1).Target == Target) { if (!instance.Applicants[j].Matched) instance = GoPath(instance, j); } } } return instance; }
public LPEdge(Instance.Applicant app, Instance.Post post, int rank) { Applicant = app; Post = post; Rank = rank; }
public Instance Match(Instance instance, string path, bool print) { try { LP = ""; if (!System.IO.Directory.Exists(path) && print) System.IO.Directory.CreateDirectory(path); GRBEnv env = new GRBEnv("mip1.log"); GRBModel model = new GRBModel(env); List<LPEdge> LPEdges = new List<LPEdge>(); if (print) { instance.Draw().Save(path + "/0Start.bmp"); } int EdgeCounter = 0; foreach (Instance.Applicant a in instance.Applicants) { EdgeCounter += a.Priorities.Count; foreach (Instance.Priority Prio in a.Priorities) { { LPEdges.Add(new LPEdge(a, instance.Posts[Prio.Target], Prio.Rank)); if (Prio.Rank == 0) instance.Posts[Prio.Target].IsF = 1; } } } // Create variables GRBVar[] Edges = new GRBVar[EdgeCounter]; for (int i = 0; i < Edges.Length; i++) { Edges[i] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "ve" + i.ToString()); } // Integrate new variables model.Update(); if (print) LP += "Applicant Matching Conditions:" + Environment.NewLine; foreach (Instance.Applicant a in instance.Applicants) { GRBLinExpr Temp = new GRBLinExpr(); for (int i = 0; i < LPEdges.Count; i++) { if (LPEdges[i].Applicant == a) { Temp += Edges[i]; if (print) LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") + "; } } model.AddConstr(Temp == 1.0, "a" + a.ID.ToString()); if (print) LP += " = 1;" + Environment.NewLine; } if (print) LP += Environment.NewLine + "Post Matching Conditions:" + Environment.NewLine; foreach (Instance.Post p in instance.Posts) { GRBLinExpr Temp = new GRBLinExpr(); for (int i = 0; i < LPEdges.Count; i++) { if (LPEdges[i].Post == p) { Temp += Edges[i]; if (print) LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") + "; } } model.AddConstr(Temp <= 1.0, "p" + p.ID.ToString()); if (print) LP += " <= 1;" + Environment.NewLine; } if (print) LP += Environment.NewLine + "First Choice Conditions:" + Environment.NewLine; for (int i = 0; i < LPEdges.Count; i++) { LPEdge le1 = LPEdges[i]; if (le1.Post.IsF == 1 && le1.Rank != 0) { model.AddConstr(Edges[i] <= 0, "s" + i.ToString()); if (print) LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") <= 0;" + Environment.NewLine; for (int j = 0; j < LPEdges[i].Applicant.Priorities.Count; j++) { if (LPEdges[i].Applicant.Priorities[j].Target == LPEdges[i].Post.ID && LPEdges[i].Rank == LPEdges[i].Applicant.Priorities[j].Rank) { LPEdges[i].Applicant.Priorities.RemoveAt(j); } } } } if (print) LP += Environment.NewLine + "Second Choice Conditions:" + Environment.NewLine; for (int i = 0; i < LPEdges.Count; i++) { LPEdge le1 = LPEdges[i]; foreach (LPEdge le2 in LPEdges) { if (le2 != le1 && le2.Post.IsF == 0 && le1.Applicant == le2.Applicant && le2.Rank != 0 && le2.Rank < le1.Rank) { model.AddConstr(Edges[i] <= 0, "s" + i.ToString()); if (print) LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") <= 0;" + Environment.NewLine; for (int j = 0; j < LPEdges[i].Applicant.Priorities.Count; j++) { if (LPEdges[i].Applicant.Priorities[j].Target == LPEdges[i].Post.ID && LPEdges[i].Rank == LPEdges[i].Applicant.Priorities[j].Rank) { LPEdges[i].Applicant.Priorities.RemoveAt(j); } } break; } } } if (print) LP += Environment.NewLine + "First Post Conditions:" + Environment.NewLine; foreach (Instance.Post p in instance.Posts) { if (p.IsF == 1) { GRBLinExpr Temp = new GRBLinExpr(); for (int i = 0; i < LPEdges.Count; i++) { if (LPEdges[i].Post == p) { Temp += Edges[i]; if (print) LP += "(a" + LPEdges[i].Applicant.ID + ", p" + LPEdges[i].Post.ID + ") + "; } } model.AddConstr(Temp >= 1.0, "f" + p.ID.ToString()); if (print) LP += ">= 1;" + Environment.NewLine; } } // Optimize model model.Optimize(); if (print) { instance.Draw().Save(path + "/1Reduced.bmp"); } for (int i = 0; i < Edges.Length; i++) { if (Edges[i].Get(GRB.DoubleAttr.X) == 1) { instance.AddMatch(LPEdges[i].Post.ID, LPEdges[i].Applicant.ID); } } if (print) { instance.Draw().Save(path + "/2Matched.bmp"); } // Dispose of model and env model.Dispose(); env.Dispose(); return instance; } catch (GRBException e) { Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message); return null; } }
private void GoTypePath(Instance instance, bool Applicant, bool match, bool odd, int id) { if (Applicant) { if (odd) { instance.Applicants[id].Type = 0; } else { instance.Applicants[id].Type = 1; } if (!match) { for (int j = 0; j < instance.Applicants[id].Priorities.Count; j++) { if (instance.Posts[instance.Applicants[id].Priorities[j].Target].Type == -1 && instance.Applicants[id].Priorities[j].Rank == 0) GoTypePath(instance, false, true, !odd, instance.Applicants[id].Priorities[j].Target); } } if (match) { for (int j = 0; j < instance.Applicants[id].Priorities.Count; j++) { if (instance.Posts[instance.Applicants[id].Priorities[j].Target].Matchings.Contains(id)) { if (instance.Posts[instance.Applicants[id].Priorities[j].Target].Type == -1 && instance.Applicants[id].Priorities[j].Rank == 0) GoTypePath(instance, false, false, !odd, instance.Applicants[id].Priorities[j].Target); } } } } else { if (odd) { instance.Posts[id].Type = 0; } else { instance.Posts[id].Type = 1; } if (match) { for (int i = 0; i < instance.Posts[id].Matchings.Count; i++) { if (instance.Applicants[instance.Posts[id].Matchings[i]].Type == -1) GoTypePath(instance, true, false, !odd, instance.Posts[id].Matchings[i]); } } if (!match) { for (int i = 0; i < instance.Applicants.Length; i++) { for (int j = 0; j < instance.Applicants[i].Priorities.Count; j++) { if (instance.Applicants[i].Priorities[j].Target == id && instance.Applicants[i].Priorities[j].Rank == 0) { if (instance.Applicants[i].Type == -1) GoTypePath(instance, true, true, !odd, i); } } } } } }
/// <summary> /// Determine the types of the nodes. /// 0 = Odd /// 1 = Even /// 2 = Unreachable /// </summary> /// <param name="instance"></param> /// <returns></returns> private Instance DetermineTypes(Instance instance) { // Unmatched nodes are directly even, go possible paths to determine the other paths. for (int i = 0; i < instance.Applicants.Length; i++) { if (!instance.Applicants[i].Matched) { instance.Applicants[i].Type = 1; for (int j = 0; j < instance.Applicants[i].Priorities.Count; j++) { if (instance.Posts[instance.Applicants[i].Priorities[j].Target].Type == -1 && instance.Applicants[i].Priorities[j].Rank == 0) GoTypePath(instance, false, true, true, instance.Applicants[i].Priorities[j].Target); } } } for (int i = 0; i < instance.Posts.Length; i++) { if (!instance.Posts[i].Full) { instance.Posts[i].Type = 1; for (int j = 0; j < instance.Applicants.Length; j++) { for (int k = 0; k < instance.Applicants[j].Priorities.Count; k++) { if (instance.Applicants[j].Priorities[k].Target == i && instance.Applicants[j].Type == -1 && instance.Applicants[j].Priorities[k].Rank == 0) GoTypePath(instance, true, true, true, j); } } } } // unreachable nodes for (int i = 0; i < instance.Applicants.Length; i++) { if (instance.Applicants[i].Type == -1) instance.Applicants[i].Type = 2; } for (int i = 0; i < instance.Posts.Length; i++) { if (instance.Posts[i].Type == -1) instance.Posts[i].Type = 2; } return instance; }
/// <summary> /// Uses a basic augmenting path algorithm to find a maximum matching. /// </summary> /// <param name="instance"></param> /// <param name="useOnly"></param> /// <returns></returns> private Instance MaxMatching(Instance instance, int useOnly) { FinalPath = new List<int>(); while (FinalPath != null) { FinalPath = DFS(new DirectedGraph(instance, useOnly), instance); if (FinalPath != null) instance.MatchPath(FinalPath, true); } return instance; }
public Instance CopyWithMatching() { Instance result = new Instance(n, m); for (int i = 0; i < Applicants.Length; i++) { result.Applicants[i] = new Applicant(i); for (int j = 0; j < Applicants[i].Priorities.Count; j++) { result.Applicants[i].Priorities.Add(new Priority(Applicants[i].Priorities[j].Target, Applicants[i].Priorities[j].Rank)); } result.Applicants[i].Matched = Applicants[i].Matched; } for (int i = 0; i < Posts.Length; i++) { result.Posts[i] = new Post(i, Posts[i].Capacity); result.Posts[i].Matched = Posts[i].Matched; result.Posts[i].Full = Posts[i].Full; result.Posts[i].NrMatchings = Posts[i].NrMatchings; result.Posts[i].Matchings = Copy(Posts[i].Matchings); } return result; }
/// <summary> /// Replace posts with capacity c by c posts. /// </summary> /// <param name="instance"></param> /// <returns></returns> private Instance Inflate(Instance instance) { int Capacity = 0; for (int i = 0; i < instance.m; i++) { Capacity += instance.Posts[i].Capacity; } Instance NewInstance = new Instance(instance.n, Capacity); for (int i = 0; i < instance.n; i++) { NewInstance.Applicants[i] = new Instance.Applicant(i); } int Counter = 0; for (int i = 0; i < instance.m + instance.n; i++) { for (int k = 0; k < instance.Posts[i].Capacity; k++) { NewInstance.Posts[Counter] = new Instance.Post(Counter, 1); for (int j = 0; j < instance.n; j++) { for (int z = 0; z < instance.Applicants[j].Priorities.Count; z++) { if (instance.Applicants[j].Priorities[z].Target == i) { NewInstance.Applicants[j].Priorities.Add(new Instance.Priority(Counter, instance.Applicants[j].Priorities[z].Rank)); } } } Counter++; } } return NewInstance; }
/// <summary> /// Returns a random instance. /// </summary> /// <param name="n">Number of Applicants</param> /// <param name="m">Number of Posts</param> /// <param name="k">Length of the priority list</param> /// <param name="c">capacity of the Posts</param> /// <param name="seed">starting seed for random</param> /// <returns></returns> /// public static Instance GetRandom(int n, int m, int k, int c, int seed) { Instance Result = new Instance(n, m); for (int i = 0; i < n; i++) { Result.Applicants[i] = new Applicant(i); Result.Applicants[i].Priorities = new List<Instance.Priority>(); for (int j = 0; j < k; j++) { int NextPrio = Rnd.Next(m); bool Existing = true; while (Existing) { Existing = false; for (int z = 0; z < Result.Applicants[i].Priorities.Count; z++) { if (NextPrio == Result.Applicants[i].Priorities[z].Target) { Existing = true; break; } } if (Existing) NextPrio = Rnd.Next(m); } Result.Applicants[i].Priorities.Add(new Instance.Priority(NextPrio, j)); } Result.Applicants[i].Priorities.Add(new Instance.Priority(m + i, k)); } for (int i = 0; i < m; i++) { Result.Posts[i] = new Post(i, c); } for (int i = m; i < m + n; i++) { Result.Posts[i] = new Post(i, 1); } return Result; }
public Node(Instance.Post p) { Post = p; Outgoing = new List<Edge>(); Component = -1; Prev = null; IsS = true; Found = false; }
/// <summary> /// Creates the reduced subgraph. /// </summary> /// <param name="instance"></param> /// <returns></returns> private Instance GetReduced(Instance instance) { // Determine the f-posts List<int> FirstPosts = new List<int>(); for (int i = 0; i < instance.n; i++) { if (!FirstPosts.Contains(instance.Applicants[i].Priorities.ElementAt(0).Target)) FirstPosts.Add(instance.Applicants[i].Priorities.ElementAt(0).Target); } for (int i = 0; i < instance.n; i++) { bool SecondFound = false; int j; for (j = 1; j < instance.Applicants[i].Priorities.Count - 1; j++) { if (FirstPosts.Contains(instance.Applicants[i].Priorities.ElementAt(j).Target)) { // delete all f-posts except the first one from priority list instance.Applicants[i].Priorities.Remove(instance.Applicants[i].Priorities.ElementAt(j)); j--; } else { // look if there is some not f-post before l on the list SecondFound = true; break; } } if (SecondFound) { // if some second priority has been found before l, delete all posts behind it for (j = j + 1; j < instance.Applicants[i].Priorities.Count; j++) { instance.Applicants[i].Priorities.Remove(instance.Applicants[i].Priorities.ElementAt(j)); j--; } } if (instance.Applicants[i].Priorities.Count == 1) return null; } // now only applicant has 2 edges, to f- and s-post return instance; }
/// <summary> /// Replace posts with capacity c by c posts /// </summary> /// <param name="instance"></param> /// <returns></returns> private Instance Inflate(Instance instance) { int Capacity = 0; // determine total complexity of the posts for (int i = 0; i < instance.m; i++) { Capacity += instance.Posts[i].Capacity; } Instance NewInstance = new Instance(instance.n, Capacity); for (int i = 0; i < instance.n; i++) { NewInstance.Applicants[i] = new Instance.Applicant(i); } int Counter = 0; for (int i = 0; i < instance.m; i++) { // traverse all old posts List<Tuple<int, int>> Suitors = new List<Tuple<int, int>>(); for (int j = 0; j < instance.n; j++) { // add all applicants connected to post j to the list of interested people for (int z = 0; z < instance.Applicants[j].Priorities.Count; z++) { if (instance.Applicants[j].Priorities.ElementAt(z).Target == i) { Suitors.Add(new Tuple<int, int>(j, z)); } // in the last iteration of the loop maybe add an edge to the l post of the applicant and mind the changed ID if (i == instance.m - 1 && instance.Applicants[j].Priorities.ElementAt(z).Target >= instance.m) NewInstance.Applicants[j].Priorities.Add(new Instance.Priority(instance.Applicants[j].Priorities.ElementAt(z).Target + (Capacity - instance.m), 0)); } } // more applicants are interested in the post than there is capacity if (Suitors.Count >= instance.Posts[i].Capacity) { // fill every new posts with about equally many interested people // calculate current interested people per space int Factor = (int)((Suitors.Count) / (decimal)instance.Posts[i].Capacity); int SCounter = 0; for (int j = 0; j < instance.Posts[i].Capacity; j++) { // traverse all posts NewInstance.Posts[Counter] = new Instance.Post(Counter, 1); // adapt factor depending on still existing interested people and remaining new posts Factor = (int)Math.Ceiling((Suitors.Count - SCounter) / ((decimal)instance.Posts[i].Capacity - j)); // add according to the factor calculated above many people to the new post for (int z = 0; z < Factor; z++) { // mind the priority list if (Suitors.ElementAt(SCounter).Item2 == 0 || NewInstance.Applicants[Suitors.ElementAt(SCounter).Item1].Priorities.Count == 0) NewInstance.Applicants[Suitors.ElementAt(SCounter++).Item1].Priorities.Insert(0, new Instance.Priority(Counter, 0)); else { NewInstance.Applicants[Suitors.ElementAt(SCounter++).Item1].Priorities.Insert(1, new Instance.Priority(Counter, 1)); } } Counter++; } } else { // other more available places than interested people exist, just fill the places int Next = Counter + instance.Posts[i].Capacity; for (int j = 0; j < Suitors.Count; j++) { NewInstance.Posts[Counter] = new Instance.Post(Counter, 1); if (Suitors.ElementAt(j).Item2 == 0) NewInstance.Applicants[Suitors.ElementAt(j).Item1].Priorities.Insert(0, new Instance.Priority(Counter, 0)); else NewInstance.Applicants[Suitors.ElementAt(j).Item1].Priorities.Insert(1, new Instance.Priority(Counter, 1)); Counter++; } for (; Counter < Next; Counter++) { NewInstance.Posts[Counter] = new Instance.Post(Counter, 1); } } } for (int j = Counter; j < NewInstance.Posts.Length; j++) { NewInstance.Posts[j] = new Instance.Post(j, 1); } return NewInstance; }