Developer Guide#
This page contains additional information for people who want to extend acados
.
Contributing#
Contributions are handled via pull requests on Github
Fork the project
Push your changes to your fork
Open a pull request https://github.com/acados/acados
Describe what you changed and why
Rather make minimal changes
Rather more commits than less
Memory management in acados
#
The following are guidelines on how memory should be assigned for an acados
structure astruct
.
There are two functions: astruct_calculate_size()
, astruct_assign()
.
astruct_calculate_size()
#
Must return a multiple of 8 to keep the pointer aligned to 8 bytes when allocating substructures. Thus, it should end with:
make_int_multiple_of(8, &size);
astruct_assign()
#
Should assign its members in the following order:
Align to 8 bytes, i.e.:
align_char_to(8, &c_ptr);
Assign structure itself, i.e.:
astruct *as_instance = (astruct *) c_ptr;
c_ptr += sizeof(astruct);
Assign pointers to substructures, if
astruct
contains an array ofbstruct
s, e.g.
mem->bstructs = (void **) c_ptr;
c_ptr += N*sizeof(void *);
Align to 8 bytes, since
astruct
might containint
s and the pointers were assigned.Assign “substructures”, i.e. structures that
astruct
has pointers to:
// assume astruct contains an instance of bstruct
as_instance->bstruct = bstruct_assign(c_ptr,...);
c_ptr += bstruct_calculate_size(astruct);
Note:
since calculate_size returns multiple of 8,
c_ptr
is still aligned to 8 bytes.blasfeo_dmat_structs
,blasfeo_dvec_structs
can be seen as “substructures” here.
Assign doubles (are 8 bytes anyway)
assign_and_advance_double(n_doubles, &as_instance->doubles, &c_ptr);
Assign pointers (4 bytes on 32 Bit)
assign_and_advance_double_ptrs(n_pointers, &as_instance->double_pointer, &c_ptr);
Align to 8 bytes, can be skipped if no pointers have been assigned
Assign integers
assign_and_advance_int(n_integers, &as_instance->ints, &c_ptr);
Align to 64 bytes, i.e.:
align_char_to(64, &c_ptr);
Assign
blasfeo_dmat_mem
(are multiple of 64 Bytes)
assign_and_advance_blasfeo_dmat_mem(nrow, ncol, &as_instance->blasfeo_mat, &c_ptr);
Assign
blasfeo_vec_mem
(are multiple of 32 Bytes)
assign_and_advance_blasfeo_dvec_mem(n, &as_instance->blasfeo_vec, &c_ptr);
Align c_ptr to 8 byte here for nested assigns, see “substructures”
relevant if no
blasfeo_mems
are inastruct
Regularization within SQP / SQP-RTI#
The Hessian of the QP is computed in the ocp_nlp_sqp
, ocp_nlp_sqp_rti
module respectively.
The following steps are carried out:
ocp_nlp_approximate_qp_matrices()
sets all Hessian blocks to 0.0
for
i in range(N+1)
if
i<N:
add to the diagonal of the Hessian of block
i
the termin->Ts[i] * opts->levenberg_marquardt
add the contribution of the dynamics module (can be turned off via
exact_hess_dyn
)
if
i==N:
add to the diagonal of the Hessian of block
N
the termopts->levenberg_marquardt
.
add the cost contribution to the Hessian
Gauss-Newton Hessian (available in least-squares case)
or exact Hessian (always used with
EXTERNAL
cost module) if no “custom hessian” is set (seecost_expr_ext_cost_custom_hess
,cost_expr_ext_cost_custom_hess_0
,cost_expr_ext_cost_custom_hess_e
)
add the inequality constraints contribution to the Hessian (can be turned off via
exact_hess_constr
)
call the regularization module (
regularize
, seeregularize_method
)
Dense QP solution: Populating dense_qp_out
#
After solving a dense QP, the solution should be stored in the dense_qp_out
structure that is passed as an argument to the function dense_qp_XXX
(where XXX
is the name of the solver).
This structure has to be populated with three things:
the primal solution,
the dual solution,
constraint slacks,
which corresponds to the fields v
, lam
, and t
, respectively, in the dense_qp_out
structure.
If there are, in addition, equality constraint their dual variables should be added to the field pi
.
Primal and soft slack variables#
The field v
should be populated with variables in the following order:
primal, lower soft slack, upper soft slack
with the corresponding dimensions nv
,ns
,ns
.
Dual variables#
The field lam
should be populated with dual variables corresponding to bounds in the following order:
lower bounds, lower general, upper bounds, upper general, lower soft slack, upper soft slack
with the corresponding dimensions nb
,ng
,nb
,ng
,ns
,ns
.
The sign convention used is that all dual variables are nonnegative, even the ones that correspond to lower bounds.
Constraint slacks#
If v
has been set correctly, the constraint slack t
can be computed using the auxiliary function dense_qp_compute_t()
.
Adding tests#
In addition to specifying new tests using add_test()
to the interface/CMakeLists.txt
, please ensure that set_tests_properties()
is also used to force serial execution for tests contained in the same directory.