Introduction
Although you can substitute symbolic variables with numerical values to get a particular numerical result from a symbolic expression, the process of doing substitution is slow and inefficient. The best way to use these symbolic expressions in the Matlab’s numerical calculation is exporting them as C++ source code and compile them as MEX binaries (or use it on other C++ projects directly).
When exporting to C++ code, the original expression will be first optimized using Common Subexpression Elimination (CSE) techniques, and then export to C++ files based on the given template.
Simplify
method for Mathematica expressions, as the process would take very long time
potentially. The CSE optimization requires less time and provides almost the
same optimal solution at the end. There are two ways to export a SymExpression
object:
- using
export
method ofSymExpression
class directly; - create a wrapper
SymFunction
object first and then useexport
method ofSymFunction
class.
The first one is straightforward, but needs to provide many information at
exporting. The second approach stores some information at initiating the
SymFunction
object, hence, less information is needed at exporting.
Using export
Method
The basic syntax of exporting would looks like this:
export(expr,'Param1','Value1',...);
where Param1
and Value1
is a pair of parameter-value (as of graphic commands in Matlab):
The following two parameters must be provided:
- Vars : the list of symbolic variables.
- File : the full path of the file to be exported to
Vars
should be a cell array of
`SymVariable` objects that cover all symbolic variables present in the
expression. Otherwise the exported code will result in undefined variables.
File
should be the full path of the file
name. If only the file name is given, it will be exported to the current folder.
>> a = SymVariable('a');
>> b = SymVariable('b');
>> b_vec = SymVaraible('var',[3,1]);
>> expr = tomatrix((b*(a+b)).^2) * b_vec;
>> export(expr,'Vars',{a,b,b_vec},'File','test'); % expr is from the previous example
Compiling: test.cc Elapsed time is 0.321564 seconds.
To use the exported function, the order and dimensions of input arguments must
match the order in Vars
.
>> test(1,2,[3,4,5])
ans =
108
144
180
There are some optional parameters for different type of operations:
- ForceExport: If
false
and the same file already exists, then the export process will be skipped with warning. However, if this option set to betrue
, then it will be exported regardless of the previous status. Default:false
- BuildMex: If
true
, the exported C++ source code will be compiled as MEX binary so that can be used directly in Matlab. Default:true
- Namespace: The exported function can be defined as a specific
Namespace. Default:
SymExpression
- TemplateFile: The template file for the C++ source code. If empty, then
use the default template file comes with FROST. Default:
[]
- TemplateHeader: The template file for the C++ header file. If empty, then
use the default template file comes with FROST. Default:
[]
Use SymFunction
Wrapper Class
Creating SymFunction
Objects
The main advantage of using SymFunction
is to store the required information
(Namely, Vars
and File
) as initialization. In addition, you can compute the
first and second order partial derivatives (Jacobian and Hessian) with respect
to the dependent variables. In particular, the SymFunction
separate dependent
symbolic variables in two main catagories: variables and parameters. The
automatic partial derivatives will be only computed with respect to variables;
parameters will be considered constants.
To initialize a SymFunction
object, run:
>> func = SymFunction('test', expr, {b_vec}, {a,b});
Here, the function name of the symbolic expression expr
is 'test'
, the
dependent variable is b_vec
and parameters are a
and b
.
Exporting SymFunction
Objects
Exporting a SymFunction
object is much easier:
>> export(func, export_path); % export_path is some path to be exported
To call the exported function (MEX) in Matlab, the orders and dimensions of input arguments should matches the orders and dimensions of variables and parameters (variables first), e.g.,
>> test([3,4,5],1,2)
ans =
108
144
180
>> sqrt(func)
ans =
{{Sqrt[b^2*(a + b)^2*var$1$1]}, {Sqrt[b^2*(a + b)^2*var$2$1]}, {Sqrt[b^2*(a + b)^2*var$3$1]}}
Exporting Jacobian and Hessian of Symbolic Expression
With SymFunction
, users can directly export the first order partial
derivatives (Jacobian) and the second order partial derivatives (Hessian) of the
symbolic expression using exportJacobian
and exportHessian
methods.
Exporting Jacobian
When exporting the Jacobian matrix, the method export two functions: one with prefix “J_” and another with prefix “Js_”. For example:
>> exportJacobian(func,pwd); % pwd is the current directory
Compiling: J_test.cc Elapsed time is 0.239276 seconds.
Compiling: Js_test.cc Elapsed time is 0.205092 seconds.
Where “Js_test” returns the indices of non-zero entries of the sparse Jacobian matrix, and “J_test” returns the values of non-zero entries. To construct the actual Jacobian matrix:
>> idx = Js_test(0);
>> val = J_test([1,2,3],1,2);
>> jac_sparse = sparse(idx(:,1),idx(:,2),val);
>> jac_full = full(jac_sparse)
jac_full =
36 0 0
0 36 0
0 0 36
Exporting Hessian
When exporting the Hessian matrix, the method export two functions: one with prefix “H_” and another with prefix “Hs_”.
>> exportHessian(func,pwd);
Compiling: H_test.cc Elapsed time is 0.211086 seconds.
Compiling: Hs_test.cc Elapsed time is 0.201248 seconds.
Similarly, “Hs_test” returns the indices of non-zero entries of the sparse Hessian matrix, and “H_test” returns the values of non-zero entries.
To call “H_test”, the last argument must be the weights lambda
, e.g.,
idx = Hs_test(0);
val = H_test([1,2,3],1,2,[1,10,100]);