Skip to content

Commit bac0a96

Browse files
authored
Add Support for Functions in Variable Domains and Overhaul Domain Restrictions (#395)
* Refactor ParameterFunction * fix typo * more minor changes * more progress * more progress * progress * Rename restricted domain info * more progress * more progress * variable_updates * Complete main package updates * full draft of src changes * more updates * More updates * test fixes * doc fixes * doc fix
1 parent e1b5a04 commit bac0a96

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+2228
-3126
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ MutableArithmetics = "1"
2929
Reexport = "0.2, 1"
3030
julia = "1.10"
3131
Interpolations = "0.16"
32-
MathOptAI = "0.1.15"
32+
MathOptAI = "0.1.18"
3333

3434
[extras]
3535
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ making it a powerful and convenient tool for advanced users.
1313

1414
| **Documentation** | **Build Status** | **Citation** |
1515
|:-------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------:|:--------------------------------------:|
16-
| [![](https://img.shields.io/badge/docs-stable-blue.svg)](https://infiniteopt.github.io/InfiniteOpt.jl/stable) | [![Build Status](https://github.com/infiniteopt/InfiniteOpt.jl/workflows/CI/badge.svg?branch=release-0.5)](https://github.com/infiniteopt/InfiniteOpt.jl/actions?query=workflow%3ACI) [![codecov.io](https://codecov.io/github/infiniteopt/InfiniteOpt.jl/coverage.svg?branch=release-0.5)](https://codecov.io/github/infiniteopt/InfiniteOpt.jl?branch=release-0.5) | [![DOI](https://img.shields.io/badge/Elsevier-CompChemEng%3A107567-yellow.svg)](https://doi.org/10.1016/j.compchemeng.2021.107567) |
17-
| [![](https://img.shields.io/badge/docs-dev-blue.svg)](https://infiniteopt.github.io/InfiniteOpt.jl/dev) | [![Build Status](https://github.com/infiniteopt/InfiniteOpt.jl/workflows/CI/badge.svg?branch=master)](https://github.com/infiniteopt/InfiniteOpt.jl/actions?query=workflow%3ACI) [![codecov.io](https://codecov.io/github/infiniteopt/InfiniteOpt.jl/coverage.svg?branch=master)](https://codecov.io/github/infiniteopt/InfiniteOpt.jl?branch=master) | |
16+
| [![](https://img.shields.io/badge/docs-stable-blue.svg)](https://infiniteopt.github.io/InfiniteOpt.jl/stable) | [![Build Status](https://github.com/infiniteopt/InfiniteOpt.jl/actions/workflows/ci.yml/badge.svg?branch=release-0.5)](https://github.com/infiniteopt/InfiniteOpt.jl/actions/workflows/ci.yml) [![codecov.io](https://codecov.io/github/infiniteopt/InfiniteOpt.jl/coverage.svg?branch=release-0.5)](https://codecov.io/github/infiniteopt/InfiniteOpt.jl?branch=release-0.5) | [![DOI](https://img.shields.io/badge/Elsevier-CompChemEng%3A107567-yellow.svg)](https://doi.org/10.1016/j.compchemeng.2021.107567) |
17+
| [![](https://img.shields.io/badge/docs-dev-blue.svg)](https://infiniteopt.github.io/InfiniteOpt.jl/dev) | [![Build Status](https://github.com/infiniteopt/InfiniteOpt.jl/actions/workflows/ci.yml/badge.svg)](https://github.com/infiniteopt/InfiniteOpt.jl/actions/workflows/ci.yml) [![codecov.io](https://codecov.io/github/infiniteopt/InfiniteOpt.jl/coverage.svg?branch=master)](https://codecov.io/github/infiniteopt/InfiniteOpt.jl?branch=master) | |
1818

1919
It builds upon `JuMP` to add support for many complex modeling objects which
2020
include:
@@ -43,7 +43,7 @@ can be installed by entering the following in the REPL.
4343
```julia
4444
julia> ]
4545

46-
(v1.11) pkg> add InfiniteOpt
46+
(v1.12) pkg> add InfiniteOpt
4747
```
4848

4949
## Documentation

docs/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,5 @@ Literate = "2.18"
2727
Plots = "1"
2828
SpecialFunctions = "2"
2929
Interpolations = "0.16"
30-
MathOptAI = "0.1.15"
30+
MathOptAI = "0.1.18"
3131
Flux = "0.16"

docs/src/develop/extensions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,7 @@ Subject to
10391039
Note that better variable naming could be used with the reformulated infinite
10401040
variables. Moreover, in general extensions of [`build_transformation_backend!`](@ref)
10411041
should account for the possibility that `InfiniteModel` contains constraints with
1042-
[`DomainRestrictions`](@ref) as accessed via [`domain_restrictions`](@ref).
1042+
[`DomainRestriction`](@ref) as accessed via [`domain_restriction`](@ref).
10431043

10441044
Now that we have optimized our `InfiniteModel` via the use the of a
10451045
`DeterministicBackend`, we probably want to access the results. All queries

docs/src/guide/constraint.md

Lines changed: 41 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,11 @@ parameters they explicitly/implicitly depend on) that is restricted to a certain
109109
sub-domain. Such constraints are common for enforcing initial/boundary conditions
110110
and for enforcing path constraints over a certain sub-domain.
111111

112-
These types of constraints are defined adding [`DomainRestrictions`](@ref). For
112+
These types of constraints are defined adding [`DomainRestriction`](@ref). For
113113
example, let's add the initial condition ``y_b(0) = 0``:
114114
```jldoctest constrs
115-
julia> @constraint(model, initial, yb == 0, DomainRestrictions(t => 0))
116-
initial : yb(t) = 0, ∀ t = 0
115+
julia> @constraint(model, initial, yb == 0, DomainRestriction(iszero, t))
116+
initial : yb(t) = 0, ∀ t ∈ [0, 10]; if iszero(t) = True
117117
```
118118
Thus, we have added a constraint to `model` defined over the sub-domain ``t = 0``
119119
in accordance with the initial condition.
@@ -127,12 +127,15 @@ in accordance with the initial condition.
127127
yb(0) = 0
128128
```
129129

130-
More complex sub-domains can be specified by simply adding more restrictions. To
130+
This syntax is quite general since any function can be defined for more
131+
complex sub-domains can be specified by simply adding more restrictions. To
131132
illustrate this, let's define the constraint
132133
``2y_b^2(t, x) + z_1 \geq 3, \ \forall t = 0, \ x \in [-1, 1]^2``:
133134
```jldoctest constrs
134-
julia> @constraint(model, 2ya^2 + z[1] >= 3, DomainRestrictions(t => 0, x => [-1, 1]))
135-
2 ya(t, x)² + z[1] ≥ 3, ∀ t = 0, x[1] ∈ [-1, 1], x[2] ∈ [-1, 1]
135+
julia> restrict(t_s, x_s) = iszero(t_s) && -1 <= x_s <= 1;
136+
137+
julia> @constraint(model, 2ya^2 + z[1] >= 3, DomainRestriction(restrict, t, x))
138+
2 ya(t, x)² + z[1] ≥ 3, ∀ t ∈ [0, 10], x[1] ∈ [-2, 2], x[2] ∈ [-2, 2]; if restrict(t, x) = True
136139
```
137140

138141
Now we have added constraints to our model, and it is ready to be solved!
@@ -155,7 +158,7 @@ and [`JuMP.VectorConstraint](https://jump.dev/JuMP.jl/v1/api/JuMP/#JuMP.VectorCo
155158

156159
Restricted constraints are built upon this data structure where the underlying
157160
constraint is created in the same manner. Then the specified
158-
[`DomainRestrictions`](@ref) are added by creating a
161+
[`DomainRestriction`](@ref) are added by creating a
159162
[`DomainRestrictedConstraint`](@ref) which stores the `JuMP.AbstractConstraint`
160163
and the restrictions.
161164

@@ -180,7 +183,7 @@ The constraint objects are specified via `JuMP.build_constraint` which requires
180183
that the user provides a function, set, and optionally include domain
181184
restrictions. For example, let's build a scalar constraint
182185
``3y_a(t, x) - y_b^2(t) \leq 0, \ \forall t \in [0, 10], x \in [-2, 2]^2`` over
183-
its full infinite domain (i.e., have no `DomainRestrictions`):
186+
its full infinite domain (i.e., have no `DomainRestriction`):
184187
```jldoctest constrs
185188
julia> constr = build_constraint(error, 3ya - yb^2, MOI.LessThan(0.0));
186189
```
@@ -203,7 +206,7 @@ macro automate the above steps.
203206
As mentioned above in the Basic Usage section, the
204207
[`@constraint`](https://jump.dev/JuMP.jl/v1/api/JuMP/#JuMP.@constraint)
205208
macro should be used to define constraints with the syntax:
206-
`@constraint(model::InfiniteModel, [container/name_expr], constr_expr, [rs::DomainRestrictions])`.
209+
`@constraint(model::InfiniteModel, [container/name_expr], constr_expr, [rs::DomainRestriction])`.
207210

208211
The second argument is optional and is used to assign a name and/or define
209212
indexing variables to be used in the constraint expression. When a name is provided it
@@ -249,29 +252,25 @@ See [`JuMP`'s constraint documentation](https://jump.dev/JuMP.jl/v1/manual/const
249252
for a thorough tutorial on the accepted syntax and constraint types.
250253

251254
Finally, restrictions on the inherent infinite domain of a constraint can be
252-
specified via [`DomainRestrictions`](@ref) with the `rs` argument. The accepted
253-
syntax is `DomainRestrictions(restricts...)` where each argument of `restricts`
254-
can be any of the following forms:
255-
- `pref => value`
256-
- `pref => [lb, ub]`
257-
- `pref => IntervalDomain(lb, ub)`
258-
- `prefs => value`
259-
- `prefs => [lb, ub]`
260-
- `prefs => IntervalDomain(lb, ub)`.
261-
Note that `pref` and `prefs` must correspond to infinite parameters.
255+
specified via [`DomainRestriction`](@ref) with the `rs` argument. The accepted
256+
syntax is `DomainRestriction(restrict_func, prefs...)` where `restrict_func` takes
257+
a support in the form of `prefs...` and returns a `Bool` that indicates if the support
258+
is in the domain of interest. Note that `prefs` must correspond to infinite parameters.
262259

263260
For example, we can define the constraint ``y_a^2(t, x) + z_i \leq 1`` and
264-
restrict the infinite domain of ``x_i`` to be ``[0, 1]``:
261+
restrict the infinite domain of ``x`` to be ``[0, 1]^2``:
265262
```jldoctest constrs
266-
julia> @constraint(model, [i = 1:2], ya^2 + z[i] <= 1, DomainRestrictions(x[i] => [0, 1]))
263+
julia> restrict2(x_s) = all(0 .<= x_s .<= 1);
264+
265+
julia> @constraint(model, [i = 1:2], ya^2 + z[i] <= 1, DomainRestriction(restrict2, x))
267266
2-element Vector{InfOptConstraintRef}:
268-
ya(t, x)² + z[1] ≤ 1, ∀ t ∈ [0, 10], x[1] ∈ [0, 1], x[2] ∈ [-2, 2]
269-
ya(t, x)² + z[2] ≤ 1, ∀ t ∈ [0, 10], x[1] ∈ [-2, 2], x[2] ∈ [0, 1]
267+
ya(t, x)² + z[1] ≤ 1, ∀ t ∈ [0, 10], x[1] ∈ [-2, 2], x[2] ∈ [-2, 2]; if restrict2(x) = True
268+
ya(t, x)² + z[2] ≤ 1, ∀ t ∈ [0, 10], x[1] ∈ [-2, 2], x[2] ∈ [-2, 2]; if restrict2(x) = True
270269
```
271270

272271
!!! tip
273272
Where possible, using [Restricted Variables](@ref) will tend to be more
274-
performant than using `DomainRestrictions` instead.
273+
performant than using `DomainRestriction` instead.
275274

276275
## Queries
277276
In this section, we describe a variety of methods to extract constraint
@@ -313,18 +312,18 @@ c1 : z[1]² + z[2]² + 2 ya(t, x) ≤ 0, ∀ t ∈ [0, 10], x[1] ∈ [-2, 2], x[
313312
### Domain Restrictions
314313
As explained above, restricted constraints serve as a key capability of
315314
`InfiniteOpt`. Information about domain restrictions can be obtained via
316-
[`has_domain_restrictions`](@ref) and [`domain_restrictions`](@ref) which indicate
317-
if a constraint is restricted and what its [`DomainRestrictions`](@ref) are,
315+
[`has_domain_restriction`](@ref) and [`domain_restriction`](@ref) which indicate
316+
if a constraint is restricted and what its [`DomainRestriction`](@ref) are,
318317
respectively. These are exemplified below:
319318
```jldoctest constrs
320-
julia> has_domain_restrictions(c1) # check if constraint is bounded
319+
julia> has_domain_restriction(c1) # check if constraint is bounded
321320
false
322321
323-
julia> has_domain_restrictions(initial)
322+
julia> has_domain_restriction(initial)
324323
true
325324
326-
julia> domain_restrictions(initial)
327-
Subdomain restrictions (1): t = 0
325+
julia> domain_restriction(initial)
326+
iszero(t)
328327
```
329328

330329
### General
@@ -412,7 +411,7 @@ let's update the name of `initial` to `"init_cond"`:
412411
julia> set_name(initial, "init_cond")
413412
414413
julia> initial
415-
init_cond : yb(t) = 0, ∀ t = 0
414+
init_cond : yb(t) = 0, ∀ t ∈ [0, 10]; if iszero(t) = True
416415
```
417416

418417
We can also update the normalized right hand side constant value or normalized
@@ -435,42 +434,31 @@ constr : 2.5 yb(t) - z[1] ≤ -1, ∀ t ∈ [0, 10]
435434
to update parameters without having to be concerned about the normalized form.
436435
For more information, see the [Finite Parameters](@ref finite_param_docs) page.
437436

438-
### Domain Restrictions
439-
Domain Restrictions can be added to, modified, or removed from any constraint in
437+
### Domain Restriction
438+
Domain Restrictions can be modified or removed from any constraint in
440439
`InfiniteOpt`. Principally, this is accomplished via
441-
[`add_domain_restrictions`](@ref), [`set_domain_restrictions`](@ref),
442-
and [`delete_domain_restrictions`](@ref).
440+
[`set_domain_restriction`](@ref) and [`delete_domain_restriction`](@ref).
443441

444442
!!! note
445-
Previous versions of `InfiniteOpt` used `@[set/add]_parameter_bounds` which
446-
have been deprecated in favor of using [`DomainRestrictions`](@ref) with the
447-
methods described used in this section.
448-
449-
First, domain restrictions can be added to a constraint via
450-
[`add_domain_restrictions`](@ref). For example, let's add the bound
451-
``t \in [0, 1]`` to `constr`:
452-
```jldoctest constrs
453-
julia> add_domain_restrictions(constr, DomainRestrictions(t => [0, 1]))
454-
455-
julia> constr
456-
constr : 2.5 yb(t) - z[1] ≤ -1, ∀ t ∈ [0, 1]
457-
```
443+
Previous versions of `InfiniteOpt` used `DomainRestrictions` with a more
444+
limited syntax. Now [`DomainRestriction`](@ref) has been introduced to
445+
provide a more flexible syntax.
458446

459-
In similar manner, [`set_domain_restrictions`](@ref) can be employed to specify
447+
[`set_domain_restriction`](@ref) can be employed to specify
460448
what restrictions a constraint has (overwriting any existing ones if forced). It
461449
follows the same syntax, so let's use it to change the bounds on `t` to ``t = 0``:
462450
```jldoctest constrs
463-
julia> set_domain_restrictions(constr, DomainRestrictions(t => 0), force = true)
451+
julia> set_domain_restriction(constr, DomainRestriction(iszero, t))
464452
465453
julia> constr
466-
constr : 2.5 yb(t) - z[1] ≤ -1, ∀ t = 0
454+
constr : 2.5 yb(t) - z[1] ≤ -1, ∀ t ∈ [0, 10]; if iszero(t) = True
467455
```
468456

469457
Finally, constraint restrictions can be deleted via
470-
[`delete_domain_restrictions`](@ref). Now let's delete the domain restrictions
458+
[`delete_domain_restriction`](@ref). Now let's delete the domain restrictions
471459
associated with our example:
472460
```jldoctest constrs
473-
julia> delete_domain_restrictions(constr)
461+
julia> delete_domain_restriction(constr)
474462
475463
julia> constr
476464
constr : 2.5 yb(t) - z[1] ≤ -1, ∀ t ∈ [0, 10]

docs/src/guide/derivative.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ julia> deriv(3t^2 - 2t, t)
7979
Conveniently, `@deriv` can be called within any measure and constraint. However,
8080
in certain cases we may need to define an initial guess (initial guess trajectory).
8181
This can be accomplished in 2 ways:
82-
- Call [`set_start_value_function`](@ref set_start_value_function(::DerivativeRef,::Union{Real, Function}))
82+
- Call [`set_start_value`](@ref)
8383
using the individual derivative (e.g., `d1` above)
8484
- Define the derivative using `@variable` with the [`Deriv`](@ref) variable type
8585
object and use the `start` keyword argument.
@@ -88,7 +88,7 @@ generate a value in accordance with the support values (i.e., following the same
8888
syntax as infinite variables). For example, we can specify the starting value of
8989
`d1` to `0` via the following:
9090
```jldoctest deriv_basic
91-
julia> set_start_value_function(d1, 0)
91+
julia> set_start_value(d1, 0)
9292
```
9393

9494
Now let's return to our discussion on derivative evaluation methods. These are the
@@ -584,7 +584,7 @@ dydt2(t, x, ξ) ≥ 1, ∀ t ∈ [0, 10], ξ ~ Uniform, x ∈ [-1, 1]
584584
julia> has_upper_bound(dydt2)
585585
false
586586
587-
julia> func = start_value_function(dydt2);
587+
julia> func = start_value(dydt2);
588588
```
589589

590590
### Model Queries
@@ -629,7 +629,7 @@ julia> fix(dydt2, 42, force = true)
629629
julia> fix_value(dydt2)
630630
42.0
631631
632-
julia> set_start_value_function(dydt2, (t, x, xi) -> t + x+ xi)
632+
julia> set_start_value(dydt2, (t, x, xi) -> t + x+ xi)
633633
634634
julia> unfix(dydt2)
635635

docs/src/guide/optimize.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ Subject to
4444
y(t) ≥ 0, ∀ t ∈ [0, 10]
4545
z ≥ 0
4646
c1 : z - y(t) ≥ 0, ∀ t ∈ [0, 10]
47-
y(0) ≥ 0
4847
c2 : y(0) = 42
4948
```
5049
Now we optimize the model using `optimize!`:

docs/src/guide/result.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,10 @@ julia> @constraint(model, c2, y(0) == 42);
3838
julia> print(model)
3939
Min 2 z
4040
Subject to
41-
y(t) ≥ 0.0, ∀ t ∈ [0, 10]
42-
z ≥ 0.0
43-
c1 : z - y(t) ≥ 0.0, ∀ t ∈ [0, 10]
44-
y(0) ≥ 0.0
45-
c2 : y(0) = 42.0
41+
y(t) ≥ 0, ∀ t ∈ [0, 10]
42+
z ≥ 0
43+
c1 : z - y(t) ≥ 0, ∀ t ∈ [0, 10]
44+
c2 : y(0) = 42
4645
4746
julia> optimize!(model)
4847

docs/src/guide/transcribe.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ Min 2 z + support_sum{t}[y(t)]
5656
Subject to
5757
y(t) ≥ 0, ∀ t ∈ [0, 10]
5858
z binary
59-
y(0) ≥ 0
6059
initial : y(0) = 1
6160
constr : y(t)² - z ≤ 42, ∀ t ∈ [0, 10]
6261
```

0 commit comments

Comments
 (0)