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
,H
take two parameters: a one-dimensional NumPy arrayx
and a scalarl
. The functions should return values atl
different points. Inx
, every consecutivel
elements 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
F
returns a one-dimensional NumPy array of lengthl
, representing the values of function \(f\) atl
points. FunctionG
returns a two-dimensional NumPy array of shape(len(G_index), l)
, representing the gradient values of function \(f\) atl
points. FunctionH
returns a two-dimensional NumPy array of shape(len(H_index_row), l)
, representing the Hessian matrix values of function \(f\) atl
points. - Variables
G_index
,H_index_row
,H_index_col
must correspond to the outputs ofG
andH
. 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_row
andH_index_col
have 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_index
andH_index_row
should be strictly increasing, andH_index_col
should 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\) |