@@ -36,15 +36,18 @@ best dealt with by other components of MathOptInterface.
36
36
## API overview
37
37
38
38
The core element of the ` Nonlinear ` submodule is
39
- [ ` Nonlinear.NonlinearData ` ] ( @ref ) :
39
+ [ ` Nonlinear.Model ` ] ( @ref ) :
40
40
``` jldoctest nonlinear_developer
41
41
julia> const Nonlinear = MathOptInterface.Nonlinear;
42
42
43
- julia> data = Nonlinear.NonlinearData()
44
- NonlinearData with available features:
45
- * :ExprGraph
43
+ julia> model = Nonlinear.Model()
44
+ A Nonlinear.Model with:
45
+ 0 objectives
46
+ 0 parameters
47
+ 0 expressions
48
+ 0 constraints
46
49
```
47
- [ ` Nonlinear.NonlinearData ` ] ( @ref ) is a mutable struct that stores all of the
50
+ [ ` Nonlinear.Model ` ] ( @ref ) is a mutable struct that stores all of the
48
51
nonlinear information added to the model.
49
52
50
53
### Decision variables
@@ -75,65 +78,126 @@ There are a number of restrictions on the input `Expr`:
75
78
Given an input expression, add an expression using
76
79
[ ` Nonlinear.add_expression ` ] ( @ref ) :
77
80
``` jldoctest nonlinear_developer
78
- julia> expr = Nonlinear.add_expression(data , input)
81
+ julia> expr = Nonlinear.add_expression(model , input)
79
82
MathOptInterface.Nonlinear.ExpressionIndex(1)
80
83
```
81
84
The return value, ` expr ` , is a [ ` Nonlinear.ExpressionIndex ` ] ( @ref ) that can
82
85
then be interpolated into other input expressions.
83
86
87
+ Looking again at ` model ` , we see:
88
+ ``` jldoctest nonlinear_developer
89
+ julia> model
90
+ A Nonlinear.Model with:
91
+ 0 objectives
92
+ 0 parameters
93
+ 1 expression
94
+ 0 constraints
95
+ ```
96
+
84
97
### [ Parameters] (@id Nonlinear_Parameters)
85
98
86
99
In addition to constant literals like ` 1 ` or ` 1.23 ` , you can create parameters.
87
100
Parameters are placeholders whose values can change before passing the
88
101
expression to the solver. Create a parameter using
89
102
[ ` Nonlinear.add_parameter ` ] ( @ref ) , which accepts a default value:
90
103
``` jldoctest nonlinear_developer
91
- julia> p = Nonlinear.add_parameter(data , 1.23)
104
+ julia> p = Nonlinear.add_parameter(model , 1.23)
92
105
MathOptInterface.Nonlinear.ParameterIndex(1)
93
106
```
94
107
The return value, ` p ` , is a [ ` Nonlinear.ParameterIndex ` ] ( @ref ) that can then be
95
108
interpolated into other input expressions.
96
109
110
+ Looking again at ` model ` , we see:
111
+ ``` jldoctest nonlinear_developer
112
+ julia> model
113
+ A Nonlinear.Model with:
114
+ 0 objectives
115
+ 1 parameter
116
+ 1 expression
117
+ 0 constraints
118
+ ```
119
+
97
120
Update a parameter as follows:
98
121
``` jldoctest nonlinear_developer
99
- julia> data [p]
122
+ julia> model [p]
100
123
1.23
101
124
102
- julia> data [p] = 4.56
125
+ julia> model [p] = 4.56
103
126
4.56
104
127
105
- julia> data [p]
128
+ julia> model [p]
106
129
4.56
107
130
```
108
131
109
132
### [ Objectives] (@id Nonlinear_Objectives)
110
133
111
134
Set a nonlinear objective using [ ` Nonlinear.set_objective ` ] ( @ref ) :
112
135
``` jldoctest nonlinear_developer
113
- julia> Nonlinear.set_objective(data, :($p + $expr + $x))
136
+ julia> Nonlinear.set_objective(model, :($p + $expr + $x))
137
+
138
+ julia> model
139
+ A Nonlinear.Model with:
140
+ 1 objective
141
+ 1 parameter
142
+ 1 expression
143
+ 0 constraints
114
144
```
145
+
115
146
Clear a nonlinear objective by passing ` nothing ` :
116
147
``` jldoctest nonlinear_developer
117
- julia> Nonlinear.set_objective(data, nothing)
148
+ julia> Nonlinear.set_objective(model, nothing)
149
+
150
+ julia> model
151
+ A Nonlinear.Model with:
152
+ 0 objectives
153
+ 1 parameter
154
+ 1 expression
155
+ 0 constraints
156
+ ```
157
+
158
+ But we'll re-add the objective for later:
159
+ ``` jldoctest nonlinear_developer
160
+ julia> Nonlinear.set_objective(model, :($p + $expr + $x));
118
161
```
119
162
120
163
### [ Constraints] (@id Nonlinear_Constraints)
121
164
122
165
Add a constraint using [ ` Nonlinear.add_constraint ` ] ( @ref ) :
123
166
``` jldoctest nonlinear_developer
124
- julia> c = Nonlinear.add_constraint(data , :(1 + sqrt($x) <= 2.0))
167
+ julia> c = Nonlinear.add_constraint(model , :(1 + sqrt($x) <= 2.0))
125
168
MathOptInterface.Nonlinear.ConstraintIndex(1)
169
+
170
+ julia> model
171
+ A Nonlinear.Model with:
172
+ 1 objective
173
+ 1 parameter
174
+ 1 expression
175
+ 1 constraint
126
176
```
127
177
The return value, ` c ` , is a [ ` Nonlinear.ConstraintIndex ` ] ( @ref ) that is a unique
128
178
identifier for the constraint. Interval constraints are also supported:
129
179
``` jldoctest nonlinear_developer
130
- julia> c2 = Nonlinear.add_constraint(data , :(-1.0 <= 1 + sqrt($x) <= 2.0))
180
+ julia> c2 = Nonlinear.add_constraint(model , :(-1.0 <= 1 + sqrt($x) <= 2.0))
131
181
MathOptInterface.Nonlinear.ConstraintIndex(2)
182
+
183
+ julia> model
184
+ A Nonlinear.Model with:
185
+ 1 objective
186
+ 1 parameter
187
+ 1 expression
188
+ 2 constraints
132
189
```
133
190
134
191
Delete a constraint using [ ` Nonlinear.delete ` ] ( @ref ) :
135
192
``` jldoctest nonlinear_developer
136
- julia> Nonlinear.delete(data, c2)
193
+ julia> Nonlinear.delete(model, c2)
194
+
195
+ julia> model
196
+ A Nonlinear.Model with:
197
+ 1 objective
198
+ 1 parameter
199
+ 1 expression
200
+ 1 constraint
137
201
```
138
202
139
203
### User-defined operators
@@ -150,11 +214,11 @@ Register a univariate user-defined operator using
150
214
julia> f(x) = 1 + sin(x)^2
151
215
f (generic function with 1 method)
152
216
153
- julia> Nonlinear.register_operator(data , :my_f, 1, f)
217
+ julia> Nonlinear.register_operator(model , :my_f, 1, f)
154
218
```
155
219
Now, you can use ` :my_f ` in expressions:
156
220
``` jldoctest nonlinear_developer
157
- julia> new_expr = Nonlinear.add_expression(data , :(my_f($x + 1)))
221
+ julia> new_expr = Nonlinear.add_expression(model , :(my_f($x + 1)))
158
222
MathOptInterface.Nonlinear.ExpressionIndex(2)
159
223
```
160
224
By default, ` Nonlinear ` will compute first- and second-derivatives of the
@@ -164,14 +228,14 @@ which compute the respective derivative:
164
228
julia> f′(x) = 2 * sin(x) * cos(x)
165
229
f′ (generic function with 1 method)
166
230
167
- julia> Nonlinear.register_operator(data , :my_f2, 1, f, f′)
231
+ julia> Nonlinear.register_operator(model , :my_f2, 1, f, f′)
168
232
```
169
233
or
170
234
``` jldoctest nonlinear_developer
171
235
julia> f′′(x) = 2 * (cos(x)^2 - sin(x)^2)
172
236
f′′ (generic function with 1 method)
173
237
174
- julia> Nonlinear.register_operator(data , :my_f3, 1, f, f′, f′′)
238
+ julia> Nonlinear.register_operator(model , :my_f3, 1, f, f′, f′′)
175
239
```
176
240
177
241
#### Multivariate operators
@@ -182,11 +246,11 @@ Register a multivariate user-defined operator using
182
246
julia> g(x...) = x[1]^2 + x[1] * x[2] + x[2]^2
183
247
g (generic function with 1 method)
184
248
185
- julia> Nonlinear.register_operator(data , :my_g, 2, g)
249
+ julia> Nonlinear.register_operator(model , :my_g, 2, g)
186
250
```
187
251
Now, you can use ` :my_f ` in expressions:
188
252
``` jldoctest nonlinear_developer
189
- julia> new_expr = Nonlinear.add_expression(data , :(my_g($x + 1, $x)))
253
+ julia> new_expr = Nonlinear.add_expression(model , :(my_g($x + 1, $x)))
190
254
MathOptInterface.Nonlinear.ExpressionIndex(3)
191
255
```
192
256
By default, ` Nonlinear ` will compute the gradient of the registered
@@ -200,7 +264,7 @@ julia> function ∇g(ret, x...)
200
264
end
201
265
∇g (generic function with 1 method)
202
266
203
- julia> Nonlinear.register_operator(data , :my_g2, 2, g, ∇g)
267
+ julia> Nonlinear.register_operator(model , :my_g2, 2, g, ∇g)
204
268
```
205
269
206
270
### [ MathOptInterface] (@id Nonlinear_MOI_interface)
@@ -209,57 +273,47 @@ MathOptInterface communicates the nonlinear portion of an optimization problem
209
273
to solvers using concrete subtypes of [ ` AbstractNLPEvaluator ` ] ( @ref ) , which
210
274
implement the [ Nonlinear programming] ( @ref ) API.
211
275
212
- [ ` Nonlinear.NonlinearData ` ] ( @ref ) is a subtype of [ ` AbstractNLPEvaluator ` ] ( @ref ) ,
213
- but the functions of the [ Nonlinear programming] ( @ref ) API that it implements
214
- depends upon the chosen [ ` Nonlinear.AbstractAutomaticDifferentiation ` ] (@ref
215
- backend.
276
+ Create an [ ` AbstractNLPEvaluator ` ] ( @ref ) from [ ` Nonlinear.Model ` ] ( @ref ) using
277
+ [ ` Nonlinear.Evaluator ` ] ( @ref ) .
278
+
279
+ [ ` Nonlinear.Evaluator ` ] ( @ref ) requires an
280
+ [ ` Nonlinear.AbstractAutomaticDifferentiation ` ] ( @ref ) backend and an ordered list
281
+ of the variables that are included in the model.
216
282
217
283
There following backends are available to choose from within MOI, although other
218
284
packages may add more options by sub-typing
219
285
[ ` Nonlinear.AbstractAutomaticDifferentiation ` ] ( @ref ) :
220
286
* [ ` Nonlinear.ExprGraphOnly ` ] ( @ref )
221
287
222
- Set the differentiation backend using
223
- ` Nonlinear.set_differentiation_backend ` ] ( @ref ) .
224
-
225
- If we set [ ` Nonlinear.ExprGraphOnly ` ] ( @ref ) , then we get access to ` :ExprGraph ` :
226
288
``` jldoctest nonlinear_developer
227
- julia> Nonlinear.set_differentiation_backend(
228
- data,
229
- Nonlinear.ExprGraphOnly(),
230
- [x],
231
- )
232
-
233
- julia> data
234
- NonlinearData with available features:
289
+ julia> evaluator = Nonlinear.Evaluator(model, Nonlinear.ExprGraphOnly(), [x])
290
+ Nonlinear.Evaluator with available features:
235
291
* :ExprGraph
236
292
```
237
-
238
- [ ` Nonlinear.set_differentiation_backend ` ] ( @ref ) requires an ordered list of the
239
- variables that are included in the model. This order corresponds to the order of
240
- the primal decision vector ` x ` which is passed to the various functions in MOI's
241
- nonlinear API.
293
+ The functions of the [ Nonlinear programming] ( @ref ) API implemented by
294
+ [ ` Nonlinear.Evaluator ` ] ( @ref ) depends upon the chosen
295
+ [ ` Nonlinear.AbstractAutomaticDifferentiation ` ] (@ref backend.
242
296
243
297
The ` :ExprGraph ` feature means we can call [ ` objective_expr ` ] ( @ref ) and
244
298
[ ` constraint_expr ` ] ( @ref ) to retrieve the expression graph of the problem.
245
299
However, we cannot call gradient terms such as
246
300
[ ` eval_objective_gradient ` ] ( @ref ) because [ ` Nonlinear.ExprGraphOnly ` ] ( @ref ) does
247
301
not have the capability to differentiate a nonlinear expression.
248
302
249
- Instead of passing [ ` AbstractNLPEvaluator ` ] ( @ref ) s directly to solvers,
303
+ Instead of passing [ ` Nonlinear.Evaluator ` ] ( @ref ) directly to solvers,
250
304
MathOptInterface instead passes an [ ` NLPBlockData ` ] ( @ref ) , which wraps an
251
- [ ` AbstractNLPEvaluator ` ] ( @ref ) and includes other information such as constraint
305
+ [ ` Nonlinear.Evaluator ` ] ( @ref ) and includes other information such as constraint
252
306
bounds and whether the evaluator has a nonlinear objective. Create an
253
- ` NLPBlockData ` ] ( @ref ) as follows:
307
+ [ ` NLPBlockData ` ] ( @ref ) as follows:
254
308
``` jldoctest nonlinear_developer
255
- julia> MOI.NLPBlockData(data );
309
+ julia> MOI.NLPBlockData(evaluator );
256
310
```
257
311
258
312
## Expression-graph representation
259
313
260
- [ ` Nonlinear.NonlinearData ` ] ( @ref ) stores nonlinear expressions in
261
- [ ` Nonlinear.NonlinearExpression ` ] ( @ref ) s. This section explains the design of
262
- the expression graph datastructure in [ ` Nonlinear.NonlinearExpression ` ] ( @ref ) .
314
+ [ ` Nonlinear.Model ` ] ( @ref ) stores nonlinear expressions in
315
+ [ ` Nonlinear.Expression ` ] ( @ref ) s. This section explains the design of
316
+ the expression graph datastructure in [ ` Nonlinear.Expression ` ] ( @ref ) .
263
317
264
318
Given a nonlinear function like ` f(x) = sin(x)^2 + x ` , a conceptual aid for
265
319
thinking about the graph representation of the expression is to convert it into
@@ -350,7 +404,7 @@ julia> struct Node
350
404
index::Int
351
405
end
352
406
353
- julia> struct NonlinearExpression
407
+ julia> struct Expression
354
408
nodes::Vector{Node}
355
409
values::Vector{Float64}
356
410
end
@@ -368,7 +422,7 @@ The `.parent` field of each node is the integer index of the parent node in
368
422
369
423
Therefore, we can represent our function as:
370
424
``` jldoctest expr_graph
371
- julia> expr = NonlinearExpression (
425
+ julia> expr = Expression (
372
426
[
373
427
Node(NODE_CALL_MULTIVARIATE, 1, -1),
374
428
Node(NODE_CALL_MULTIVARIATE, 2, 1),
@@ -399,8 +453,8 @@ evaluates all children nodes before their parent.
399
453
400
454
### The design in practice
401
455
402
- In practice, ` Node ` and ` NonlinearExpression ` are exactly [ ` Nonlinear.Node ` ] ( @ref )
403
- and [ ` Nonlinear.NonlinearExpression ` ] ( @ref ) . However, [ ` Nonlinear.NodeType ` ] ( @ref )
456
+ In practice, ` Node ` and ` Expression ` are exactly [ ` Nonlinear.Node ` ] ( @ref )
457
+ and [ ` Nonlinear.Expression ` ] ( @ref ) . However, [ ` Nonlinear.NodeType ` ] ( @ref )
404
458
has more fields to account for comparison operators such as ` :>= ` and ` :<= ` ,
405
459
logic operators such as ` :&& ` and ` :|| ` , nonlinear parameters, and nested
406
460
subexpressions.
@@ -412,6 +466,6 @@ operators and a vector of comparison operators. In addition to
412
466
[ ` Nonlinear.DEFAULT_MULTIVARIATE_OPERATORS ` ] ( @ref ) , you can register
413
467
user-defined functions using [ ` Nonlinear.register_operator ` ] ( @ref ) .
414
468
415
- [ ` Nonlinear.NonlinearData ` ] ( @ref ) is a struct that stores the
469
+ [ ` Nonlinear.Model ` ] ( @ref ) is a struct that stores the
416
470
[ ` Nonlinear.OperatorRegistry ` ] ( @ref ) , as well as a list of parameters and
417
471
subexpressions in the model.
0 commit comments