How to retrieve dual values using Solver Foundation Services
Dual values, or shadow prices, represent the marginal utility of relaxing a constraint. They are often used during the post-solve analysis of an optimization model. If you solve a linear or mixed integer model using a solver class such as SimplexSolver, you can get the dual values from the solver solution object using the sensibly named GetDualValue method. However, in Solver Foundation 2.1 you can also get dual values for models that you build through OML or Solver Foundation Services. Solving a model is easy: call SolverContext.Solve(). This method returns a Solution object which can among other things return a solution report. If you are dealing with a linear or mixed integer model you can cast the report object to LinearReport and retrieve dual values using GetShadowPrices. A single constraint can have more than one dual value associated with it, because a constraint may use Foreach – therefore GetShadowPrices returns an IEnumerable of key value pairs, rather than a single number. Here is an example:
private static void PetrochemSimple() {
SolverContext context = SolverContext.GetContext();
context.ClearModel();
Model model = context.CreateModel();
Decision sa = new Decision(Domain.RealRange(0, 9000), "SA");
Decision vz = new Decision(Domain.RealRange(0, 6000), "VZ");
model.AddDecisions(sa, vz);
model.AddGoal("goal", GoalKind.Minimize, 20 * sa + 15 * vz);
Constraint demand1 = model.AddConstraint("demand1", 0.3 * sa + 0.4 * vz >= 2000);
Constraint demand2 = model.AddConstraint("demand2", 0.4 * sa + 0.2 * vz >= 1500);
Constraint demand3 = model.AddConstraint("demand3", 0.2 * sa + 0.3 * vz >= 500);
Solution solution = context.Solve(new SimplexDirective { GetSensitivity = true });
LinearReport report = ((LinearReport)solution.GetReport());
foreach (Constraint constraint in model.Constraints) {
foreach (var dual in report.GetShadowPrices(constraint)) {
Console.WriteLine(dual.Key + " = " + dual.Value.ToDouble());
}
}
}
This won’t work if the solver that was chosen by Solver Foundation does not know how to return dual values! The built-in SimplexSolver knows how to do this, as do many plug-in solvers. The InteriorPointSolver does not currently return dual information – it will in the next version of Solver Foundation.