Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 29 additions & 21 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,35 @@ end

# ModelAnalyzer.jl

This package provides tools for analyzing (and debugging) [JuMP](https://github.com/jump-dev/JuMP.jl) models.
This package provides tools for analyzing (and debugging)
[JuMP](https://github.com/jump-dev/JuMP.jl) models.

Three main functionalities are provided:

1. **Numerical Analysis**: Check for numerical issues in the model, such as large and small coefficients,
empty constraints, non-convex quadratic functions.

2. **Feasibility Analysis**: Given an optimized model, or a candidate solution, check if the solutions is
feasible and optimal (when possible). This includes checking the feasibility of the primal model and
also the dual model (if available). Complementary slackness conditions are also checked (if applicable).

3. **Infeasibility Analysis**: Given an unsolved of solved model, three steps are made to check for
infeasibility:
- Check bounds, integers and binaries consistency is also checked at this point.
- Propagate bounds in constraints individually, to check if each constraint is infeasible
given the current variable bounds. This is only done if bounds are ok.
- Run an IIS (Irreducible Inconsistent Subsystem / irreducible infeasible sets)
resolver algorithm to find a minimal infeasible subset of constraints.
This is only done if no issues are found in the previous two steps.
1. **Numerical Analysis**: Check for numerical issues in the model, such as
large and small coefficients, empty constraints, non-convex quadratic
functions.
2. **Feasibility Analysis**: Given an optimized model, or a candidate solution,
check if the solutions is feasible and optimal (when possible). This
includes checking the feasibility of the primal model and also the dual
model (if available). Complementary slackness conditions are also checked
(if applicable).
3. **Infeasibility Analysis**: Given an unsolved of solved model, three steps
are made to check for infeasibility:
- Check bounds, integers and binaries consistency is also checked at this
point.
- Propagate bounds in constraints individually, to check if each constraint
is infeasible given the current variable bounds. This is only done if
bounds are ok.
- Run an IIS (Irreducible Inconsistent Subsystem / irreducible infeasible
sets) resolver algorithm to find a minimal infeasible subset of
constraints. This is only done if no issues are found in the previous two
steps.

## Installation

You can install the package using the Julia package manager. In the Julia REPL, run:
You can install the package using the Julia package manager. In the Julia REPL,
run:

```julia
using Pkg
Expand Down Expand Up @@ -84,14 +90,16 @@ ModelAnalyzer.summarize(data)

The `ModelAnalyzer.analyze(...)` function can always take the keyword arguments:
* `verbose = false` to condense the print output.
* `max_issues = n` to limit the maximum number of issues to report for each type.
* `max_issues = n` to limit the maximum number of issues to report for each
type.

For certain analysis modes, the `summarize` function can take additional arguments.
For certain analysis modes, the `summarize` function can take additional
arguments.

### Advanced usage

After any `ModelAnalyzer.analyze(...)` call is performed, the resulting data structure
can be summarized using `ModelAnalyzer.summarize(data)` as show above,
After any `ModelAnalyzer.analyze(...)` call is performed, the resulting data
structure can be summarized using `ModelAnalyzer.summarize(data)` as show above,
or it can be further inspected programmatically.

```julia
Expand Down
45 changes: 40 additions & 5 deletions src/feasibility.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ julia> data = ModelAnalyzer.analyze(

The additional parameters:
- `primal_point`: The primal solution point to use for feasibility checking.
If `nothing`, it will use the current primal solution from optimized model.
If `nothing`, it will use the current primal solution from optimized model.
- `dual_point`: The dual solution point to use for feasibility checking.
If `nothing` and the model can be dualized, it will use the current dual
solution from the model.
If `nothing` and the model can be dualized, it will use the current dual
solution from the model.
- `atol`: The absolute tolerance for feasibility checking.
- `skip_missing`: If `true`, constraints with missing variables in the provided
point will be ignored.
point will be ignored.
- `dual_check`: If `true`, it will perform dual feasibility checking. Disabling
the dual check will also disable complementarity checking.
the dual check will also disable complementarity checking.
"""
struct Analyzer <: ModelAnalyzer.AbstractAnalyzer end

Expand All @@ -62,6 +62,11 @@ abstract type AbstractFeasibilityIssue <: ModelAnalyzer.AbstractIssue end

The `PrimalViolation` issue is identified when a primal constraint has a
left-hand-side value that is not within the constraint's set.

For more information, run:
```julia
julia> ModelAnalyzer.summarize(ModelAnalyzer.Feasibility.PrimalViolation)
```
"""
struct PrimalViolation <: AbstractFeasibilityIssue
ref::JuMP.ConstraintRef
Expand All @@ -73,6 +78,11 @@ end

The `DualViolation` issue is identified when a constraint has a dual value
that is not within the dual constraint's set.

For more information, run:
```julia
julia> ModelAnalyzer.summarize(ModelAnalyzer.Feasibility.DualViolation)
```
"""
struct DualViolation <: AbstractFeasibilityIssue
ref::Union{JuMP.ConstraintRef,JuMP.VariableRef}
Expand All @@ -86,6 +96,11 @@ The `ComplemetarityViolation` issue is identified when a pair of primal
constraint and dual variable has a nonzero complementarity value, i.e., the
inner product of the primal constraint's slack and the dual variable's
violation is not zero.

For more information, run:
```julia
julia> ModelAnalyzer.summarize(ModelAnalyzer.Feasibility.ComplemetarityViolation)
```
"""
struct ComplemetarityViolation <: AbstractFeasibilityIssue
ref::JuMP.ConstraintRef
Expand All @@ -98,6 +113,11 @@ end
The `DualObjectiveMismatch` issue is identified when the dual objective value
computed from problem data and the dual solution does not match the solver's
dual objective value.

For more information, run:
```julia
julia> ModelAnalyzer.summarize(ModelAnalyzer.Feasibility.DualObjectiveMismatch)
```
"""
struct DualObjectiveMismatch <: AbstractFeasibilityIssue
obj::Float64
Expand All @@ -110,6 +130,11 @@ end
The `PrimalObjectiveMismatch` issue is identified when the primal objective
value computed from problem data and the primal solution does not match
the solver's primal objective value.

For more information, run:
```julia
julia> ModelAnalyzer.summarize(ModelAnalyzer.Feasibility.PrimalObjectiveMismatch)
```
"""
struct PrimalObjectiveMismatch <: AbstractFeasibilityIssue
obj::Float64
Expand All @@ -122,6 +147,11 @@ end
The `PrimalDualMismatch` issue is identified when the primal objective value
computed from problem data and the primal solution does not match the dual
objective value computed from problem data and the dual solution.

For more information, run:
```julia
julia> ModelAnalyzer.summarize(ModelAnalyzer.Feasibility.PrimalDualMismatch)
```
"""
struct PrimalDualMismatch <: AbstractFeasibilityIssue
primal::Float64
Expand All @@ -134,6 +164,11 @@ end
The `PrimalDualSolverMismatch` issue is identified when the primal objective
value reported by the solver does not match the dual objective value reported
by the solver.

For more information, run:
```julia
julia> ModelAnalyzer.summarize(ModelAnalyzer.Feasibility.PrimalDualSolverMismatch)
```
"""
struct PrimalDualSolverMismatch <: AbstractFeasibilityIssue
primal::Float64
Expand Down
26 changes: 26 additions & 0 deletions src/infeasibility.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ abstract type AbstractInfeasibilitylIssue <: ModelAnalyzer.AbstractIssue end

The `InfeasibleBounds` issue is identified when a variable has a lower bound
that is greater than its upper bound.

For more information, run:
```julia
julia> ModelAnalyzer.summarize(ModelAnalyzer.Infeasibility.InfeasibleBounds)
````
"""
struct InfeasibleBounds{T} <: AbstractInfeasibilitylIssue
variable::JuMP.VariableRef
Expand All @@ -57,6 +62,13 @@ The `InfeasibleIntegrality` issue is identified when a variable has an
integrality constraint (like `MOI.Integer` or `MOI.ZeroOne`) that is not
consistent with its bounds. That is, the bounds do not allow for any
integer value to be feasible.

For more information, run:
```julia
julia> ModelAnalyzer.summarize(
ModelAnalyzer.Infeasibility.InfeasibleIntegrality
)
```
"""
struct InfeasibleIntegrality{T} <: AbstractInfeasibilitylIssue
variable::JuMP.VariableRef
Expand All @@ -74,6 +86,13 @@ constraint at a time and all variable bounds of variables involved in the
constraint.
This issue can only be found is all variable bounds are consistent, that is,
no issues of type `InfeasibleBounds` were found in the first layer of analysis.

For more information, run:
```julia
julia> ModelAnalyzer.summarize(
ModelAnalyzer.Infeasibility.InfeasibleConstraintRange
)
```
"""
struct InfeasibleConstraintRange{T} <: AbstractInfeasibilitylIssue
constraint::JuMP.ConstraintRef
Expand All @@ -90,6 +109,13 @@ constraints cannot be satisfied simultaneously. This is typically found
by the IIS resolver after the first two layers of infeasibility analysis
have been completed with no issues, that is, no issues of any other type
were found.

For more information, run:
```julia
julia> ModelAnalyzer.summarize(
ModelAnalyzer.Infeasibility.IrreducibleInfeasibleSubset
)
```
"""
struct IrreducibleInfeasibleSubset <: AbstractInfeasibilitylIssue
constraint::Vector{JuMP.ConstraintRef}
Expand Down
Loading