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

Support Nonlinear Expressions #161

Merged
merged 55 commits into from
Oct 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
2b4b4c1
Initial tree implementation
pulsipher Aug 2, 2021
d92b129
Merge branch 'master' into nlp
pulsipher Aug 3, 2021
0e8559f
add LCRSTrees pkg
pulsipher Aug 3, 2021
1cd27c0
more LCRST progress
pulsipher Aug 3, 2021
d5ea375
starting nlp functions
pulsipher Aug 3, 2021
9a0fbd6
Added more NLP functions
pulsipher Aug 4, 2021
ddcf755
Merge branch 'master' into nlp
pulsipher Aug 4, 2021
c327a3c
Added operator precedence to printing
pulsipher Aug 5, 2021
224492e
improve printing precedence
pulsipher Aug 5, 2021
1ba190f
Added expression mapping
pulsipher Aug 24, 2021
25f8d9f
Performance improvements
pulsipher Aug 27, 2021
df81bd7
Added NLP transcription
pulsipher Sep 3, 2021
211ef16
More additions/fixes
pulsipher Sep 10, 2021
add3429
bug fixes
pulsipher Sep 10, 2021
1dcb22b
doctest fix
pulsipher Sep 15, 2021
22c7c50
add LCRST extension tests
pulsipher Sep 15, 2021
f4f1ca3
fix nlp expression map bug
pulsipher Oct 1, 2021
c78f621
measure transcription bug
pulsipher Oct 1, 2021
a62a705
Another measure trasncription bug fix
pulsipher Oct 1, 2021
efbf98d
test fix
pulsipher Oct 1, 2021
5d39189
Temporary hack for transcription
pulsipher Oct 2, 2021
8dc905c
test fix
pulsipher Oct 2, 2021
db4a6f5
Fix nlp to ast bug
pulsipher Oct 2, 2021
cd21e57
Added tests
pulsipher Oct 8, 2021
67192fa
added tests and bug fix
pulsipher Oct 8, 2021
a8834eb
test fix
pulsipher Oct 8, 2021
df292a2
test fix
pulsipher Oct 8, 2021
0d057ec
Added more tests and bug fixes
pulsipher Oct 11, 2021
3cd4bda
More tests
pulsipher Oct 11, 2021
0903729
even more tests
pulsipher Oct 11, 2021
46885f5
More tests
pulsipher Oct 11, 2021
9e3c757
more tests and bug fixes
pulsipher Oct 12, 2021
e36b526
Minor fixes
pulsipher Oct 12, 2021
5f949da
minor test fixes
pulsipher Oct 12, 2021
df8d404
Fixed tests
pulsipher Oct 12, 2021
2ebcdd4
activate tests
pulsipher Oct 12, 2021
44a783b
progress on the new docs
pulsipher Oct 13, 2021
949e05c
Merge branch 'master' into nlp
pulsipher Oct 13, 2021
7167cad
doctest fix
pulsipher Oct 13, 2021
dfdf8e8
Merge branch 'nlp' of https://github.com/pulsipher/InfiniteOpt.jl int…
pulsipher Oct 13, 2021
1fc4438
doctest fix 2
pulsipher Oct 13, 2021
4e6493f
Added more docs
pulsipher Oct 13, 2021
910cb8f
Updated docs
pulsipher Oct 14, 2021
f02890b
Merge branch 'master' into nlp
pulsipher Oct 14, 2021
ff8fe05
doc fix
pulsipher Oct 14, 2021
a52b24a
added registration
pulsipher Oct 21, 2021
ffe94ea
Finalizing touches
pulsipher Oct 21, 2021
d446dab
Fixes and debug statement
pulsipher Oct 21, 2021
c9c71df
potential fixes
pulsipher Oct 21, 2021
45c8f48
doctest_fix
pulsipher Oct 21, 2021
39bbd6d
module check fix
pulsipher Oct 21, 2021
98750b0
doctest fix
pulsipher Oct 21, 2021
8efcedd
doc fixes
pulsipher Oct 21, 2021
e791363
[ci skip] minor doc addition
pulsipher Oct 21, 2021
f42e9a7
Merge branch 'master' into nlp
pulsipher Oct 21, 2021
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
15 changes: 12 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,33 @@ authors = ["Joshua Pulsipher and Weiqi Zhang"]
version = "0.4.3"

