File: 03.dox

package info (click to toggle)
casadi 3.7.0%2Bds2-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 19,964 kB
  • sloc: cpp: 114,229; python: 35,462; xml: 1,946; ansic: 859; makefile: 257; sh: 114; f90: 63; perl: 9
file content (425 lines) | stat: -rw-r--r-- 21,191 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
/*! \page chapter3 Symbolic core

<table style="width: 100%;">
   <tr><td style="text-align: left;">Previous chapter: \ref chapter2</td>
       <td style="text-align: right;">Next chapter: \ref chapter4</td>
   </tr>
</table>
\b Contents
<ol>
<li> \ref section3_1
<li> \ref section3_2
<ul>
<li> \ref subsection3_2_1
<li> \ref subsection3_2_2
</ul>
<li> \ref section3_3
<ul>
<li> \ref subsection3_3_1
<li> \ref subsection3_3_2
<li> \ref subsection3_3_3
</ul>
</ol>
   In CasADi a very powerful symbolic abstraction of mathematical functions is implemented.
   In this chapter we will learn how to create general functions out of our model equations, 
   how to evaluate them and optionally their derivatives. We also give some instructional
   examples to make it more easily understandable.
\section section3_1 Symbolic expressions
   Normally, mathematical expressions represent operations between variables and parameters.
   In order to build up our models, we need to have a computer-based abstraction of these. In CasADi
   the casadi::SX class provides us exactly these building blocks. We create a simple expression:
<table border="0" style="border-style: dotted; border-width: 1px;">
   <tr><td>Example:</td><td>Output:</td>
   <tr style="vertical-align: top;"><td>
\code
     1  #include "casadi/sx/sx.hpp"
     2  using namespace casadi;
     3  int main(int argc, char* argv[]){
     4     SX x("x");
     5     SX expr;
     6     cout << "x: " << x << endl;
     7     cout << "expr: " << expr << endl;
     8     expr = 3.0 * x + pow(x, 2) - sin(x);
     9     cout << "expr: " << expr << endl;
    10     SX y("y");
    11     expr += y / 2 / x;
    12     cout << "expr: " << expr << endl;
    13  }
\endcode
   </td>
   <td>
\code
x: x
expr: nan
expr: (((3*x)+(x*x))-sin(x))
expr: ((((3*x)+(x*x))-sin(x))+((y/2)/x))
\endcode
   </td>
   </tr>
</table>
On the 1st line we include the header file containing the casadi::SX class, on the 4th the \c x object
is created and from here on the string \c "x" is assigned to this variable. We can also create 
casadi::SX objects by invoking the default constructor (line 5), although this variable is not initialized to any symbolic
expression at this time. The \c expr object is initialized on line 8, while from the line 10 on we extend our expression
with a \c y variable. One can always check whether an expression is correct by simply printing it to the standard output.
With the use of casadi::SX objects and the <tt>+ - * / += -= *= /= exp log sqrt sin pow</tt> etc. operations we can build up a
wide range of mathemetical expressions.
We can also create a vector of expressions if needed, although each element must be initialized that may be
carried out by the casadi::make_symbolic() function. Now we demonstrate how this works.
<table border="0" style="border-style: dotted; border-width: 1px;">                                                                                                                                            
   <tr><td>Example:</td><td>Output:</td>                                                                                                                                                                       
   <tr style="vertical-align: top;"><td>
\code
     1  #include "casadi/sx/sx.hpp"
     2  #include "casadi/sx/sx_tools.hpp"
     3  
     4  ...
     5  vector<SX> z(10);
     6  make_symbolic(z.begin(), z.end(), "z");
     7  cout << "z[4]: " << z[4] << endl;
     8  ...
\endcode
   </td> 
   <td>
\code
z[4]: z_4
\endcode
   </td>
   </tr>
   </table>
After invoking make_symbolic (line 6) the elements of \c z are assigned to <tt>z_0, z_1, ...</tt>  and can be used later on in modelling.
\section section3_2 Functions 
Now that we can build up mathematical expressions we would like to evaluate them symbolically or numerically. We will see how this can be
done with the casadi::SXFunction object, which can represent mathematical functions that has prototype
 \f$\mathbb{R} \rightarrow \mathbb{R}\f$, \f$\mathbb{R}^n \rightarrow \mathbb{R}\f$,
\f$\mathbb{R}^n \rightarrow \mathbb{R}^m \f$ or \f$\mathbb{R}^{n_1 \times n_2} \rightarrow \mathbb{R}^{m_1 \times m_2}\f$.
In the constructor of casadi::SXFunction one has to give two arguments. The first argument should contain all the variables
that the function will depend on, and the second argument stores the function definition itself. The data type of the arguments may be various
depending on the prototype of the function that is to be represented. Let's see some examples.
\subsection subsection3_2_1 Numerical evaluation
Most often we would like to compute the value of a function in a certain point. In this subsection we will learn how to do that
 in case of different function prototypes.
First we create and evaluate a simple scalar-scalar function numerically.
<table border="0" style="border-style: dotted; border-width: 1px;">                                                                                                                                            
   <tr><td>Example:</td><td>Output:</td>                                                                                                                                                                       
   <tr style="vertical-align: top;"><td>
\code
     1  #include "casadi/sx/sx.hpp"
     2  ...
     3  SX x("x");
     4  SX f_expr = x * x - 3 * x + 2;
     5  SXFunction f(x, f_expr);
     6  f.init();
     7  double d = 10.0;
     8  f.setInput(d);
     9  f.evaluate();
    10  cout << "Function value in x = " << d << " : " << f.output() << "\n";
\endcode
   </td>                                                                                                                                                                                                       
   <td>
\code
Function value in x = 10 : 72
\endcode
   </td>
   </tr>
   </table>
On line 4 we create the expression that will represent our function. The SXFunction
object is created (line 5) with the variable \c x and the \c f_expr object.
Before passing any input to the function, we have to initialize it (see line 6). Then we set the input
of the function, evaluate it and finally print the result.

Now we create a vector-scalar function that calculates the 2-norm of its argument.
<table border="0" style="border-style: dotted; border-width: 1px;">                                                                                                                                            
   <tr><td>Example:</td><td>Output:</td>                                                                                                                                                                       
   <tr style="vertical-align: top;"><td>
\code
     1  vector<SX> x(4);
     2  make_symbolic(x.begin(), x.end(), "x");
     3  SX f_expr = 0;
     4  for(int i = 0; i < x.size(); ++i){
     5     f_expr += x[i] * x[i];
     6  }
     7  f_expr = sqrt(f_expr);
     8  SXFunction f(x, f_expr);
     9  f.init();
    10  vector<double> d(x.size());
    11  fill(d.begin(), d.end(), 3);
    12  f.setInput(d);
    13  f.evaluate();
    14  cout << "Function value: " << f.output() << "\n";
\endcode
   </td>                                                                                                                                                                                                       
   <td>
\code
Function value: 6
\endcode
   </td>
   </tr>
   </table>
The principle is exactly the same, the only difference is that now we pass a \c std::vector<SX> in the first argument
on line 8 and we provide a \c std::vector<double> as an input on line 12.

Now we define and evaluate a vector-vector function.
<table border="0" style="border-style: dotted; border-width: 1px;">                                                                                                                                            
   <tr><td>Example:</td><td>Output:</td>                                                                                                                                                                       
   <tr style="vertical-align: top;"><td>
\code
     1  vector<SX> x(3);
     2  make_symbolic(x.begin(), x.end(), "x");
     3  vector<SX> f_expr(2);
     4  fill(f_expr.begin(), f_expr.end(), 0);
     5  f_expr[0] = x[0] + 2 * x[1];
     6  f_expr[1] = x[1] + 4 * exp(x[2]);
     7  SXFunction f(x, f_expr);
     8  f.init();
     9  vector<double> d(3);
    10  fill(d.begin(), d.end(), 2);
    11  f.setInput(d);
    12  f.evaluate();
    13  vector<double> value = f.output().data();
    14  cout << "[" << value.size() << "](";
    15  for(int i = 0; i < value.size(); ++i){
    16     cout << value[i] << ",";
    17  }
    18  cout << "\b)\n";
\endcode
   </td>                                                                                                                                                                                                       
   <td>
\code
[2](6,31.5562)
\endcode
   </td>
   </tr>
   </table>
This time both arguments of the constructor on line 7 are \c std::vector<SX>
 and the function value is accessible via
 SXFunction.output().data() (line 13).

As the last example let's see a piece of code, where the function depends on a  <tt> std::vector<std::vector<SX> > </tt>. 
Note that this covers the case when our function depends on a matrix.
<table border="0" style="border-style: dotted; border-width: 1px;">                                                                                                                                            
   <tr><td>Example:</td><td>Output:</td>                                                                                                                                                                       
   <tr style="vertical-align: top;"><td>
\code
     1  vector<vector<SX> > variables;
     2  vector<SX> x(3);
     3  make_symbolic(x.begin(), x.end(), "x");
     4  variables.push_back(x);
     5  vector<SX> y(2);
     6  make_symbolic(y.begin(), y.end(), "y");
     7  variables.push_back(y);
     8  vector<SX> f_expr(2);
     9  f_expr[0] = x[0] + x[2] - sin(y[0]);
    10  f_expr[1] = cos(x[1] - y[1]);
    11  SXFunction f(variables, f_expr);
    12  f.init();
    13  vector<double> d0(3);
    14  fill(d0.begin(), d0.end(), 6.0);
    15  vector<double> d1(2);
    16  fill(d1.begin(), d1.end(), 3.0);
    17  f.setInput(d0, 0);
    18  f.setInput(d1, 1);
    19  f.evaluate();
    20  vector<double> value = f.output().data();
    21  cout << "[" << value.size() << "](";
    22  for(int i = 0; i < value.size(); ++i){
    23     cout << value[i] << ",";
    24  }
    25  cout << "\b)\n";
\endcode
   </td>                                                                                                                                                                                                       
   <td>
\code
[2](11.8589,-0.989992)
\endcode
   </td>
   </tr>
   </table>
In variable \c variables we collect vectors of SX objects. On line 17 and 18 you can notice
a new argument (which was always 0 until now) that addresses an input vector. In this example on the first coordinate
we have a 3 long vector, on the second we have a 2 long vector, which correspond to the function definition (line 11).
It is important to understand the concept of functions depending on matrices, because, as it will be shown later on (see
\ref chapter4), integrators are exactly of this type.

\subsection subsection3_2_2 Symbolic evaluation
One might also wish to replace certain variables in a symbolic expression with some other variables
  or with more complex expressions. This may be carried out easily by the use of symbolic evaluation, we use
  the casadi::SXFunction::eval() member function.
<table border="0" style="border-style: dotted; border-width: 1px;">                                                                                                                                            
   <tr><td>Example:</td><td>Output:</td>                                                                                                                                                                       
   <tr style="vertical-align: top;"><td>
\code
     1  vector<SX> x(3);
     2  make_symbolic(x.begin(), x.end(), "x");
     3  vector<SX> f_expr(2);
     4  f_expr[0] = x[0] + 5 * x[1];
     5  f_expr[1] = x[0] + cos(x[2]);
     6  SXFunction f(x, f_expr);
     7  f.init();
     8  vector<SX> y = x;
     9  y[0] = x[1] + pow(x[2], 3);
    10  vector<SX> f_expr_subs = f.eval(y);
    11  cout << f_expr[0] << " --> " << f_expr_subs[0] << endl;
    12  cout << f_expr[1] << " --> " << f_expr_subs[1] << endl;
\endcode
   </td>                                                                                                                                                                                                       
   <td>
\code
(x_0+(5*x_1)) --> ((x_1+(x_2*(x_2*x_2)))+(5*x_1))
(x_0+cos(x_2)) --> ((x_1+(x_2*(x_2*x_2)))+cos(x_2))
\endcode
   </td>
   </tr>
   </table>
First we create a function depending on the vector \c x (line 1-7), then we create a vector of SX objects, whose
size correspond to the function definition and we modify the first element by an arbitrary expression (line 9). As a result we get
back the function expression in which the substitution has already been committed.
\section section3_3 Calculating derivatives
In this section we will learn how to calculate first-order derivatives of general functions. Within CasADi derivatives of general
functions may be calculated in two ways. First, the derivatives are calculated numerically based on automatic differentiation,
 which has two modes forward and backward. Second, knowing the symbolic representation of the functions one may differentiate
 symbolically.
\subsection subsection3_3_1 Forward differentiation
 In the forward mode one can calculate the directional derivative
\f$J p\f$, where \f$J\f$ is the Jacobian of a \f$f: \mathbb{R}^n \rightarrow \mathbb{R}^m\f$ and \f$p \in \mathbb{R}^m\f$ is the direction.
In the following code we calculate the full Jacobian providing multiple directions.
<table border="0" style="border-style: dotted; border-width: 1px;">                                                                                                                                            
   <tr><td>Example:</td><td>Output:</td>                                                                                                                                                                       
   <tr style="vertical-align: top;"><td>
\code
     1  vector<SX> x(3);
     2  make_symbolic(x.begin(), x.end(), "x");
     3  vector<SX> f_expr(2);
     4  f_expr[0] = x[0] + 5 * x[1];
     5  f_expr[1] = x[0] + cos(x[2]);
     6  SXFunction f(x, f_expr);
     7  f.setOption("number_of_fwd_dir", (int)x.size());
     8  f.init();
     9  vector<double> d(x.size());
    10  fill(d.begin(), d.end(), 4.0);
    11  f.setInput(d);
    12  vector<double> fwd_seed(x.size());
    13  fill(fwd_seed.begin(), fwd_seed.end(), 0);
    14  for(int i = 0; i < x.size(); ++i){
    15     fwd_seed[i] = 1;
    16     f.setFwdSeed(fwd_seed, 0, i);
    17     fwd_seed[i] = 0;
    18  }
    19  f.evaluate(x.size(), 0);
    20  cout << "Function value: " << f.output() << endl;
    21  vector<double> jacobian_column;
    22  for(int i = 0; i < x.size(); ++i){
    23     jacobian_column = f.fwdSens(0, i).data();
    24     cout << "[" << jacobian_column.size() << "](";
    25     for(int j = 0; j < jacobian_column.size(); ++j){
    26        cout << jacobian_column[j] << ",";
    27     }
    28     cout << "\b)\n";
    29  }
\endcode
   </td>                                                                                                                                                                                                       
   <td>
\code
Function value: [24,3.34636]
[2](1,1)
[2](5,0)
[2](0,0.756802)
\endcode
   </td>
   </tr>
   </table>
 The first new thing is on line 7, we set an option called \c number_of_fwd_dir to the number
of the forward directions in which we would like to differentiate. On line 16 we are inside a for loop
and we provide the directions; now only columns of the identity matrix. The way of evaluation is also
slightly different (line 19), so far we haven't given any arguments. The first argument indicates the number of
forward derivatives to be evaluated, the second is just the same,
 but with adjoint derivatives. In any case, the function itself is evaluated. We can collect our
directional derivatives by the casadi::SXFunction::fwdSens() member function (line 23). Note that the first argument addresses
the the matrix input. Since we have only vector input now, this is always zero.


\subsection subsection3_3_2 Backward (adjoint) differentiation
In this mode of derivative calculation one can calculate \f$J^T p\f$. Mutiple directions are not yet supported by CasADi.
The code is as follows:

<table border="0" style="border-style: dotted; border-width: 1px;">                                                                                                                                            
   <tr><td>Example:</td><td>Output:</td>                                                                                                                                                                       
   <tr style="vertical-align: top;"><td>
\code
     1  vector<SX> x(3);
     2  make_symbolic(x.begin(), x.end(), "x");
     3  vector<SX> f_expr(2);
     4  f_expr[0] = x[0] + 5 * x[1];
     5  f_expr[1] = x[0] + cos(x[2]);
     6  SXFunction f(x, f_expr);
     7  f.setOption("number_of_adj_dir", 1);
     8  f.init();
     9  vector<double> d(x.size());
    10  fill(d.begin(), d.end(), 4.0);
    11  f.setInput(d);
    12  vector<double> adj_seed(f_expr.size());
    13  fill(adj_seed.begin(), adj_seed.end(), 1);
    14  f.setAdjSeed(adj_seed, 0, 0);
    15  f.evaluate(0, 1);
    16  cout << "Function value: " << f.output() << endl;
    17  cout << "Adjoint derivative: " << f.adjSens(0, 0) << endl;
\endcode
   </td>                                                                                                                                                                                                       
   <td>
\code
Function value: [24,3.34636]
Adjoint derivative: [2,5,0.756802]
\endcode
   </td>
   </tr>
   </table>
This time we set the option \c number_of_adj_dir (greater than 1 throws an error) and we invoke SXFunction::evaluate(0, 1).
The adjoint derivative we can access by the casadi::SXFunction::adjSens(...) method.

\subsection subsection3_3_3 Symbolic differentiation
The second way one can differentiate is by symbolic manipulation. The result of this approach is nothing else than a
function symbolically representing the first derivative of the original function. The following example demonstrates this.
<table border="0" style="border-style: dotted; border-width: 1px;">                                                                                                                                            
   <tr><td>Example:</td><td>Output:</td>                                                                                                                                                                       
   <tr style="vertical-align: top;"><td>
\code
     1  vector<SX> variables;
     2  vector<SX> x(3);
     3  make_symbolic(x, "x");
     4  variables = x;
     5  vector<SX> f_expr(2);
     6  f_expr[0] = x[0] + x[2] - sin(x[0]);
     7  f_expr[1] = cos(x[1] - x[2] * x[0]);
     8  SXFunction f(variables, f_expr);
     9  f.init();
    10  SXFunction f_der = f.jacobian();
    11  cout << "f: " << f.mx_out2() << "\n"; 
    12  cout << "f_der: " << f_der.mx_out2() << "\n";
    13  vector<double> d0(3);
    14  fill(d0.begin(), d0.end(), 6.0);
    15  f_der.init();
    16  f_der.setInput(d0);
    17  f_der.evaluate();
    18  cout << "Jacobian: " << f_der.output() << "\n"; 
\endcode
   </td>                                                                                                                                                                                                       
   <td>
\code
f: [((x_0+x_2)-sin(x_0)),cos((x_1-(x_2*x_0)))]
f_der: [[((-cos(x_0))+1),0,1],[(x_2*sin((x_1-(x_2*x_0)))),(-sin((x_1-(x_2*x_0)))),(x_0*sin((x_1-(x_2*x_0))))]]
Jacobian: [[0.0398297,0,1],[5.92819,-0.988032,5.92819]]
\endcode
   </td>
   </tr>
   </table>
The code is very self-explanatory, we create a vector-vector function (line 1-9) and invoke the SXFunction::jacobian() method, which
returns an SXFunction object. This object, since it's a function itself, can be evaluated and differentiated again.
This way one may calculate higher-order derivatives.
<table style="width: 100%;">
   <tr><td style="text-align: left;">Previous chapter: \ref chapter2</td>
       <td style="text-align: right;">Next chapter: \ref chapter4</td>
   </tr>
</table>

 */