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; }
/// <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 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; } }
/// <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; }