[deps]
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
FastGaussQuadrature = "442a2c76-b920-505d-bb47-c5924d526838"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
LeftChildRightSiblingTrees = "1d6d02ad-be62-4b6b-8a6d-2f90e265016e"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MutableArithmetics = "d8a4904e-b15c-11e9-3269-09a3773c0cb0"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"

[compat]
AbstractTrees = "0.3"
DataStructures = "^0.14.2, 0.15, 0.16, 0.17, 0.18"
Distributions = "0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25"
FastGaussQuadrature = "^0.3.2, 0.4"
JuMP = "0.21.9"
JuMP = "0.21.10"
LeftChildRightSiblingTrees = "0.1"
MutableArithmetics = "0.2"
Reexport = "0.2, 1"
SpecialFunctions = "0.8, 0.9, 0.10, 1"
julia = "1"

[extras]
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb"

[targets]
test = ["Test", "Random", "LinearAlgebra"]
test = ["Test", "Random", "Suppressor"]
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ It builds upon `JuMP` to add support for many complex modeling objects which
include:
- Infinite parameters (e.g., time, space, uncertainty, etc.)
- Finite parameters (similar to `ParameterJuMP`)
- Infinite variables (e.g., `y(t, x)`)
- Infinite variables (decision functions) (e.g., `y(t, x)`)
- Derivatives (e.g., `∂y(t, x)/∂t`)
- Measures (e.g., `∫y(t,x)dt`, `𝔼[y(ξ)]`)
- More
- **1st class nonlinear modeling**

The unifying modeling abstraction behind `InfiniteOpt` captures a wide spectrum
of disciplines which include dynamic, PDE, stochastic, and semi-infinite
Expand Down
2 changes: 2 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[compat]
Expand All @@ -17,4 +18,5 @@ InfiniteOpt = "0.4"
Ipopt = "0.7"
Literate = "2.8"
Plots = "1"
SpecialFunctions = "1.7"
julia = "1.6"
56 changes: 40 additions & 16 deletions docs/src/develop/extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,6 @@ extended using the following steps:
- [`InfiniteOpt.map_value`](@ref) (enables `JuMP.value`)
- [`InfiniteOpt.map_optimizer_index`](@ref) (enables `JuMP.optimizer_index`)
- [`InfiniteOpt.map_dual`](@ref) (enables `JuMP.dual`)
- [`InfiniteOpt.map_shadow_price`](@ref) (enables `JuMP.shadow_price`)
11. Extend [`InfiniteOpt.add_point_variable`](@ref) and
[`InfiniteOpt.add_semi_infinite_variable`](@ref) to use
[`expand_measure`](@ref) without modifying the infinite model.
Expand Down Expand Up @@ -801,6 +800,7 @@ build our `InfiniteModel` as normal, for example:
@objective(model, Min, z + expect(y[1] + y[2], ξ))
@constraint(model, 2y[1] - z <= 42)
@constraint(model, y[2]^2 + ξ == 2)
@constraint(model, sin(z) >= -1)
print(model)

