Team Building Optimization Using Microsoft Solver Foundation 3.0
I'm working on a student project team building application. I'm familiar with optimization but haven't used Microsoft Solver Foundation before. I have my constraints worked out but am having trouble identifying my goals with the Solver syntax. Here's a basic summary of the application:
Professors weight certain skills for each project. Students list which skills are their strengths and weaknesses and they rank projects they would like to do. A project must have between 3-5 students assigned to it. Each student must be assigned a project.
- Primary goal is开发者_开发技巧 to maximize number of satisfied skill requirements
- Secondary goal is to maximize student preferences
I have been playing around with the SimplexSolver Class based on this Mixed Integer Problem tutorial and am able to maximize student preferences without any problem.
using Microsoft.SolverFoundation.Solvers;
//This example has 2 projects and 6 students
SimplexSolver solver = new SimplexSolver();
//Student A wants to be in project 1, Student B is indifferent to project 1, Student C does not want to be in project 1, etc...
double[] studentprojectpref = new double[] { 1, 0, -1, 0, -1, 0, 0, 1, 0, 1, 0, 1 };
int[] choosestudentprojectPS = new int[12];
//GOAL - maximize student preferences
int sumpreferences;
solver.AddRow("sumpreferences", out sumpreferences);
solver.AddGoal(sumpreferences, 1, false);
//add a varaible (column) for each possible student/project pair
for (int i = 0; i < choosestudentprojectPS.GetUpperBound(0)+1; i++)
{
solver.AddVariable(projectstudent[i], out choosestudentprojectPS[i]);
solver.SetBounds(choosestudentprojectPS[i], 0, 1);
solver.SetIntegrality(choosestudentprojectPS[i], true);
solver.SetCoefficient(sumpreferences, choosestudentprojectPS[i], studentprojectpref[i]);
}
solver.Solve(new SimplexSolverParams());
Response.Write(solver.MipResult + "<br>");
Response.Write("<br>Project 1<br>");
for (int i = 0; i < 6; i++)
{
if (solver.GetValue(choosestudentprojectPS[i]) == 1) Response.Write(projectstudent[i] + "<br>");
}
Response.Write("<br>Project 2<br>");
for (int i = 6; i < 12; i++)
{
if (solver.GetValue(choosestudentprojectPS[i]) == 1) Response.Write(projectstudent[i] + "<br>");
}
Response.Write("<br>The total sumpreferences is: " + solver.GetValue(sumpreferences) + "<br>");
I see how I can add rows for each project skill requirement, and set coefficients for each student's strength/weakness for that skill and set a lower bound for that project's skill weight. This gives me 2 problems though.
- I don't believe that all project skill requirements are going to be met. That's why I would like to set a goal to maximize the number of skill requirements that are meant instead of setting the skill weight minimum as a constraint. Even if a team is 1 point short on a particular skill it is still better than all of them having that skill listed as a weakness.
- If there are 4 students on a team that has a programming skill weight of 3, and 3 of them have programming listed as a strength (+1) and the other student has programming listed as a weakness (-1) then my model would incorrectly show that the programming requirement is not met because (1+1+1-1)<3.
Anybody have any ideas? Is SimplexSolver the best way to go about this problem? It looks like Solution Foundation has a lot of different solvers/tools. I have the Express version of Solution Foundation but could probably get a hold of the Academic Enterprise version if needed.
Thanks, - Greg
*Final application will need to solve models with approximately 100 students, 20-30 projects, and ~30 potential skills (~5 per project).
Yes, you can solve this using Simplex. This is an standard "Assignment Problem" with a few variations in terms of preferences and skill weights.
You can address Issue 1 in your question by introducing one or more "dummy variables" to take up the 'slack'
Instead of writing the skill constraint as:
Sum for all students (X_sp) >= NumMin_pk
for each project p, for each skill k.
you write
sum for all students (X_sp) > 0 + NumMin_pk * Dummy1_pk
for each p, for each skill k
And in the objective function, you penalize Dummy_pk (by giving it a negative cost for the Maximization problem.) So, Simplex will assign a non-zero Dummy_pk only if it has no other alternative.
Further, let's say for one skill (programming) the project has a minimum skill weight of 3, but if 5 students have programming that is even better. You can achieve that by introducing a second Dummy Variable (Dummy2_pk).
Sum for all students (X_sp) > 0 + 3* Dummy_pk + 2 * Dummy_pk2
for each p, for each skill k
In the objective function, give a High negative cost to Dummy_pk and a smaller but negative cost to Dummy2_pk.The model will first try to make get Dummy1_pk 0, and if possible, if will drive Dummy2_pk zero. The result would be 5 students with programming skills getting assigned to that project.
To address issue 2 (negative skill weights): Split the skill vector into two vectors by separating the 1s and the -1's.
So [1,0,0,1,-1,0,1] becomes [1,0,0,1,0,0,1] and [0,0,0,0,-1,0,0]. Depending on what you want to do with skill weakness, you can write TWO constraints for each project p, skill k and avoid the problem of weakness canceling out another student's skill.
精彩评论