Skip to content

Commit 275cebc

Browse files
andrewrosembergmzagorowskaodowblegatjoaquimg
authored
🚀 Add NonLinearProgram Support to DiffOpt.jl (#260)
* NonLinearProgram * index by MOI index * only cache gradient * update API * start reverse mode * add overloads * update MOI wrapper * update code for DiffOpt API * working code * usage example * add reverse diff * update code * update tests * update tests * add forward_differentiate! tests * add reverse_differentiate! tests * update docs * format * update API reference * fix typos * update reference * update spdiagm * Typo "acutal" to "actual" (#258) Correcting typo "acutal" to "actual" * Fix GitHub actions badge in README (#263) * Implement MOI.Utilities.scalar_type for (Matrix|Sparse)VectorAffineFunction (#264) * Use SlackBridgePrimalDualStart (#253) * Use SlackBridgePrimalDualStart * Update src/copy_dual.jl * Remove test_broken * Add supports * Add comment * Move to AbstractModel * Integrate with POI to improve UX (#262) * [WIP] Integrate with POI to improve UX * add missing import * temp change to proj toml * format * simplify method setting to sue model constructor * add possible fix to scalarize bridge error * add pkg to project * format * improvements * remove jump wrapper * clean tests * fix readme * use intermediary API * format * Apply suggestions from code review Co-authored-by: Benoît Legat <[email protected]> * add suggestion * use Parameter set * todo was fixed * format * update docs for newer Flux * format * kwargs * remove diff model * suggestions * format * fix examples --------- Co-authored-by: Benoît Legat <[email protected]> * Add error for missing starting value (#269) * update API * expose kwargs * restrict hessian type * reverse wrong change * update usage * fix mad merge * fix typo * fix typo * fix wrong index * reverse index * allow user to just set relevat sensitivities * fix copy reverse sensitivity dual * format * update tests * format * update docs * extend parameter @test_throws tests for NLP * update comments * update private api: _add_leq_geq * fix typo * continue fix typo check asserts * expose factorization through as MOI.AbstractModelAttribute * add tests factorization * add comment * rm rm kwargs * use correct underscore signature for private funcs * format * change github actions to v3 * reverse checkout version * add reference sipopt paper * update factorization routine API * format * Update ci.yml * improve coverage * add test inertia correction * add test ReverseConstraintDual * format * rm useless checks * add test get ReverseConstraintDual * format * rm unecessary funcs * rm kwargs * format * rename factorization attributte * add supports * Apply suggestions from code review --------- Co-authored-by: mzagorowska <[email protected]> Co-authored-by: Oscar Dowson <[email protected]> Co-authored-by: Benoît Legat <[email protected]> Co-authored-by: Joaquim <[email protected]>
1 parent 14cb7de commit 275cebc

17 files changed

+2692
-53
lines changed

Diff for: .github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
with:
2323
version: ${{ matrix.version }}
2424
arch: ${{ matrix.arch }}
25-
- uses: actions/cache@v1
25+
- uses: actions/cache@v3
2626
env:
2727
cache-name: cache-artifacts
2828
with:

Diff for: Project.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "DiffOpt"
22
uuid = "930fe3bc-9c6b-11ea-2d94-6184641e85e7"
3-
authors = ["Akshay Sharma", "Mathieu Besançon", "Joaquim Dias Garcia", "Benoît Legat", "Oscar Dowson"]
4-
version = "0.4.3"
3+
authors = ["Akshay Sharma", "Mathieu Besançon", "Joaquim Dias Garcia", "Benoît Legat", "Oscar Dowson", "Andrew Rosemberg"]
4+
version = "0.5.0"
55

66
[deps]
77
BlockDiagonals = "0a1fb500-61f7-11e9-3c65-f5ef3456f9f0"

Diff for: docs/src/index.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# DiffOpt.jl
22

3-
[DiffOpt.jl](https://github.com/jump-dev/DiffOpt.jl) is a package for differentiating convex optimization program ([JuMP.jl](https://github.com/jump-dev/JuMP.jl) or [MathOptInterface.jl](https://github.com/jump-dev/MathOptInterface.jl) models) with respect to program parameters. Note that this package does not contain any solver.
3+
[DiffOpt.jl](https://github.com/jump-dev/DiffOpt.jl) is a package for differentiating convex and non-convex optimization program ([JuMP.jl](https://github.com/jump-dev/JuMP.jl) or [MathOptInterface.jl](https://github.com/jump-dev/MathOptInterface.jl) models) with respect to program parameters. Note that this package does not contain any solver.
44
This package has two major backends, available via the `reverse_differentiate!` and `forward_differentiate!` methods, to differentiate models (quadratic or conic) with optimal solutions.
55

66
!!! note
7-
Currently supports *linear programs* (LP), *convex quadratic programs* (QP) and *convex conic programs* (SDP, SOCP, exponential cone constraints only).
7+
Currently supports *linear programs* (LP), *convex quadratic programs* (QP), *convex conic programs* (SDP, SOCP, exponential cone constraints only), and *general nonlinear programs* (NLP).
88

99

1010
## Installation
@@ -16,8 +16,8 @@ DiffOpt can be installed through the Julia package manager:
1616

1717
## Why are Differentiable optimization problems important?
1818

19-
Differentiable optimization is a promising field of convex optimization and has many potential applications in game theory, control theory and machine learning (specifically deep learning - refer [this video](https://www.youtube.com/watch?v=NrcaNnEXkT8) for more).
20-
Recent work has shown how to differentiate specific subclasses of convex optimization problems. But several applications remain unexplored (refer section 8 of this [really good thesis](https://github.com/bamos/thesis)). With the help of automatic differentiation, differentiable optimization can have a significant impact on creating end-to-end differentiable systems to model neural networks, stochastic processes, or a game.
19+
Differentiable optimization is a promising field of constrained optimization and has many potential applications in game theory, control theory and machine learning (specifically deep learning - refer [this video](https://www.youtube.com/watch?v=NrcaNnEXkT8) for more).
20+
Recent work has shown how to differentiate specific subclasses of constrained optimization problems. But several applications remain unexplored (refer section 8 of this [really good thesis](https://github.com/bamos/thesis)). With the help of automatic differentiation, differentiable optimization can have a significant impact on creating end-to-end differentiable systems to model neural networks, stochastic processes, or a game.
2121

2222

2323
## Contributing

Diff for: docs/src/manual.md

+29-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
# Manual
22

3-
!!! note
4-
As of now, this package only works for optimization models that can be written either in convex conic form or convex quadratic form.
5-
6-
7-
## Supported objectives & constraints - `QuadraticProgram` backend
3+
## Supported objectives & constraints - scheme 1
84

95
For `QuadraticProgram` backend, the package supports following `Function-in-Set` constraints:
106

@@ -52,6 +48,33 @@ and the following objective types:
5248

5349
Other conic sets such as `RotatedSecondOrderCone` and `PositiveSemidefiniteConeSquare` are supported through bridges.
5450

51+
## Supported objectives & constraints - `NonlinearProgram` backend
52+
53+
For the `NonlinearProgram` backend, the package supports following `Function-in-Set` constraints:
54+
55+
| MOI Function | MOI Set |
56+
|:-------|:---------------|
57+
| `VariableIndex` | `GreaterThan` |
58+
| `VariableIndex` | `LessThan` |
59+
| `VariableIndex` | `EqualTo` |
60+
| `ScalarAffineFunction` | `GreaterThan` |
61+
| `ScalarAffineFunction` | `LessThan` |
62+
| `ScalarAffineFunction` | `EqualTo` |
63+
| `ScalarQuadraticFunction` | `GreaterThan` |
64+
| `ScalarQuadraticFunction` | `LessThan` |
65+
| `ScalarQuadraticFunction` | `EqualTo` |
66+
| `ScalarNonlinearFunction` | `GreaterThan` |
67+
| `ScalarNonlinearFunction` | `LessThan` |
68+
| `ScalarNonlinearFunction` | `EqualTo` |
69+
70+
and the following objective types:
71+
72+
| MOI Function |
73+
|:-------:|
74+
| `VariableIndex` |
75+
| `ScalarAffineFunction` |
76+
| `ScalarQuadraticFunction` |
77+
| `ScalarNonlinearFunction` |
5578

5679
## Creating a differentiable MOI optimizer
5780

@@ -68,7 +91,7 @@ DiffOpt requires taking projections and finding projection gradients of vectors
6891
## Conic problem formulation
6992

7093
!!! note
71-
As of now, the package is using `SCS` geometric form for affine expressions in cones.
94+
As of now, when defining a conic or convex quadratic problem, the package is using `SCS` geometric form for affine expressions in cones.
7295

7396
Consider a convex conic optimization problem in its primal (P) and dual (D) forms:
7497
```math

Diff for: docs/src/reference.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
```
55

66
```@autodocs
7-
Modules = [DiffOpt, DiffOpt.QuadraticProgram, DiffOpt.ConicProgram]
7+
Modules = [DiffOpt, DiffOpt.QuadraticProgram, DiffOpt.ConicProgram, DiffOpt.NonLinearProgram]
88
```

Diff for: docs/src/usage.md

+62
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,65 @@ MOI.set(model, DiffOpt.ForwardObjectiveFunction(), ones(2) ⋅ x)
5656
DiffOpt.forward_differentiate!(model)
5757
grad_x = MOI.get.(model, DiffOpt.ForwardVariablePrimal(), x)
5858
```
59+
60+
3. To differentiate a general nonlinear program, have to use the API for Parameterized JuMP models. For example, consider the following nonlinear program:
61+
62+
```julia
63+
using JuMP, DiffOpt, HiGHS
64+
65+
model = Model(() -> DiffOpt.diff_optimizer(Ipopt.Optimizer))
66+
set_silent(model)
67+
68+
p_val = 4.0
69+
pc_val = 2.0
70+
@variable(model, x)
71+
@variable(model, p in Parameter(p_val))
72+
@variable(model, pc in Parameter(pc_val))
73+
@constraint(model, cons, pc * x >= 3 * p)
74+
@objective(model, Min, x^4)
75+
optimize!(model)
76+
@show value(x) == 3 * p_val / pc_val
77+
78+
# the function is
79+
# x(p, pc) = 3p / pc
80+
# hence,
81+
# dx/dp = 3 / pc
82+
# dx/dpc = -3p / pc^2
83+
84+
# First, try forward mode AD
85+
86+
# differentiate w.r.t. p
87+
direction_p = 3.0
88+
MOI.set(model, DiffOpt.ForwardConstraintSet(), ParameterRef(p), Parameter(direction_p))
89+
DiffOpt.forward_differentiate!(model)
90+
@show MOI.get(model, DiffOpt.ForwardVariablePrimal(), x) == direction_p * 3 / pc_val
91+
92+
# update p and pc
93+
p_val = 2.0
94+
pc_val = 6.0
95+
set_parameter_value(p, p_val)
96+
set_parameter_value(pc, pc_val)
97+
# re-optimize
98+
optimize!(model)
99+
# check solution
100+
@show value(x) 3 * p_val / pc_val
101+
102+
# stop differentiating with respect to p
103+
DiffOpt.empty_input_sensitivities!(model)
104+
# differentiate w.r.t. pc
105+
direction_pc = 10.0
106+
MOI.set(model, DiffOpt.ForwardConstraintSet(), ParameterRef(pc), Parameter(direction_pc))
107+
DiffOpt.forward_differentiate!(model)
108+
@show abs(MOI.get(model, DiffOpt.ForwardVariablePrimal(), x) -
109+
-direction_pc * 3 * p_val / pc_val^2) < 1e-5
110+
111+
# always a good practice to clear previously set sensitivities
112+
DiffOpt.empty_input_sensitivities!(model)
113+
# Now, reverse model AD
114+
direction_x = 10.0
115+
MOI.set(model, DiffOpt.ReverseVariablePrimal(), x, direction_x)
116+
DiffOpt.reverse_differentiate!(model)
117+
@show MOI.get(model, DiffOpt.ReverseConstraintSet(), ParameterRef(p)) == MOI.Parameter(direction_x * 3 / pc_val)
118+
@show abs(MOI.get(model, DiffOpt.ReverseConstraintSet(), ParameterRef(pc)).value -
119+
-direction_x * 3 * p_val / pc_val^2) < 1e-5
120+
```

Diff for: src/DiffOpt.jl

+8
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ include("bridges.jl")
2727

2828
include("QuadraticProgram/QuadraticProgram.jl")
2929
include("ConicProgram/ConicProgram.jl")
30+
include("NonLinearProgram/NonLinearProgram.jl")
3031

3132
"""
3233
add_all_model_constructors(model)
@@ -37,6 +38,13 @@ Add all constructors of [`AbstractModel`](@ref) defined in this package to
3738
function add_all_model_constructors(model)
3839
add_model_constructor(model, QuadraticProgram.Model)
3940
add_model_constructor(model, ConicProgram.Model)
41+
add_model_constructor(model, NonLinearProgram.Model)
42+
return
43+
end
44+
45+
function add_default_factorization(model)
46+
model.input_cache.factorization =
47+
NonLinearProgram._lu_with_inertia_correction
4048
return
4149
end
4250

0 commit comments

Comments
 (0)