Conflicting Set
The OPTANO.Modeling Library supports the analysis of contradictions within your model.
The ConflictingSet includes the conflicting bounds of constraints or variables after the model was found to be Infeasible.
Just add the following code to your Program (please note: this example is based on a Gurobi Solver):
// setup the model scope
// ...
// populate the model
// ...
// Get a solver instance, change your solver
using (var solver = new GurobiSolver())
{
solver.Configuration.TimeLimit = 1;
solver.Configuration.ComputeIIS = true;
// solve the model
var solution = solver.Solve(model);
var conflicts = solution.ConflictingSet.ToString();
Console.WriteLine(conflicts);
}
In the Console Output, you will find information about the conflicting bounds of constraints and variables in the model. Therefore, it will be much easier to find logical errors in the code. Alternatively, you can just dump the text into a file.
Remember that large models need a higher time limit to find out that a model is infeasible.
Here is another example, using Cplex 12.8. This examples shows, how to access the ConflictSet:
using OPTANO.Modeling.Optimization.Configuration;
using OPTANO.Modeling.Optimization.Solver.Cplex128;
/// [...]
public void TestConflictingSetIIS4()
{
// The model. c3 and the bounds of x1 are broken
/*
Maximize
obj: x1 + 2 x2 + 3 x3
Subject To
c1: x2 + x3 <= 20
c2: x1 - 3 x2 + x3 <= 30
c3: 40 <= x1 <= 40
Bounds
10 <= x1 <= 10
Generals
x1 x2 x3
End
*/
// keep names as given in model
var scopeConfig = new Configuration.Configuration() { NameHandling = NameHandlingStyle.Manual };
using (var scope = new ModelScope(scopeConfig))
{
var model = new Model { Name = "model" };
var x1 = new Variable("x1", 10, 10);
var x2 = new Variable("x2");
var x3 = new Variable("x3");
model.AddConstraint(x2 + x3 <= 20, "c1");
model.AddConstraint(x1 - 2 * x2 + x3 <= 30, "c2");
var brokenConstraint = new Constraint(x1, "c3", 40, 40);
model.AddConstraint(brokenConstraint);
model.AddObjective(new Objective(x1 + 2 * x2 + 3 * x3, "obj"));
// get the IIS, if the Model is infeasable
var solverConfig = new CplexSolverConfiguration() { ComputeIIS = true };
var solver = new CplexSolver(solverConfig);
var solution = solver.Solve(model);
Assert.IsTrue(solution.ConflictingSet.ConstraintsLB.Contains(brokenConstraint));
Assert.IsTrue(solution.ConflictingSet.ConstraintsUB.Count() == 0);
Assert.IsTrue(solution.ConflictingSet.VariablesUB.Contains(x1));
Assert.IsTrue(solution.ConflictingSet.VariablesLB.Count() == 0);
Console.WriteLine(solution.ConflictingSet.ToString());
}
This example will print the following results:
IIS:
ConstraintLB
x1, Name: c3, LB: 40
ConstraintUB
VariablesLB
VariablesUB
Name: x1, UB: 10
Map (Short-)Names of Variables to their respective Debug-Names
If you specified a debug name generator for a VariableCollection and variables from that collection are part of the ConflictingSet, then you can generate a mapping from the current Variable.Name to the respective long name (a.k.a. debug name):
// ... extending the example above ...
Dictionary<string, string> nameMapping = model.GetVariableNameToLongNameMapping();
conflicts = solution.ConflictingSet.ToDebugNameString(nameMapping);
Console.WriteLine(conflicts);
Console.ReadLine();
The nameMapping
currently only contains records for variables that belong to a variable collection for which the DebugNameGenerator is set.