# output
Expand All @@ -810,6 +810,7 @@ Subject to
y[2](ξ) ≥ 0.0, ∀ ξ ~ Uniform
2 y[1](ξ) - z ≤ 42.0, ∀ ξ ~ Uniform
y[2](ξ)² + ξ = 2.0, ∀ ξ ~ Uniform
sin(z) - -1 ≥ 0.0
```

We have defined our `InfiniteModel`, but now we need to specify how to
Expand Down Expand Up @@ -864,16 +865,13 @@ function _make_expression(
)
return _make_expression(opt_model, measure_function(expr))
end
# AffExpr
function _make_expression(opt_model::Model, expr::GenericAffExpr)
return @expression(opt_model, sum(c * _make_expression(opt_model, v)
for (c, v) in linear_terms(expr)) + constant(expr))
# AffExpr/QuadExpr
function _make_expression(opt_model::Model, expr::Union{GenericAffExpr, GenericQuadExpr})
return map_expression(v -> _make_expression(opt_model, v), expr)
end
# QuadExpr
function _make_expression(opt_model::Model, expr::GenericQuadExpr)
return @expression(opt_model, sum(c * _make_expression(opt_model, v1) *
_make_expression(opt_model, v2) for (c, v1, v2) in quad_terms(expr)) +
_make_expression(opt_model, expr.aff))
# NLPExpr
function _make_expression(opt_model::Model, expr::NLPExpr)
return add_NL_expression(opt_model, map_nlp_to_ast(v -> _make_expression(opt_model, v), expr))
end

# output
Expand All @@ -883,7 +881,8 @@ _make_expression (generic function with 8 methods)
For simplicity in example, above we assume that only `DistributionDomain`s are
used, there are not any `PointVariableRef`s, and all `MeasureRef`s correspond to
expectations. Naturally, a full extension should include checks to enforce that
such assumptions hold.
such assumptions hold. Notice that [`map_expression`](@ref) and
[`map_nlp_to_ast`](@ref) are useful for converting expressions.

Now let's extend [`build_optimizer_model!`](@ref) for `DeterministicModel`s.
Such extensions should build an optimizer model in place and in general should
Expand All @@ -904,6 +903,9 @@ function InfiniteOpt.build_optimizer_model!(
# clear the model for a build/rebuild
determ_model = InfiniteOpt.clear_optimizer_model_build!(model)

# add the registered functions if there are any
add_registered_to_jump(determ_model, model)

# add variables
for vref in all_variables(model)
dvref = dispatch_variable_ref(vref)
Expand All @@ -919,16 +921,31 @@ function InfiniteOpt.build_optimizer_model!(
end

# add the objective
set_objective(determ_model, objective_sense(model),
_make_expression(determ_model, objective_function(model)))
obj_func = _make_expression(determ_model, objective_function(model))
if obj_func isa NonlinearExpression
set_NL_objective(determ_model, objective_sense(model), obj_func)
else
set_objective(determ_model, objective_sense(model), obj_func)
end

# add the constraints
for cref in all_constraints(model)
if !InfiniteOpt._is_info_constraint(cref)
constr = constraint_object(cref)
new_constr = build_constraint(error, _make_expression(determ_model, constr.func),
constr.set)
new_cref = add_constraint(determ_model, new_constr, name(cref))
new_func = _make_expression(determ_model, constr.func)
if new_func isa NonlinearExpression
if constr.set isa MOI.LessThan
ex = :($new_func <= $(constr.set.upper))
elseif constr.set isa MOI.GreaterThan
ex = :($new_func >= $(constr.set.lower))
else # assume it is MOI.EqualTo
ex = :($new_func == $(constr.set.value))
end
new_cref = add_NL_constraint(determ_model, ex)
else
new_constr = build_constraint(error, new_func, constr.set)
new_cref = add_constraint(determ_model, new_constr, name(cref))
end
deterministic_data(determ_model).infconstr_to_detconstr[cref] = new_cref
end
end
Expand All @@ -954,6 +971,9 @@ Subject to
y[2]² = 1.5
y[1] ≥ 0.0
y[2] ≥ 0.0
subexpression[1] - 0.0 ≥ 0
With NL expressions
subexpression[1]: sin(z) - -1.0
```
Note that better variable naming could be used with the reformulated infinite
variables. Moreover, in general extensions of [`build_optimizer_model!`](@ref)
Expand Down Expand Up @@ -1040,3 +1060,7 @@ solution techniques. These extension packages can implement any of the extension
shown above and likely will want to introduce wrapper functions and macros to
use package specific terminology (e.g., using random variables instead of
infinite variables).

Please reach out to us via the
[discussion forum](https://github.com/pulsipher/InfiniteOpt.jl/discussions) to
discuss your plans before starting this on your own.
10 changes: 5 additions & 5 deletions docs/src/guide/constraint.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ are enforced over some specified sub-domain of its infinite parameter
dependencies (e.g., boundary conditions). This page will highlight how to
implement these types of constraints in `InfiniteOpt`.

!!! note
Nonlinear constraints as defined by `JuMP.@NLconstraint` are not currently
supported by `InfiniteOpt`. See [Nonlinear Expressions](@ref) for more
information and possible workarounds.

## Basic Usage
Principally, the
[`@constraint`](https://jump.dev/JuMP.jl/v0.21.10/reference/constraints/#JuMP.@constraint)
Expand All @@ -48,6 +43,11 @@ julia> @variable(model, z[1:2]);
see [JuMP's constraint documentation](https://jump.dev/JuMP.jl/v0.21.10/manual/constraints/#Constraints)
for a thorough explanation of the supported types and syntax.

!!! note
Nonlinear constraints are defined simply by using `@constraint` and not
using `JuMP.@NLconstraint`. See [Nonlinear Expressions](@ref nlp_guide) for
more information.

### Scalar Constraints
Scalar constraints use scalar functions of variables. For example, let's define
the constraint
Expand Down
Loading