Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow querying conflicts from within JuMP #2300

Merged
merged 14 commits into from
Sep 7, 2020
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Calculus = "0.5"
DataStructures = "0.17"
ForwardDiff = "~0.5.0, ~0.6, ~0.7, ~0.8, ~0.9, ~0.10"
MathOptInterface = "~0.9.11"
MathOptInterface = "~0.9.14"
MutableArithmetics = "0.2"
NaNMath = "0.3"
julia = "1"
Expand Down
25 changes: 24 additions & 1 deletion docs/src/solutions.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ This function will return a `MOI.TerminationStatusCode` `enum`.
MOI.TerminationStatusCode
```

Additionally, we can receive a solver specific string explaning why the
Additionally, we can receive a solver specific string explaining why the
optimization stopped with [`raw_status`](@ref).

## Solution statuses
Expand Down Expand Up @@ -249,6 +249,28 @@ lp_objective_perturbation_range
lp_rhs_perturbation_range
```

## Conflicts

Sometimes, the model you input is infeasible, and some solvers can help you
dourouc05 marked this conversation as resolved.
Show resolved Hide resolved
find the cause of this infeasibility by offering a conflict, i.e. a subset of
dourouc05 marked this conversation as resolved.
Show resolved Hide resolved
the constraints that create this infeasibility.

The function [`compute_conflict!`](@ref) is used to start the computation of
odow marked this conversation as resolved.
Show resolved Hide resolved
dourouc05 marked this conversation as resolved.
Show resolved Hide resolved
a conflict. Once this process is finished, the attribute `MOI.ConflictStatus`
returns a `MOI.ConflictStatusCode` `enum`.

```@docs
MOI.ConflictStatusCode
```

If there is a conflict, you can query each constraint whether it participates
dourouc05 marked this conversation as resolved.
Show resolved Hide resolved
in the conflict or not using the attribute `MOI.ConstraintConflictStatus`.
It returns a `MOI.ConstraintConflictStatus` `enum`.

```@docs
MOI.ConflictParticipationStatusCode
```

dourouc05 marked this conversation as resolved.
Show resolved Hide resolved
## Multiple solutions

Some solvers support returning multiple solutions. You can check how many
Expand Down Expand Up @@ -289,6 +311,7 @@ JuMP.dual
JuMP.solve_time
OptimizeNotCalled
MOI.optimize!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this should be JuMP.optimize!

JuMP.compute_conflict!
JuMP.result_count
JuMP.relative_gap
JuMP.simplex_iterations
Expand Down
21 changes: 21 additions & 0 deletions src/optimizer_interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,27 @@ function optimize!(model::Model,
return
end

"""
compute_conflict!(model::Model)

Compute a conflict if the model is infeasible. If an optimizer has not
been set yet (see [`set_optimizer`](@ref)), a [`NoOptimizer`](@ref)
error is thrown.

The status of the conflict can be checked with the `MOI.ConflictStatus`
model attribute. Then, the status for each constraint can be queried with
the `MOI.ConstraintConflictStatus` attribute.
"""
function compute_conflict!(model::Model)
if mode(model) != DIRECT && MOIU.state(backend(model)) == MOIU.NO_OPTIMIZER
throw(NoOptimizer())
end

MOI.compute_conflict!(backend(model))

return
end

"""
result_count(model::Model)

Expand Down
8 changes: 8 additions & 0 deletions test/model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -507,3 +507,11 @@ function dummy_optimizer_hook(::JuMP.AbstractModel) end
@test_throws ErrorException JuMP.copy(model)
end
end

@testset "Conflict computation" begin
@testset "NoOptimizer()" begin
err = NoOptimizer()
model = Model()
@test_throws err compute_conflict!(model)
end
end