Skip Symbolic Differentiation
Although symbolic differentiation is convenient for most problems, you may want to skip it for the following reasons:
- The problem cannot be simply described as symbolic expressions
- There are other more suitable automatic differentiation methods
- Functions need to call pre-compiled external libraries
- Want to directly call compiled functions for better performance
Setup Method
If you need to skip symbolic differentiation for certain functions, the method is similar to using the cache feature (see Compilation Is Very Slow). Simply place the manually edited function files in a specified folder, then set the cache parameter to that folder path in the set_* functions. Pockit will directly load these functions, thereby skipping symbolic differentiation.
For example, if you need to skip symbolic differentiation of the dynamics equation for the first state variable, you can prepare a cache/dynamics_0.py file, then set cache="cache" in the set_dynamics function. Regardless of the symbolic dynamics equation passed in (can be set to 0), pockit will directly load the cache/dynamics_0.py file. The filenames for different functions are shown in the following table:
| Function | Filename |
|---|---|
Phase.set_dynamics |
dynamics_{i}.py |
Phase.set_integral |
integral_{i}.py |
Phase.set_phase_constraint |
phase_constraint_{i}.py |
Phase.set_boundary_condition |
boundary_condition_0_{i}.py,boundary_condition_f_{i}.py,boundary_condition_t_0.py,boundary_condition_t_f.py |
System.set_objective |
objective.py |
System.set_system_constraint |
system_constraint_{i}.py |
File Format
The provided Python files should contain vector functions F, G, H and variables G_index, H_index_row, H_index_col. These functions and variables are defined as follows (also see the API documentation):
- Functions
F,G,Htake two parameters: a one-dimensional NumPy arrayxand a scalarl. The functions should return values atldifferent points. Inx, every consecutivelelements represent the values of one parameter at different points. For example, if the function is \(f(x_0, x_1, \dots, x_{m - 1})\), the vectorized function should compute values at points \([f(x_0, x_1,\)\( \dots, x_{l - 1}), \)\(f(x_l, x_{l + 1}, \)\(\dots, x_{2l - 1}), \)\(\dots, \)\(f(x_{(m - 1) l}, x_{(m - 1) l + 1}, \)\(\dots, x_{-1})\)\(]\). - Function
Freturns a one-dimensional NumPy array of lengthl, representing the values of function \(f\) atlpoints. FunctionGreturns a two-dimensional NumPy array of shape(len(G_index), l), representing the gradient values of function \(f\) atlpoints. FunctionHreturns a two-dimensional NumPy array of shape(len(H_index_row), l), representing the Hessian matrix values of function \(f\) atlpoints. - Variables
G_index,H_index_row,H_index_colmust correspond to the outputs ofGandH. These variables should be integer NumPy arrays, representing the indices of non-zero elements in the gradient and Hessian matrix of function \(f\).H_index_rowandH_index_colhave equal length and only contain indices of the lower triangular part. (The Hessian matrix is symmetric, so only the lower triangular part needs to be stored.)G_indexandH_index_rowshould be strictly increasing, andH_index_colshould also be strictly increasing within the same row.
Example files can be found in the generated cache files.
Given a system with \(n_x\) state variables, \(n_u\) control variables, \(n_i\) integrals, and \(n_s\) system parameters, the input parameters and dimensions for different functions are shown in the following table:
| Function | Input Parameters | Input Dimension \(m\) |
|---|---|---|
Phase.set_dynamics |
\(x\), \(u\), \(t\), \(s\) | \(n_x + n_u + 1 + n_s\) |
Phase.set_integral |
\(x\), \(u\), \(t\), \(s\) | \(n_x + n_u + 1 + n_s\) |
Phase.set_phase_constraint |
\(x\), \(u\), \(t\), \(s\) | \(n_x + n_u + 1 + n_s\) |
Phase.set_boundary_condition |
\(s\) | \(n_s\) |
System.set_objective |
\(I\), \(s\) | \(n_i + n_s\) |
System.set_system_constraint |
\(I\), \(s\) | \(n_i + n_s\) |