Developer Guide

This page contains additional information for people who want to extend acados.

Contributions

are handled via Pull Requests (PR) 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 of bstructs, e.g.

    mem->bstructs = (void **) c_ptr;
    c_ptr += N*sizeof(void *);
  • Align to 8 bytes, since astruct might contain ints 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 in astruct

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().