We can generate C code of an objective function by using Maple as
- with(linalg);
- F := ...;
- Ffunc := unapply(convert(convert(F, vector), list), PARAMETERS);
- CodeGeneration[C](Ffunc, optimize);
I tried the following equation $latex \frac{p_0}{ 1 + exp(p_1 - p_2*x) } $ as
- F := < p_0 / ( 1 + exp(p_1 - p_2*x) ) >;
- Ffunc := unapply(convert(convert(F, vector), list), p_0, p_1, p_2, x);
- CodeGeneration[C](Ffunc, optimize);
The result is as follows:
The above result looks nice. However, this style cannot handle huge size of parameters like hundreds or thousands. Therefore, the variables p_ should be converted to a single dynamic array double p for handling arbitrary dimensionality of parameters.
The revised version of Maple code is
- F := < p[1] / ( 1 + exp(p[2] - p[3]*x) ) >;
- Ffunc := unapply(convert(convert(F, vector), list), p, x);
- CodeGeneration[C](Ffunc, optimize);
NOTE that the indices of the parameters are incremented due to very important reason, mentioned below. The result is
Then, it follows similar way to derive jacobian function.
- J := jacobian(F, [ PARAMETERS ]);
- Jfunc := unapply(convert(convert(J, vector), list), PARAMETERS);
- CodeGeneration[C](Jfunc, optimize);
In this example, the command is
- J := jacobian(F, [ p[1], p[2], p[3] ]);
- Jfunc := unapply(convert(convert(J, vector), list), p);
- CodeGeneration[C](Jfunc, optimize);
Then, we obtain the following result
This looks perfect as well. Finally, I can use these objective and jacobian functions for performing non-linear optimization.
NOTE: you can easily understand the reason why the argument's indices must start from 1. Index rule of Maple is same as one of MatLab, meaning 1 origin. If we start the index with 0, generated code use p[-1] as following result shows.