dragonpilot beta3

date: 2023-07-26T22:20:36
commit: c6d842c412052be1985b63d683c63be9dcb2b0eb
This commit is contained in:
dragonpilot
2023-07-26 22:14:57 +08:00
parent 67c2c03b43
commit 1abc7d7daa
536 changed files with 437552 additions and 24400 deletions
@@ -0,0 +1,387 @@
/*
* Copyright 2019 Gianluca Frison, Dimitris Kouzoupis, Robin Verschueren,
* Andrea Zanelli, Niels van Duijkeren, Jonathan Frey, Tommaso Sartor,
* Branimir Novoselnik, Rien Quirynen, Rezart Qelibari, Dang Doan,
* Jonas Koenemann, Yutao Chen, Tobias Schöls, Jonas Schlagenhauf, Moritz Diehl
*
* This file is part of acados.
*
* The 2-Clause BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.;
*/
// standard
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// acados
#include "acados/utils/print.h"
#include "acados_c/ocp_nlp_interface.h"
#include "acados_solver_{{ model.name }}.h"
// mex
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
long long *l_ptr;
int status = 0;
// create solver
{{ model.name }}_solver_capsule *acados_ocp_capsule = {{ model.name }}_acados_create_capsule();
status = {{ model.name }}_acados_create(acados_ocp_capsule);
if (status)
{
mexPrintf("{{ model.name }}_acados_create() returned status %d.\n", status);
}
mexPrintf("{{ model.name }}_acados_create() -> success!\n");
// get pointers to nlp solver related objects
ocp_nlp_plan_t *nlp_plan = {{ model.name }}_acados_get_nlp_plan(acados_ocp_capsule);
ocp_nlp_config *nlp_config = {{ model.name }}_acados_get_nlp_config(acados_ocp_capsule);
ocp_nlp_dims *nlp_dims = {{ model.name }}_acados_get_nlp_dims(acados_ocp_capsule);
ocp_nlp_in *nlp_in = {{ model.name }}_acados_get_nlp_in(acados_ocp_capsule);
ocp_nlp_out *nlp_out = {{ model.name }}_acados_get_nlp_out(acados_ocp_capsule);
ocp_nlp_solver *nlp_solver = {{ model.name }}_acados_get_nlp_solver(acados_ocp_capsule);
void *nlp_opts = {{ model.name }}_acados_get_nlp_opts(acados_ocp_capsule);
// mexPrintf("acados: got pointer to objectes!\n");
// field names of output struct
#define FIELDS_OCP 9
#define FIELDS_EXT_FUN 25
#define MAX_FIELDS 25
char *fieldnames[MAX_FIELDS];
for (int i = 0; i < MAX_FIELDS; i++)
{
fieldnames[i] = (char*) mxMalloc(50);
}
memcpy(fieldnames[0],"config",sizeof("config"));
memcpy(fieldnames[1],"dims",sizeof("dims"));
memcpy(fieldnames[2],"opts",sizeof("opts"));
memcpy(fieldnames[3],"in",sizeof("in"));
memcpy(fieldnames[4],"out",sizeof("out"));
memcpy(fieldnames[5],"solver",sizeof("solver"));
memcpy(fieldnames[6],"sens_out",sizeof("sens_out"));
memcpy(fieldnames[7],"plan",sizeof("plan"));
memcpy(fieldnames[8],"capsule",sizeof("capsule"));
// create output struct - C_ocp
plhs[0] = mxCreateStructMatrix(1, 1, 9, (const char **) fieldnames);
// MEX: config, dims, opts, in, out, solver, sens_out, plan
// plan
mxArray *plan_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(plan_mat);
l_ptr[0] = (long long) nlp_plan;
mxSetField(plhs[0], 0, "plan", plan_mat);
// config
mxArray *config_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(config_mat);
l_ptr[0] = (long long) nlp_config;
mxSetField(plhs[0], 0, "config", config_mat);
// dims
mxArray *dims_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(dims_mat);
l_ptr[0] = (long long) nlp_dims;
mxSetField(plhs[0], 0, "dims", dims_mat);
// opts
mxArray *opts_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(opts_mat);
l_ptr[0] = (long long) nlp_opts;
mxSetField(plhs[0], 0, "opts", opts_mat);
// in
mxArray *in_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(in_mat);
l_ptr[0] = (long long) nlp_in;
mxSetField(plhs[0], 0, "in", in_mat);
// out
mxArray *out_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(out_mat);
l_ptr[0] = (long long) nlp_out;
mxSetField(plhs[0], 0, "out", out_mat);
// solver
mxArray *solver_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(solver_mat);
l_ptr[0] = (long long) nlp_solver;
mxSetField(plhs[0], 0, "solver", solver_mat);
// TODO: sens_out not actually implemented in templates..
// sens_out
mxArray *sens_out_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(sens_out_mat);
l_ptr[0] = (long long) 1;
mxSetField(plhs[0], 0, "sens_out", sens_out_mat);
// capsule
mxArray *capsule_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(capsule_mat);
l_ptr[0] = (long long) acados_ocp_capsule;
mxSetField(plhs[0], 0, "capsule", capsule_mat);
/* store external function pointers */
// dyn
memcpy(fieldnames[0],"expl_ode_fun",sizeof("expl_ode_fun"));
memcpy(fieldnames[1],"forw_vde",sizeof("forw_vde"));
memcpy(fieldnames[2],"hess_vde",sizeof("hess_vde"));
memcpy(fieldnames[3],"impl_dae_fun",sizeof("impl_dae_fun"));
memcpy(fieldnames[4],"impl_dae_fun_jac_x_xdot_z",sizeof("impl_dae_fun_jac_x_xdot_z"));
memcpy(fieldnames[5],"impl_dae_jac_x_xdot_u_z",sizeof("impl_dae_jac_x_xdot_u_z"));
memcpy(fieldnames[6],"impl_dae_hess",sizeof("impl_dae_hess"));
memcpy(fieldnames[7],"gnsf_phi_fun",sizeof("gnsf_phi_fun"));
memcpy(fieldnames[8],"gnsf_phi_fun_jac_y",sizeof("gnsf_phi_fun_jac_y"));
memcpy(fieldnames[9],"gnsf_phi_jac_y_uhat",sizeof("gnsf_phi_jac_y_uhat"));
memcpy(fieldnames[10],"gnsf_f_lo_jac_x1_x1dot_u_z",sizeof("gnsf_f_lo_jac_x1_x1dot_u_z"));
memcpy(fieldnames[11],"gnsf_get_matrices_fun",sizeof("gnsf_get_matrices_fun"));
memcpy(fieldnames[12],"disc_phi_fun",sizeof("disc_phi_fun"));
memcpy(fieldnames[13],"disc_phi_fun_jac",sizeof("disc_phi_fun_jac"));
memcpy(fieldnames[14],"disc_phi_fun_jac_hess",sizeof("disc_phi_fun_jac_hess"));
// cost
memcpy(fieldnames[15],"cost_y_fun",sizeof("cost_y_fun"));
memcpy(fieldnames[16],"cost_y_fun_jac_ut_xt",sizeof("cost_y_fun_jac_ut_xt"));
memcpy(fieldnames[17],"cost_y_hess",sizeof("cost_y_hess"));
memcpy(fieldnames[18],"ext_cost_fun",sizeof("ext_cost_fun"));
memcpy(fieldnames[19],"ext_cost_fun_jac",sizeof("ext_cost_fun_jac"));
memcpy(fieldnames[20],"ext_cost_fun_jac_hess",sizeof("ext_cost_fun_jac_hess"));
// constraints
memcpy(fieldnames[21],"phi_constraint",sizeof("phi_constraint"));
memcpy(fieldnames[22],"nl_constr_h_fun_jac",sizeof("nl_constr_h_fun_jac"));
memcpy(fieldnames[23],"nl_constr_h_fun",sizeof("nl_constr_h_fun"));
memcpy(fieldnames[24],"nl_constr_h_fun_jac_hess",sizeof("nl_constr_h_fun_jac_hess"));
// create output struct - C_ocp_ext_fun
plhs[1] = mxCreateStructMatrix(1, 1, FIELDS_EXT_FUN, (const char **) fieldnames);
for (int i = 0; i < FIELDS_EXT_FUN; i++)
{
mxFree( fieldnames[i] );
}
/* dynamics */
mxArray *expl_ode_fun_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
mxArray *forw_vde_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
mxArray *hess_vde_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
mxArray *impl_dae_fun_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
mxArray *impl_dae_fun_jac_x_xdot_z_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
mxArray *impl_dae_jac_x_xdot_u_z_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
mxArray *impl_dae_hess_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
mxArray *gnsf_phi_fun_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
mxArray *gnsf_phi_fun_jac_y_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
mxArray *gnsf_phi_jac_y_uhat_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
mxArray *gnsf_f_lo_jac_x1_x1dot_u_z_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
mxArray *gnsf_get_matrices_fun_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
mxArray *disc_phi_fun_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
mxArray *disc_phi_fun_jac_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
mxArray *disc_phi_fun_jac_hess_mat = mxCreateNumericMatrix(1, 1, mxINT64_CLASS, mxREAL);
{% if solver_options.integrator_type == "ERK" %}
{# TODO: remove _casadi from these names.. #}
l_ptr = mxGetData(forw_vde_mat);
l_ptr[0] = (long long) acados_ocp_capsule->forw_vde_casadi;
l_ptr = mxGetData(expl_ode_fun_mat);
l_ptr[0] = (long long) acados_ocp_capsule->expl_ode_fun;
{% if solver_options.hessian_approx == "EXACT" %}
l_ptr = mxGetData(hess_vde_mat);
l_ptr[0] = (long long) acados_ocp_capsule->hess_vde_casadi;
{%- endif %}
{% elif solver_options.integrator_type == "IRK" %}
l_ptr = mxGetData(impl_dae_fun_mat);
l_ptr[0] = (long long) acados_ocp_capsule->impl_dae_fun;
l_ptr = mxGetData(impl_dae_fun_jac_x_xdot_z_mat);
l_ptr[0] = (long long) acados_ocp_capsule->impl_dae_fun_jac_x_xdot_z;
l_ptr = mxGetData(impl_dae_jac_x_xdot_u_z_mat);
l_ptr[0] = (long long) acados_ocp_capsule->impl_dae_jac_x_xdot_u_z;
{% if solver_options.hessian_approx == "EXACT" %}
l_ptr = mxGetData(impl_dae_hess_mat);
l_ptr[0] = (long long) acados_ocp_capsule->impl_dae_hess;
{%- endif %}
{% elif solver_options.integrator_type == "GNSF" %}
{% if model.gnsf.purely_linear != 1 %}
l_ptr = mxGetData(gnsf_phi_fun_mat);
l_ptr[0] = (long long) acados_ocp_capsule->gnsf_phi_fun;
l_ptr = mxGetData(gnsf_phi_fun_jac_y_mat);
l_ptr[0] = (long long) acados_ocp_capsule->gnsf_phi_fun_jac_y;
l_ptr = mxGetData(gnsf_phi_jac_y_uhat_mat);
l_ptr[0] = (long long) acados_ocp_capsule->gnsf_phi_jac_y_uhat;
{% if model.gnsf.nontrivial_f_LO == 1 %}
l_ptr = mxGetData(gnsf_f_lo_jac_x1_x1dot_u_z_mat);
l_ptr[0] = (long long) acados_ocp_capsule->gnsf_f_lo_jac_x1_x1dot_u_z;
{%- endif %}
{%- endif %}
l_ptr = mxGetData(gnsf_get_matrices_fun_mat);
l_ptr[0] = (long long) acados_ocp_capsule->gnsf_get_matrices_fun;
{% elif solver_options.integrator_type == "DISCRETE" %}
l_ptr = mxGetData(disc_phi_fun_mat);
l_ptr[0] = (long long) acados_ocp_capsule->discr_dyn_phi_fun;
l_ptr = mxGetData(disc_phi_fun_jac_mat);
l_ptr[0] = (long long) acados_ocp_capsule->discr_dyn_phi_fun_jac_ut_xt;
{% if solver_options.hessian_approx == "EXACT" %}
l_ptr = mxGetData(disc_phi_fun_jac_hess_mat);
l_ptr[0] = (long long) acados_ocp_capsule->discr_dyn_phi_fun_jac_ut_xt_hess;
{%- endif %}
{%- endif %}
mxSetField(plhs[1], 0, "expl_ode_fun", expl_ode_fun_mat);
mxSetField(plhs[1], 0, "forw_vde", forw_vde_mat);
mxSetField(plhs[1], 0, "hess_vde", hess_vde_mat);
mxSetField(plhs[1], 0, "gnsf_phi_fun", gnsf_phi_fun_mat);
mxSetField(plhs[1], 0, "gnsf_phi_fun_jac_y", gnsf_phi_fun_jac_y_mat);
mxSetField(plhs[1], 0, "gnsf_phi_jac_y_uhat", gnsf_phi_jac_y_uhat_mat);
mxSetField(plhs[1], 0, "gnsf_f_lo_jac_x1_x1dot_u_z", gnsf_f_lo_jac_x1_x1dot_u_z_mat);
mxSetField(plhs[1], 0, "gnsf_get_matrices_fun", gnsf_get_matrices_fun_mat);
mxSetField(plhs[1], 0, "impl_dae_fun", impl_dae_fun_mat);
mxSetField(plhs[1], 0, "impl_dae_fun_jac_x_xdot_z", impl_dae_fun_jac_x_xdot_z_mat);
mxSetField(plhs[1], 0, "impl_dae_jac_x_xdot_u_z", impl_dae_jac_x_xdot_u_z_mat);
mxSetField(plhs[1], 0, "impl_dae_hess", impl_dae_hess_mat);
mxSetField(plhs[1], 0, "disc_phi_fun", disc_phi_fun_mat);
mxSetField(plhs[1], 0, "disc_phi_fun_jac", disc_phi_fun_jac_mat);
mxSetField(plhs[1], 0, "disc_phi_fun_jac_hess", disc_phi_fun_jac_hess_mat);
/* constaints */
mxArray *phi_constraint_mat = mxCreateNumericMatrix(1, 2, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(phi_constraint_mat);
{%- if constraints.constr_type == "BGP" %}
l_ptr[0] = (long long) acados_ocp_capsule->phi_constraint;
{% endif %}
{% if constraints.constr_type_e == "BGP" %}
l_ptr[1] = (long long) &acados_ocp_capsule->phi_e_constraint;
{% endif %}
mxSetField(plhs[1], 0, "phi_constraint", phi_constraint_mat);
mxArray *nl_constr_h_fun_jac_mat = mxCreateNumericMatrix(1, 2, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(nl_constr_h_fun_jac_mat);
{% if constraints.constr_type == "BGH" and dims.nh > 0 %}
l_ptr[0] = (long long) acados_ocp_capsule->nl_constr_h_fun_jac;
{% endif %}
{% if constraints.constr_type_e == "BGH" and dims.nh_e > 0 %}
l_ptr[1] = (long long) &acados_ocp_capsule->nl_constr_h_e_fun_jac;
{%- endif %}
mxSetField(plhs[1], 0, "nl_constr_h_fun_jac", nl_constr_h_fun_jac_mat);
mxArray *nl_constr_h_fun_mat = mxCreateNumericMatrix(1, 2, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(nl_constr_h_fun_mat);
{% if constraints.constr_type == "BGH" and dims.nh > 0 %}
l_ptr[0] = (long long) acados_ocp_capsule->nl_constr_h_fun;
{% endif %}
{% if constraints.constr_type_e == "BGH" and dims.nh_e > 0 %}
l_ptr[1] = (long long) &acados_ocp_capsule->nl_constr_h_e_fun;
{%- endif %}
mxSetField(plhs[1], 0, "nl_constr_h_fun", nl_constr_h_fun_mat);
mxArray *nl_constr_h_fun_jac_hess_mat = mxCreateNumericMatrix(1, 2, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(nl_constr_h_fun_jac_hess_mat);
{% if constraints.constr_type == "BGH" and dims.nh > 0 and solver_options.hessian_approx == "EXACT" %}
l_ptr[0] = (long long) acados_ocp_capsule->nl_constr_h_fun_jac_hess;
{% endif %}
{% if constraints.constr_type_e == "BGH" and dims.nh_e > 0 and solver_options.hessian_approx == "EXACT" %}
l_ptr[1] = (long long) &acados_ocp_capsule->nl_constr_h_e_fun_jac_hess;
{%- endif %}
mxSetField(plhs[1], 0, "nl_constr_h_fun_jac_hess", nl_constr_h_fun_jac_hess_mat);
/* cost */
mxArray *cost_y_fun_mat = mxCreateNumericMatrix(1, 2, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(cost_y_fun_mat);
{% if cost.cost_type == "NONLINEAR_LS" %}
l_ptr[0] = (long long) acados_ocp_capsule->cost_y_fun;
{% endif %}
{% if cost.cost_type_e == "NONLINEAR_LS" %}
l_ptr[1] = (long long) &acados_ocp_capsule->cost_y_e_fun;
{%- endif %}
mxSetField(plhs[1], 0, "cost_y_fun", cost_y_fun_mat);
mxArray *cost_y_fun_jac_ut_xt_mat = mxCreateNumericMatrix(1, 2, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(cost_y_fun_jac_ut_xt_mat);
{% if cost.cost_type == "NONLINEAR_LS" %}
l_ptr[0] = (long long) acados_ocp_capsule->cost_y_fun_jac_ut_xt;
{% endif %}
{% if cost.cost_type_e == "NONLINEAR_LS" %}
l_ptr[1] = (long long) &acados_ocp_capsule->cost_y_e_fun_jac_ut_xt;
{%- endif %}
mxSetField(plhs[1], 0, "cost_y_fun_jac_ut_xt", cost_y_fun_jac_ut_xt_mat);
mxArray *cost_y_hess_mat = mxCreateNumericMatrix(1, 2, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(cost_y_hess_mat);
{% if cost.cost_type == "NONLINEAR_LS" %}
l_ptr[0] = (long long) acados_ocp_capsule->cost_y_hess;
{% endif %}
{% if cost.cost_type_e == "NONLINEAR_LS" %}
l_ptr[1] = (long long) &acados_ocp_capsule->cost_y_e_hess;
{%- endif %}
mxSetField(plhs[1], 0, "cost_y_hess", cost_y_hess_mat);
mxArray *ext_cost_fun_mat = mxCreateNumericMatrix(1, 2, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(ext_cost_fun_mat);
{% if cost.cost_type == "EXTERNAL" %}
l_ptr[0] = (long long) acados_ocp_capsule->ext_cost_fun;
{% endif -%}
{% if cost.cost_type_e == "EXTERNAL" %}
l_ptr[1] = (long long) &acados_ocp_capsule->ext_cost_e_fun;
{%- endif %}
mxSetField(plhs[1], 0, "ext_cost_fun", ext_cost_fun_mat);
mxArray *ext_cost_fun_jac_mat = mxCreateNumericMatrix(1, 2, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(ext_cost_fun_jac_mat);
{% if cost.cost_type == "EXTERNAL" %}
l_ptr[0] = (long long) acados_ocp_capsule->ext_cost_fun_jac;
{% endif -%}
{% if cost.cost_type_e == "EXTERNAL" %}
l_ptr[1] = (long long) &acados_ocp_capsule->ext_cost_e_fun_jac;
{%- endif %}
mxSetField(plhs[1], 0, "ext_cost_fun_jac", ext_cost_fun_jac_mat);
mxArray *ext_cost_fun_jac_hess_mat = mxCreateNumericMatrix(1, 2, mxINT64_CLASS, mxREAL);
l_ptr = mxGetData(ext_cost_fun_jac_hess_mat);
{% if cost.cost_type == "EXTERNAL" %}
l_ptr[0] = (long long) acados_ocp_capsule->ext_cost_fun_jac_hess;
{% endif -%}
{% if cost.cost_type_e == "EXTERNAL" %}
l_ptr[1] = (long long) &acados_ocp_capsule->ext_cost_e_fun_jac_hess;
{%- endif %}
mxSetField(plhs[1], 0, "ext_cost_fun_jac_hess", ext_cost_fun_jac_hess_mat);
return;
}
@@ -0,0 +1,70 @@
/*
* Copyright 2019 Gianluca Frison, Dimitris Kouzoupis, Robin Verschueren,
* Andrea Zanelli, Niels van Duijkeren, Jonathan Frey, Tommaso Sartor,
* Branimir Novoselnik, Rien Quirynen, Rezart Qelibari, Dang Doan,
* Jonas Koenemann, Yutao Chen, Tobias Schöls, Jonas Schlagenhauf, Moritz Diehl
*
* This file is part of acados.
*
* The 2-Clause BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.;
*/
// system
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// acados
#include "acados_solver_{{ model.name }}.h"
// mex
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int status = 0;
long long *ptr;
// mexPrintf("\nin mex_acados_free\n");
const mxArray *C_ocp = prhs[0];
// capsule
ptr = (long long *) mxGetData( mxGetField( C_ocp, 0, "capsule" ) );
{{ model.name }}_solver_capsule *capsule = ({{ model.name }}_solver_capsule *) ptr[0];
status = {{ model.name }}_acados_free(capsule);
if (status)
{
mexPrintf("{{ model.name }}_acados_free() returned status %d.\n", status);
}
status = {{ model.name }}_acados_free_capsule(capsule);
if (status)
{
mexPrintf("{{ model.name }}_acados_free_capsule() returned status %d.\n", status);
}
return;
}
@@ -0,0 +1,570 @@
/*
* Copyright 2019 Gianluca Frison, Dimitris Kouzoupis, Robin Verschueren,
* Andrea Zanelli, Niels van Duijkeren, Jonathan Frey, Tommaso Sartor,
* Branimir Novoselnik, Rien Quirynen, Rezart Qelibari, Dang Doan,
* Jonas Koenemann, Yutao Chen, Tobias Schöls, Jonas Schlagenhauf, Moritz Diehl
*
* This file is part of acados.
*
* The 2-Clause BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.;
*/
// standard
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// acados
#include "acados/utils/print.h"
#include "acados_c/ocp_nlp_interface.h"
#include "acados_solver_{{ model.name }}.h"
// mex
#include "mex.h"
#include "mex_macros.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
long long *ptr;
int acados_size;
mxArray *mex_field;
char fun_name[20] = "ocp_set";
char buffer [500]; // for error messages
/* RHS */
int min_nrhs = 6;
char *ext_fun_type = mxArrayToString( prhs[0] );
char *ext_fun_type_e = mxArrayToString( prhs[1] );
// C ocp
const mxArray *C_ocp = prhs[2];
// capsule
ptr = (long long *) mxGetData( mxGetField( C_ocp, 0, "capsule" ) );
{{ model.name }}_solver_capsule *capsule = ({{ model.name }}_solver_capsule *) ptr[0];
// plan
ptr = (long long *) mxGetData( mxGetField( C_ocp, 0, "plan" ) );
ocp_nlp_plan_t *plan = (ocp_nlp_plan_t *) ptr[0];
// config
ptr = (long long *) mxGetData( mxGetField( C_ocp, 0, "config" ) );
ocp_nlp_config *config = (ocp_nlp_config *) ptr[0];
// dims
ptr = (long long *) mxGetData( mxGetField( C_ocp, 0, "dims" ) );
ocp_nlp_dims *dims = (ocp_nlp_dims *) ptr[0];
// opts
ptr = (long long *) mxGetData( mxGetField( C_ocp, 0, "opts" ) );
void *opts = (void *) ptr[0];
// in
ptr = (long long *) mxGetData( mxGetField( C_ocp, 0, "in" ) );
ocp_nlp_in *in = (ocp_nlp_in *) ptr[0];
// out
ptr = (long long *) mxGetData( mxGetField( C_ocp, 0, "out" ) );
ocp_nlp_out *out = (ocp_nlp_out *) ptr[0];
// solver
ptr = (long long *) mxGetData( mxGetField( C_ocp, 0, "solver" ) );
ocp_nlp_solver *solver = (ocp_nlp_solver *) ptr[0];
const mxArray *C_ext_fun_pointers = prhs[3];
// field
char *field = mxArrayToString( prhs[4] );
// value
double *value = mxGetPr( prhs[5] );
// for checks
int matlab_size = (int) mxGetNumberOfElements( prhs[5] );
int nrow = (int) mxGetM( prhs[5] );
int ncol = (int) mxGetN( prhs[5] );
int N = dims->N;
int nu = dims->nu[0];
int nx = dims->nx[0];
// stage
int s0, se;
if (nrhs==min_nrhs)
{
s0 = 0;
se = N;
}
else if (nrhs==min_nrhs+1)
{
s0 = mxGetScalar( prhs[6] );
if (s0 > N)
{
sprintf(buffer, "ocp_set: N < specified stage = %d\n", s0);
mexErrMsgTxt(buffer);
}
se = s0 + 1;
}
else
{
sprintf(buffer, "ocp_set: wrong nrhs: %d\n", nrhs);
mexErrMsgTxt(buffer);
}
/* Set value */
// constraints
if (!strcmp(field, "constr_x0"))
{
acados_size = nx;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
ocp_nlp_constraints_model_set(config, dims, in, 0, "lbx", value);
ocp_nlp_constraints_model_set(config, dims, in, 0, "ubx", value);
}
else if (!strcmp(field, "constr_C"))
{
for (int ii=s0; ii<se; ii++)
{
int ng = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "ug");
MEX_DIM_CHECK_MAT(fun_name, "constr_C", nrow, ncol, ng, nx);
ocp_nlp_constraints_model_set(config, dims, in, ii, "C", value);
}
}
else if (!strcmp(field, "constr_lbx"))
{
for (int ii=s0; ii<se; ii++)
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "lbx");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
ocp_nlp_constraints_model_set(config, dims, in, ii, "lbx", value);
}
}
else if (!strcmp(field, "constr_ubx"))
{
for (int ii=s0; ii<se; ii++)
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "ubx");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
ocp_nlp_constraints_model_set(config, dims, in, ii, "ubx", value);
}
}
else if (!strcmp(field, "constr_lbu"))
{
for (int ii=s0; ii<se; ii++)
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "lbu");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
ocp_nlp_constraints_model_set(config, dims, in, ii, "lbu", value);
}
}
else if (!strcmp(field, "constr_ubu"))
{
for (int ii=s0; ii<se; ii++)
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "ubu");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
ocp_nlp_constraints_model_set(config, dims, in, ii, "ubu", value);
}
}
else if (!strcmp(field, "constr_D"))
{
for (int ii=s0; ii<se; ii++)
{
int ng = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "ug");
MEX_DIM_CHECK_MAT(fun_name, "constr_D", nrow, ncol, ng, nu);
ocp_nlp_constraints_model_set(config, dims, in, ii, "D", value);
}
}
else if (!strcmp(field, "constr_lg"))
{
for (int ii=s0; ii<se; ii++)
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "lg");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
ocp_nlp_constraints_model_set(config, dims, in, ii, "lg", value);
}
}
else if (!strcmp(field, "constr_ug"))
{
for (int ii=s0; ii<se; ii++)
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "ug");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
ocp_nlp_constraints_model_set(config, dims, in, ii, "ug", value);
}
}
else if (!strcmp(field, "constr_lh"))
{
for (int ii=s0; ii<se; ii++)
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "lh");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
ocp_nlp_constraints_model_set(config, dims, in, ii, "lh", value);
}
}
else if (!strcmp(field, "constr_uh"))
{
for (int ii=s0; ii<se; ii++)
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "uh");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
ocp_nlp_constraints_model_set(config, dims, in, ii, "uh", value);
}
}
// cost:
else if (!strcmp(field, "cost_y_ref"))
{
for (int ii=s0; ii<se; ii++)
{
if ((plan->nlp_cost[ii] == LINEAR_LS) || (plan->nlp_cost[ii] == NONLINEAR_LS))
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "y_ref");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
ocp_nlp_cost_model_set(config, dims, in, ii, "y_ref", value);
}
else
{
MEX_FIELD_NOT_SUPPORTED_FOR_COST_STAGE(fun_name, field, plan->nlp_cost[ii], ii);
}
}
}
else if (!strcmp(field, "cost_y_ref_e"))
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, N, "y_ref");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
ocp_nlp_cost_model_set(config, dims, in, N, "y_ref", value);
}
else if (!strcmp(field, "cost_Vu"))
{
for (int ii=s0; ii<se; ii++)
{
if ((plan->nlp_cost[ii] == LINEAR_LS) || (plan->nlp_cost[ii] == NONLINEAR_LS))
{
int ny = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "y_ref");
int nu = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "u");
acados_size = ny * nu;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
ocp_nlp_cost_model_set(config, dims, in, ii, "Vu", value);
}
else
{
MEX_FIELD_NOT_SUPPORTED_FOR_COST_STAGE(fun_name, field, plan->nlp_cost[ii], ii);
}
}
}
else if (!strcmp(field, "cost_Vx"))
{
for (int ii=s0; ii<se; ii++)
{
if ((plan->nlp_cost[ii] == LINEAR_LS) || (plan->nlp_cost[ii] == NONLINEAR_LS))
{
int ny = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "y_ref");
int nx = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "x");
acados_size = ny * nx;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
ocp_nlp_cost_model_set(config, dims, in, ii, "Vx", value);
}
else
{
MEX_FIELD_NOT_SUPPORTED_FOR_COST_STAGE(fun_name, field, plan->nlp_cost[ii], ii);
}
}
}
else if (!strcmp(field, "cost_W"))
{
for (int ii=s0; ii<se; ii++)
{
if ((plan->nlp_cost[ii] == LINEAR_LS) || (plan->nlp_cost[ii] == NONLINEAR_LS))
{
int ny = ocp_nlp_dims_get_from_attr(config, dims, out, s0, "y_ref");
acados_size = ny * ny;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
ocp_nlp_cost_model_set(config, dims, in, ii, "W", value);
}
else
{
MEX_FIELD_NOT_SUPPORTED_FOR_COST_STAGE(fun_name, field, plan->nlp_cost[ii], ii);
}
}
}
else if (!strcmp(field, "cost_Z"))
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, s0, "cost_Z");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
for (int ii=s0; ii<se; ii++)
{
ocp_nlp_cost_model_set(config, dims, in, ii, "Z", value);
}
}
else if (!strcmp(field, "cost_Zl"))
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, s0, "Zl");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
for (int ii=s0; ii<se; ii++)
{
ocp_nlp_cost_model_set(config, dims, in, ii, "Zl", value);
}
}
else if (!strcmp(field, "cost_Zu"))
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, s0, "Zu");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
for (int ii=s0; ii<se; ii++)
{
ocp_nlp_cost_model_set(config, dims, in, ii, "Zu", value);
}
}
else if (!strcmp(field, "cost_z"))
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, s0, "cost_z");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
for (int ii=s0; ii<se; ii++)
{
ocp_nlp_cost_model_set(config, dims, in, ii, "z", value);
}
}
else if (!strcmp(field, "cost_zl"))
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, s0, "zl");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
for (int ii=s0; ii<se; ii++)
{
ocp_nlp_cost_model_set(config, dims, in, ii, "zl", value);
}
}
else if (!strcmp(field, "cost_zu"))
{
acados_size = ocp_nlp_dims_get_from_attr(config, dims, out, s0, "zu");
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
for (int ii=s0; ii<se; ii++)
{
ocp_nlp_cost_model_set(config, dims, in, ii, "zu", value);
}
}
// constraints TODO
// // NOTE(oj): how is it with Jbx, Jbu, idxb can they be changed?!
// else if (!strcmp(field, "constr_lbx"))
// {
// // bounds at 0 are a special case.
// if (s0==0)
// {
// sprintf(buffer, "%s cannot set %s for stage 0", fun_name, field);
// mexErrMsgTxt(buffer);
// }
// }
// initializations
else if (!strcmp(field, "init_x"))
{
if (nrhs!=min_nrhs)
MEX_SETTER_NO_STAGE_SUPPORT(fun_name, field)
acados_size = (N+1) * nx;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
for (int ii=0; ii<=N; ii++)
{
ocp_nlp_out_set(config, dims, out, ii, "x", value+ii*nx);
}
}
else if (!strcmp(field, "init_u"))
{
if (nrhs!=min_nrhs)
MEX_SETTER_NO_STAGE_SUPPORT(fun_name, field)
acados_size = N*nu;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
for (int ii=0; ii<N; ii++)
{
ocp_nlp_out_set(config, dims, out, ii, "u", value+ii*nu);
}
}
else if (!strcmp(field, "init_z"))
{
sim_solver_plan_t sim_plan = plan->sim_solver_plan[0];
sim_solver_t type = sim_plan.sim_solver;
if (type == IRK)
{
int nz = ocp_nlp_dims_get_from_attr(config, dims, out, 0, "z");
if (nrhs!=min_nrhs)
MEX_SETTER_NO_STAGE_SUPPORT(fun_name, field)
acados_size = N*nz;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
for (int ii=0; ii<N; ii++)
{
ocp_nlp_set(config, solver, ii, "z_guess", value+ii*nz);
}
}
else
{
MEX_FIELD_ONLY_SUPPORTED_FOR_SOLVER(fun_name, "init_z", "irk")
}
}
else if (!strcmp(field, "init_xdot"))
{
sim_solver_plan_t sim_plan = plan->sim_solver_plan[0];
sim_solver_t type = sim_plan.sim_solver;
if (type == IRK)
{
int nx = ocp_nlp_dims_get_from_attr(config, dims, out, 0, "x");
if (nrhs!=min_nrhs)
MEX_SETTER_NO_STAGE_SUPPORT(fun_name, field)
acados_size = N*nx;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
for (int ii=0; ii<N; ii++)
{
ocp_nlp_set(config, solver, ii, "xdot_guess", value+ii*nx);
}
}
else
{
MEX_FIELD_ONLY_SUPPORTED_FOR_SOLVER(fun_name, "init_z", "irk")
}
}
else if (!strcmp(field, "init_gnsf_phi"))
{
sim_solver_plan_t sim_plan = plan->sim_solver_plan[0];
sim_solver_t type = sim_plan.sim_solver;
if (type == GNSF)
{
int nout = ocp_nlp_dims_get_from_attr(config, dims, out, 0, "init_gnsf_phi");
if (nrhs!=min_nrhs)
MEX_SETTER_NO_STAGE_SUPPORT(fun_name, field)
acados_size = N*nout;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
for (int ii=0; ii<N; ii++)
{
ocp_nlp_set(config, solver, ii, "gnsf_phi_guess", value+ii*nx);
}
}
else
{
MEX_FIELD_ONLY_SUPPORTED_FOR_SOLVER(fun_name, "init_gnsf_phi", "irk_gnsf")
}
}
else if (!strcmp(field, "init_pi"))
{
if (nrhs!=min_nrhs)
MEX_SETTER_NO_STAGE_SUPPORT(fun_name, field)
acados_size = N*nx;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
for (int ii=0; ii<N; ii++)
{
ocp_nlp_out_set(config, dims, out, ii, "pi", value+ii*nx);
}
}
else if (!strcmp(field, "init_lam"))
{
for (int ii=s0; ii<se; ii++)
{
int nlam = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "lam");
MEX_DIM_CHECK_VEC(fun_name, "lam", nrow*ncol, nlam);
ocp_nlp_out_set(config, dims, out, ii, "lam", value);
}
}
else if (!strcmp(field, "init_t"))
{
for (int ii=s0; ii<se; ii++)
{
int nt = ocp_nlp_dims_get_from_attr(config, dims, out, ii, "t");
MEX_DIM_CHECK_VEC(fun_name, "t", nrow*ncol, nt);
ocp_nlp_out_set(config, dims, out, ii, "t", value);
}
}
else if (!strcmp(field, "p"))
{
if (nrhs==min_nrhs) // all stages
{
for (int ii=0; ii<=N; ii++)
{
{{ model.name }}_acados_update_params(capsule, ii, value, matlab_size);
}
}
else if (nrhs==min_nrhs+1) // one stage
{
int stage = mxGetScalar( prhs[6] );
{{ model.name }}_acados_update_params(capsule, stage, value, matlab_size);
}
}
else if (!strcmp(field, "nlp_solver_max_iter"))
{
acados_size = 1;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
int nlp_solver_max_iter = (int) value[0];
ocp_nlp_solver_opts_set(config, opts, "max_iter", &nlp_solver_max_iter);
}
else if (!strcmp(field, "rti_phase"))
{
acados_size = 1;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
int rti_phase = (int) value[0];
if (plan->nlp_solver == SQP && rti_phase != 0)
{
MEX_FIELD_ONLY_SUPPORTED_FOR_SOLVER(fun_name, field, "sqp_rti")
}
ocp_nlp_solver_opts_set(config, opts, "rti_phase", &rti_phase);
}
else if (!strcmp(field, "qp_warm_start"))
{
acados_size = 1;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
int qp_warm_start = (int) value[0];
ocp_nlp_solver_opts_set(config, opts, "qp_warm_start", &qp_warm_start);
}
else if (!strcmp(field, "warm_start_first_qp"))
{
acados_size = 1;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
int warm_start_first_qp = (int) value[0];
ocp_nlp_solver_opts_set(config, opts, "warm_start_first_qp", &warm_start_first_qp);
}
else if (!strcmp(field, "print_level"))
{
acados_size = 1;
MEX_DIM_CHECK_VEC(fun_name, field, matlab_size, acados_size);
int print_level = (int) value[0];
ocp_nlp_solver_opts_set(config, opts, "print_level", &print_level);
}
else
{
MEX_FIELD_NOT_SUPPORTED_SUGGEST(fun_name, field, "p, constr_x0,\
constr_lbx, constr_ubx, constr_C, constr_D, constr_lg, constr_ug, constr_lh, constr_uh\
constr_lbu, constr_ubu, cost_y_ref[_e],\
cost_Vu, cost_Vx, cost_Vz, cost_W, cost_Z, cost_Zl, cost_Zu, cost_z,\
cost_zl, cost_zu, init_x, init_u, init_z, init_xdot, init_gnsf_phi,\
init_pi, nlp_solver_max_iter, qp_warm_start, warm_start_first_qp, print_level");
}
return;
}
@@ -0,0 +1,59 @@
/*
* Copyright 2019 Gianluca Frison, Dimitris Kouzoupis, Robin Verschueren,
* Andrea Zanelli, Niels van Duijkeren, Jonathan Frey, Tommaso Sartor,
* Branimir Novoselnik, Rien Quirynen, Rezart Qelibari, Dang Doan,
* Jonas Koenemann, Yutao Chen, Tobias Schöls, Jonas Schlagenhauf, Moritz Diehl
*
* This file is part of acados.
*
* The 2-Clause BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.;
*/
// system
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// acados
#include "acados_solver_{{ model.name }}.h"
// mex
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
// C_ocp
long long *ptr;
const mxArray *C_ocp = prhs[0];
// capsule
ptr = (long long *) mxGetData( mxGetField( C_ocp, 0, "capsule" ) );
{{ model.name }}_solver_capsule *capsule = ({{ model.name }}_solver_capsule *) ptr[0];
// solve
{{ model.name }}_acados_solve(capsule);
}
@@ -0,0 +1,508 @@
/*
* Copyright 2019 Gianluca Frison, Dimitris Kouzoupis, Robin Verschueren,
* Andrea Zanelli, Niels van Duijkeren, Jonathan Frey, Tommaso Sartor,
* Branimir Novoselnik, Rien Quirynen, Rezart Qelibari, Dang Doan,
* Jonas Koenemann, Yutao Chen, Tobias Schöls, Jonas Schlagenhauf, Moritz Diehl
*
* This file is part of acados.
*
* The 2-Clause BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.;
*/
{%- if solver_options.hessian_approx %}
{%- set hessian_approx = solver_options.hessian_approx %}
{%- elif solver_options.sens_hess %}
{%- set hessian_approx = "EXACT" %}
{%- else %}
{%- set hessian_approx = "GAUSS_NEWTON" %}
{%- endif %}
// standard
#include <stdio.h>
#include <stdlib.h>
// acados
#include "acados_c/external_function_interface.h"
#include "acados_c/sim_interface.h"
#include "acados_c/external_function_interface.h"
#include "acados/sim/sim_common.h"
#include "acados/utils/external_function_generic.h"
#include "acados/utils/print.h"
// example specific
#include "{{ model.name }}_model/{{ model.name }}_model.h"
#include "acados_sim_solver_{{ model.name }}.h"
// ** solver data **
sim_solver_capsule * {{ model.name }}_acados_sim_solver_create_capsule()
{
void* capsule_mem = malloc(sizeof(sim_solver_capsule));
sim_solver_capsule *capsule = (sim_solver_capsule *) capsule_mem;
return capsule;
}
int {{ model.name }}_acados_sim_solver_free_capsule(sim_solver_capsule * capsule)
{
free(capsule);
return 0;
}
int {{ model.name }}_acados_sim_create(sim_solver_capsule * capsule)
{
// initialize
const int nx = {{ model.name | upper }}_NX;
const int nu = {{ model.name | upper }}_NU;
const int nz = {{ model.name | upper }}_NZ;
const int np = {{ model.name | upper }}_NP;
bool tmp_bool;
{#// double Tsim = {{ solver_options.tf / dims.N }};#}
double Tsim = {{ solver_options.Tsim }};
{% if solver_options.integrator_type == "IRK" %}
capsule->sim_impl_dae_fun = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
capsule->sim_impl_dae_fun_jac_x_xdot_z = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
capsule->sim_impl_dae_jac_x_xdot_u_z = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
// external functions (implicit model)
capsule->sim_impl_dae_fun->casadi_fun = &{{ model.name }}_impl_dae_fun;
capsule->sim_impl_dae_fun->casadi_work = &{{ model.name }}_impl_dae_fun_work;
capsule->sim_impl_dae_fun->casadi_sparsity_in = &{{ model.name }}_impl_dae_fun_sparsity_in;
capsule->sim_impl_dae_fun->casadi_sparsity_out = &{{ model.name }}_impl_dae_fun_sparsity_out;
capsule->sim_impl_dae_fun->casadi_n_in = &{{ model.name }}_impl_dae_fun_n_in;
capsule->sim_impl_dae_fun->casadi_n_out = &{{ model.name }}_impl_dae_fun_n_out;
external_function_param_casadi_create(capsule->sim_impl_dae_fun, np);
capsule->sim_impl_dae_fun_jac_x_xdot_z->casadi_fun = &{{ model.name }}_impl_dae_fun_jac_x_xdot_z;
capsule->sim_impl_dae_fun_jac_x_xdot_z->casadi_work = &{{ model.name }}_impl_dae_fun_jac_x_xdot_z_work;
capsule->sim_impl_dae_fun_jac_x_xdot_z->casadi_sparsity_in = &{{ model.name }}_impl_dae_fun_jac_x_xdot_z_sparsity_in;
capsule->sim_impl_dae_fun_jac_x_xdot_z->casadi_sparsity_out = &{{ model.name }}_impl_dae_fun_jac_x_xdot_z_sparsity_out;
capsule->sim_impl_dae_fun_jac_x_xdot_z->casadi_n_in = &{{ model.name }}_impl_dae_fun_jac_x_xdot_z_n_in;
capsule->sim_impl_dae_fun_jac_x_xdot_z->casadi_n_out = &{{ model.name }}_impl_dae_fun_jac_x_xdot_z_n_out;
external_function_param_casadi_create(capsule->sim_impl_dae_fun_jac_x_xdot_z, np);
// external_function_param_casadi impl_dae_jac_x_xdot_u_z;
capsule->sim_impl_dae_jac_x_xdot_u_z->casadi_fun = &{{ model.name }}_impl_dae_jac_x_xdot_u_z;
capsule->sim_impl_dae_jac_x_xdot_u_z->casadi_work = &{{ model.name }}_impl_dae_jac_x_xdot_u_z_work;
capsule->sim_impl_dae_jac_x_xdot_u_z->casadi_sparsity_in = &{{ model.name }}_impl_dae_jac_x_xdot_u_z_sparsity_in;
capsule->sim_impl_dae_jac_x_xdot_u_z->casadi_sparsity_out = &{{ model.name }}_impl_dae_jac_x_xdot_u_z_sparsity_out;
capsule->sim_impl_dae_jac_x_xdot_u_z->casadi_n_in = &{{ model.name }}_impl_dae_jac_x_xdot_u_z_n_in;
capsule->sim_impl_dae_jac_x_xdot_u_z->casadi_n_out = &{{ model.name }}_impl_dae_jac_x_xdot_u_z_n_out;
external_function_param_casadi_create(capsule->sim_impl_dae_jac_x_xdot_u_z, np);
{%- if hessian_approx == "EXACT" %}
capsule->sim_impl_dae_hess = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
// external_function_param_casadi impl_dae_jac_x_xdot_u_z;
capsule->sim_impl_dae_hess->casadi_fun = &{{ model.name }}_impl_dae_hess;
capsule->sim_impl_dae_hess->casadi_work = &{{ model.name }}_impl_dae_hess_work;
capsule->sim_impl_dae_hess->casadi_sparsity_in = &{{ model.name }}_impl_dae_hess_sparsity_in;
capsule->sim_impl_dae_hess->casadi_sparsity_out = &{{ model.name }}_impl_dae_hess_sparsity_out;
capsule->sim_impl_dae_hess->casadi_n_in = &{{ model.name }}_impl_dae_hess_n_in;
capsule->sim_impl_dae_hess->casadi_n_out = &{{ model.name }}_impl_dae_hess_n_out;
external_function_param_casadi_create(capsule->sim_impl_dae_hess, np);
{%- endif %}
{% elif solver_options.integrator_type == "ERK" %}
// explicit ode
capsule->sim_forw_vde_casadi = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
capsule->sim_expl_ode_fun_casadi = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
capsule->sim_forw_vde_casadi->casadi_fun = &{{ model.name }}_expl_vde_forw;
capsule->sim_forw_vde_casadi->casadi_n_in = &{{ model.name }}_expl_vde_forw_n_in;
capsule->sim_forw_vde_casadi->casadi_n_out = &{{ model.name }}_expl_vde_forw_n_out;
capsule->sim_forw_vde_casadi->casadi_sparsity_in = &{{ model.name }}_expl_vde_forw_sparsity_in;
capsule->sim_forw_vde_casadi->casadi_sparsity_out = &{{ model.name }}_expl_vde_forw_sparsity_out;
capsule->sim_forw_vde_casadi->casadi_work = &{{ model.name }}_expl_vde_forw_work;
external_function_param_casadi_create(capsule->sim_forw_vde_casadi, np);
capsule->sim_expl_ode_fun_casadi->casadi_fun = &{{ model.name }}_expl_ode_fun;
capsule->sim_expl_ode_fun_casadi->casadi_n_in = &{{ model.name }}_expl_ode_fun_n_in;
capsule->sim_expl_ode_fun_casadi->casadi_n_out = &{{ model.name }}_expl_ode_fun_n_out;
capsule->sim_expl_ode_fun_casadi->casadi_sparsity_in = &{{ model.name }}_expl_ode_fun_sparsity_in;
capsule->sim_expl_ode_fun_casadi->casadi_sparsity_out = &{{ model.name }}_expl_ode_fun_sparsity_out;
capsule->sim_expl_ode_fun_casadi->casadi_work = &{{ model.name }}_expl_ode_fun_work;
external_function_param_casadi_create(capsule->sim_expl_ode_fun_casadi, np);
{%- if hessian_approx == "EXACT" %}
capsule->sim_expl_ode_hess = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
// external_function_param_casadi impl_dae_jac_x_xdot_u_z;
capsule->sim_expl_ode_hess->casadi_fun = &{{ model.name }}_expl_ode_hess;
capsule->sim_expl_ode_hess->casadi_work = &{{ model.name }}_expl_ode_hess_work;
capsule->sim_expl_ode_hess->casadi_sparsity_in = &{{ model.name }}_expl_ode_hess_sparsity_in;
capsule->sim_expl_ode_hess->casadi_sparsity_out = &{{ model.name }}_expl_ode_hess_sparsity_out;
capsule->sim_expl_ode_hess->casadi_n_in = &{{ model.name }}_expl_ode_hess_n_in;
capsule->sim_expl_ode_hess->casadi_n_out = &{{ model.name }}_expl_ode_hess_n_out;
external_function_param_casadi_create(capsule->sim_expl_ode_hess, np);
{%- endif %}
{% elif solver_options.integrator_type == "GNSF" -%}
{% if model.gnsf.purely_linear != 1 %}
capsule->sim_gnsf_phi_fun = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
capsule->sim_gnsf_phi_fun_jac_y = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
capsule->sim_gnsf_phi_jac_y_uhat = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
{% if model.gnsf.nontrivial_f_LO == 1 %}
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
{%- endif %}
{%- endif %}
capsule->sim_gnsf_get_matrices_fun = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
{% if model.gnsf.purely_linear != 1 %}
capsule->sim_gnsf_phi_fun->casadi_fun = &{{ model.name }}_gnsf_phi_fun;
capsule->sim_gnsf_phi_fun->casadi_n_in = &{{ model.name }}_gnsf_phi_fun_n_in;
capsule->sim_gnsf_phi_fun->casadi_n_out = &{{ model.name }}_gnsf_phi_fun_n_out;
capsule->sim_gnsf_phi_fun->casadi_sparsity_in = &{{ model.name }}_gnsf_phi_fun_sparsity_in;
capsule->sim_gnsf_phi_fun->casadi_sparsity_out = &{{ model.name }}_gnsf_phi_fun_sparsity_out;
capsule->sim_gnsf_phi_fun->casadi_work = &{{ model.name }}_gnsf_phi_fun_work;
external_function_param_casadi_create(capsule->sim_gnsf_phi_fun, np);
capsule->sim_gnsf_phi_fun_jac_y->casadi_fun = &{{ model.name }}_gnsf_phi_fun_jac_y;
capsule->sim_gnsf_phi_fun_jac_y->casadi_n_in = &{{ model.name }}_gnsf_phi_fun_jac_y_n_in;
capsule->sim_gnsf_phi_fun_jac_y->casadi_n_out = &{{ model.name }}_gnsf_phi_fun_jac_y_n_out;
capsule->sim_gnsf_phi_fun_jac_y->casadi_sparsity_in = &{{ model.name }}_gnsf_phi_fun_jac_y_sparsity_in;
capsule->sim_gnsf_phi_fun_jac_y->casadi_sparsity_out = &{{ model.name }}_gnsf_phi_fun_jac_y_sparsity_out;
capsule->sim_gnsf_phi_fun_jac_y->casadi_work = &{{ model.name }}_gnsf_phi_fun_jac_y_work;
external_function_param_casadi_create(capsule->sim_gnsf_phi_fun_jac_y, np);
capsule->sim_gnsf_phi_jac_y_uhat->casadi_fun = &{{ model.name }}_gnsf_phi_jac_y_uhat;
capsule->sim_gnsf_phi_jac_y_uhat->casadi_n_in = &{{ model.name }}_gnsf_phi_jac_y_uhat_n_in;
capsule->sim_gnsf_phi_jac_y_uhat->casadi_n_out = &{{ model.name }}_gnsf_phi_jac_y_uhat_n_out;
capsule->sim_gnsf_phi_jac_y_uhat->casadi_sparsity_in = &{{ model.name }}_gnsf_phi_jac_y_uhat_sparsity_in;
capsule->sim_gnsf_phi_jac_y_uhat->casadi_sparsity_out = &{{ model.name }}_gnsf_phi_jac_y_uhat_sparsity_out;
capsule->sim_gnsf_phi_jac_y_uhat->casadi_work = &{{ model.name }}_gnsf_phi_jac_y_uhat_work;
external_function_param_casadi_create(capsule->sim_gnsf_phi_jac_y_uhat, np);
{% if model.gnsf.nontrivial_f_LO == 1 %}
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z->casadi_fun = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz;
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z->casadi_n_in = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_n_in;
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z->casadi_n_out = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_n_out;
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z->casadi_sparsity_in = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_sparsity_in;
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z->casadi_sparsity_out = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_sparsity_out;
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z->casadi_work = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_work;
external_function_param_casadi_create(capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z, np);
{%- endif %}
{%- endif %}
capsule->sim_gnsf_get_matrices_fun->casadi_fun = &{{ model.name }}_gnsf_get_matrices_fun;
capsule->sim_gnsf_get_matrices_fun->casadi_n_in = &{{ model.name }}_gnsf_get_matrices_fun_n_in;
capsule->sim_gnsf_get_matrices_fun->casadi_n_out = &{{ model.name }}_gnsf_get_matrices_fun_n_out;
capsule->sim_gnsf_get_matrices_fun->casadi_sparsity_in = &{{ model.name }}_gnsf_get_matrices_fun_sparsity_in;
capsule->sim_gnsf_get_matrices_fun->casadi_sparsity_out = &{{ model.name }}_gnsf_get_matrices_fun_sparsity_out;
capsule->sim_gnsf_get_matrices_fun->casadi_work = &{{ model.name }}_gnsf_get_matrices_fun_work;
external_function_param_casadi_create(capsule->sim_gnsf_get_matrices_fun, np);
{% endif %}
// sim plan & config
sim_solver_plan_t plan;
plan.sim_solver = {{ solver_options.integrator_type }};
// create correct config based on plan
sim_config * {{ model.name }}_sim_config = sim_config_create(plan);
capsule->acados_sim_config = {{ model.name }}_sim_config;
// sim dims
void *{{ model.name }}_sim_dims = sim_dims_create({{ model.name }}_sim_config);
capsule->acados_sim_dims = {{ model.name }}_sim_dims;
sim_dims_set({{ model.name }}_sim_config, {{ model.name }}_sim_dims, "nx", &nx);
sim_dims_set({{ model.name }}_sim_config, {{ model.name }}_sim_dims, "nu", &nu);
sim_dims_set({{ model.name }}_sim_config, {{ model.name }}_sim_dims, "nz", &nz);
{% if solver_options.integrator_type == "GNSF" %}
int gnsf_nx1 = {{ dims.gnsf_nx1 }};
int gnsf_nz1 = {{ dims.gnsf_nz1 }};
int gnsf_nout = {{ dims.gnsf_nout }};
int gnsf_ny = {{ dims.gnsf_ny }};
int gnsf_nuhat = {{ dims.gnsf_nuhat }};
sim_dims_set({{ model.name }}_sim_config, {{ model.name }}_sim_dims, "nx1", &gnsf_nx1);
sim_dims_set({{ model.name }}_sim_config, {{ model.name }}_sim_dims, "nz1", &gnsf_nz1);
sim_dims_set({{ model.name }}_sim_config, {{ model.name }}_sim_dims, "nout", &gnsf_nout);
sim_dims_set({{ model.name }}_sim_config, {{ model.name }}_sim_dims, "ny", &gnsf_ny);
sim_dims_set({{ model.name }}_sim_config, {{ model.name }}_sim_dims, "nuhat", &gnsf_nuhat);
{% endif %}
// sim opts
sim_opts *{{ model.name }}_sim_opts = sim_opts_create({{ model.name }}_sim_config, {{ model.name }}_sim_dims);
capsule->acados_sim_opts = {{ model.name }}_sim_opts;
int tmp_int = {{ solver_options.sim_method_newton_iter }};
sim_opts_set({{ model.name }}_sim_config, {{ model.name }}_sim_opts, "newton_iter", &tmp_int);
sim_collocation_type collocation_type = {{ solver_options.collocation_type }};
sim_opts_set({{ model.name }}_sim_config, {{ model.name }}_sim_opts, "collocation_type", &collocation_type);
{% if problem_class == "SIM" %}
tmp_int = {{ solver_options.sim_method_num_stages }};
sim_opts_set({{ model.name }}_sim_config, {{ model.name }}_sim_opts, "num_stages", &tmp_int);
tmp_int = {{ solver_options.sim_method_num_steps }};
sim_opts_set({{ model.name }}_sim_config, {{ model.name }}_sim_opts, "num_steps", &tmp_int);
// options that are not available to AcadosOcpSolver
// (in OCP they will be determined by other options, like exact_hessian)
tmp_bool = {{ solver_options.sens_forw }};
sim_opts_set({{ model.name }}_sim_config, {{ model.name }}_sim_opts, "sens_forw", &tmp_bool);
tmp_bool = {{ solver_options.sens_adj }};
sim_opts_set({{ model.name }}_sim_config, {{ model.name }}_sim_opts, "sens_adj", &tmp_bool);
tmp_bool = {{ solver_options.sens_algebraic }};
sim_opts_set({{ model.name }}_sim_config, {{ model.name }}_sim_opts, "sens_algebraic", &tmp_bool);
tmp_bool = {{ solver_options.sens_hess }};
sim_opts_set({{ model.name }}_sim_config, {{ model.name }}_sim_opts, "sens_hess", &tmp_bool);
tmp_bool = {{ solver_options.output_z }};
sim_opts_set({{ model.name }}_sim_config, {{ model.name }}_sim_opts, "output_z", &tmp_bool);
{% else %} {# num_stages and num_steps of first shooting interval are used #}
tmp_int = {{ solver_options.sim_method_num_stages[0] }};
sim_opts_set({{ model.name }}_sim_config, {{ model.name }}_sim_opts, "num_stages", &tmp_int);
tmp_int = {{ solver_options.sim_method_num_steps[0] }};
sim_opts_set({{ model.name }}_sim_config, {{ model.name }}_sim_opts, "num_steps", &tmp_int);
tmp_bool = {{ solver_options.sim_method_jac_reuse[0] }};
sim_opts_set({{ model.name }}_sim_config, {{ model.name }}_sim_opts, "jac_reuse", &tmp_bool);
{% endif %}
// sim in / out
sim_in *{{ model.name }}_sim_in = sim_in_create({{ model.name }}_sim_config, {{ model.name }}_sim_dims);
capsule->acados_sim_in = {{ model.name }}_sim_in;
sim_out *{{ model.name }}_sim_out = sim_out_create({{ model.name }}_sim_config, {{ model.name }}_sim_dims);
capsule->acados_sim_out = {{ model.name }}_sim_out;
sim_in_set({{ model.name }}_sim_config, {{ model.name }}_sim_dims,
{{ model.name }}_sim_in, "T", &Tsim);
// model functions
{%- if solver_options.integrator_type == "IRK" %}
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"impl_ode_fun", capsule->sim_impl_dae_fun);
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"impl_ode_fun_jac_x_xdot", capsule->sim_impl_dae_fun_jac_x_xdot_z);
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"impl_ode_jac_x_xdot_u", capsule->sim_impl_dae_jac_x_xdot_u_z);
{%- if hessian_approx == "EXACT" %}
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"impl_dae_hess", capsule->sim_impl_dae_hess);
{%- endif %}
{%- elif solver_options.integrator_type == "ERK" %}
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"expl_vde_for", capsule->sim_forw_vde_casadi);
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"expl_ode_fun", capsule->sim_expl_ode_fun_casadi);
{%- if hessian_approx == "EXACT" %}
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"expl_ode_hess", capsule->sim_expl_ode_hess);
{%- endif %}
{%- elif solver_options.integrator_type == "GNSF" %}
{% if model.gnsf.purely_linear != 1 %}
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"phi_fun", capsule->sim_gnsf_phi_fun);
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"phi_fun_jac_y", capsule->sim_gnsf_phi_fun_jac_y);
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"phi_jac_y_uhat", capsule->sim_gnsf_phi_jac_y_uhat);
{% if model.gnsf.nontrivial_f_LO == 1 %}
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"f_lo_jac_x1_x1dot_u_z", capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z);
{%- endif %}
{%- endif %}
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"gnsf_get_matrices_fun", capsule->sim_gnsf_get_matrices_fun);
{%- endif %}
// sim solver
sim_solver *{{ model.name }}_sim_solver = sim_solver_create({{ model.name }}_sim_config,
{{ model.name }}_sim_dims, {{ model.name }}_sim_opts);
capsule->acados_sim_solver = {{ model.name }}_sim_solver;
{% if dims.np > 0 %}
/* initialize parameter values */
double* p = calloc(np, sizeof(double));
{% for item in parameter_values %}
{%- if item != 0 %}
p[{{ loop.index0 }}] = {{ item }};
{%- endif %}
{%- endfor %}
{{ model.name }}_acados_sim_update_params(capsule, p, np);
free(p);
{% endif %}{# if dims.np #}
/* initialize input */
// x
double x0[{{ dims.nx }}];
for (int ii = 0; ii < {{ dims.nx }}; ii++)
x0[ii] = 0.0;
sim_in_set({{ model.name }}_sim_config, {{ model.name }}_sim_dims,
{{ model.name }}_sim_in, "x", x0);
// u
double u0[{{ dims.nu }}];
for (int ii = 0; ii < {{ dims.nu }}; ii++)
u0[ii] = 0.0;
sim_in_set({{ model.name }}_sim_config, {{ model.name }}_sim_dims,
{{ model.name }}_sim_in, "u", u0);
// S_forw
double S_forw[{{ dims.nx * (dims.nx + dims.nu) }}];
for (int ii = 0; ii < {{ dims.nx * (dims.nx + dims.nu) }}; ii++)
S_forw[ii] = 0.0;
for (int ii = 0; ii < {{ dims.nx }}; ii++)
S_forw[ii + ii * {{ dims.nx }} ] = 1.0;
sim_in_set({{ model.name }}_sim_config, {{ model.name }}_sim_dims,
{{ model.name }}_sim_in, "S_forw", S_forw);
int status = sim_precompute({{ model.name }}_sim_solver, {{ model.name }}_sim_in, {{ model.name }}_sim_out);
return status;
}
int {{ model.name }}_acados_sim_solve(sim_solver_capsule *capsule)
{
// integrate dynamics using acados sim_solver
int status = sim_solve(capsule->acados_sim_solver,
capsule->acados_sim_in, capsule->acados_sim_out);
if (status != 0)
printf("error in {{ model.name }}_acados_sim_solve()! Exiting.\n");
return status;
}
int {{ model.name }}_acados_sim_free(sim_solver_capsule *capsule)
{
// free memory
sim_solver_destroy(capsule->acados_sim_solver);
sim_in_destroy(capsule->acados_sim_in);
sim_out_destroy(capsule->acados_sim_out);
sim_opts_destroy(capsule->acados_sim_opts);
sim_dims_destroy(capsule->acados_sim_dims);
sim_config_destroy(capsule->acados_sim_config);
// free external function
{%- if solver_options.integrator_type == "IRK" %}
external_function_param_casadi_free(capsule->sim_impl_dae_fun);
external_function_param_casadi_free(capsule->sim_impl_dae_fun_jac_x_xdot_z);
external_function_param_casadi_free(capsule->sim_impl_dae_jac_x_xdot_u_z);
{%- if hessian_approx == "EXACT" %}
external_function_param_casadi_free(capsule->sim_impl_dae_hess);
{%- endif %}
{%- elif solver_options.integrator_type == "ERK" %}
external_function_param_casadi_free(capsule->sim_forw_vde_casadi);
external_function_param_casadi_free(capsule->sim_expl_ode_fun_casadi);
{%- if hessian_approx == "EXACT" %}
external_function_param_casadi_free(capsule->sim_expl_ode_hess);
{%- endif %}
{%- elif solver_options.integrator_type == "GNSF" %}
{% if model.gnsf.purely_linear != 1 %}
external_function_param_casadi_free(capsule->sim_gnsf_phi_fun);
external_function_param_casadi_free(capsule->sim_gnsf_phi_fun_jac_y);
external_function_param_casadi_free(capsule->sim_gnsf_phi_jac_y_uhat);
{% if model.gnsf.nontrivial_f_LO == 1 %}
external_function_param_casadi_free(capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z);
{%- endif %}
{%- endif %}
external_function_param_casadi_free(capsule->sim_gnsf_get_matrices_fun);
{% endif %}
return 0;
}
int {{ model.name }}_acados_sim_update_params(sim_solver_capsule *capsule, double *p, int np)
{
int status = 0;
int casadi_np = {{ model.name | upper }}_NP;
if (casadi_np != np) {
printf("{{ model.name }}_acados_sim_update_params: trying to set %i parameters for external functions."
" External function has %i parameters. Exiting.\n", np, casadi_np);
exit(1);
}
{%- if solver_options.integrator_type == "ERK" %}
capsule->sim_forw_vde_casadi[0].set_param(capsule->sim_forw_vde_casadi, p);
capsule->sim_expl_ode_fun_casadi[0].set_param(capsule->sim_expl_ode_fun_casadi, p);
{%- if hessian_approx == "EXACT" %}
capsule->sim_expl_ode_hess[0].set_param(capsule->sim_expl_ode_hess, p);
{%- endif %}
{%- elif solver_options.integrator_type == "IRK" %}
capsule->sim_impl_dae_fun[0].set_param(capsule->sim_impl_dae_fun, p);
capsule->sim_impl_dae_fun_jac_x_xdot_z[0].set_param(capsule->sim_impl_dae_fun_jac_x_xdot_z, p);
capsule->sim_impl_dae_jac_x_xdot_u_z[0].set_param(capsule->sim_impl_dae_jac_x_xdot_u_z, p);
{%- if hessian_approx == "EXACT" %}
capsule->sim_impl_dae_hess[0].set_param(capsule->sim_impl_dae_hess, p);
{%- endif %}
{%- elif solver_options.integrator_type == "GNSF" %}
{% if model.gnsf.purely_linear != 1 %}
capsule->sim_gnsf_phi_fun[0].set_param(capsule->sim_gnsf_phi_fun, p);
capsule->sim_gnsf_phi_fun_jac_y[0].set_param(capsule->sim_gnsf_phi_fun_jac_y, p);
capsule->sim_gnsf_phi_jac_y_uhat[0].set_param(capsule->sim_gnsf_phi_jac_y_uhat, p);
{% if model.gnsf.nontrivial_f_LO == 1 %}
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z[0].set_param(capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z, p);
{%- endif %}
{%- endif %}
capsule->sim_gnsf_get_matrices_fun[0].set_param(capsule->sim_gnsf_get_matrices_fun, p);
{% endif %}
return status;
}
/* getters pointers to C objects*/
sim_config * {{ model.name }}_acados_get_sim_config(sim_solver_capsule *capsule)
{
return capsule->acados_sim_config;
};
sim_in * {{ model.name }}_acados_get_sim_in(sim_solver_capsule *capsule)
{
return capsule->acados_sim_in;
};
sim_out * {{ model.name }}_acados_get_sim_out(sim_solver_capsule *capsule)
{
return capsule->acados_sim_out;
};
void * {{ model.name }}_acados_get_sim_dims(sim_solver_capsule *capsule)
{
return capsule->acados_sim_dims;
};
sim_opts * {{ model.name }}_acados_get_sim_opts(sim_solver_capsule *capsule)
{
return capsule->acados_sim_opts;
};
sim_solver * {{ model.name }}_acados_get_sim_solver(sim_solver_capsule *capsule)
{
return capsule->acados_sim_solver;
};
@@ -0,0 +1,233 @@
/*
* Copyright 2019 Gianluca Frison, Dimitris Kouzoupis, Robin Verschueren,
* Andrea Zanelli, Niels van Duijkeren, Jonathan Frey, Tommaso Sartor,
* Branimir Novoselnik, Rien Quirynen, Rezart Qelibari, Dang Doan,
* Jonas Koenemann, Yutao Chen, Tobias Schöls, Jonas Schlagenhauf, Moritz Diehl
*
* This file is part of acados.
*
* The 2-Clause BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.;
*/
#define S_FUNCTION_NAME acados_sim_solver_sfunction_{{ model.name }}
#define S_FUNCTION_LEVEL 2
#define MDL_START
// acados
// #include "acados/utils/print.h"
#include "acados_c/ocp_nlp_interface.h"
#include "acados_c/external_function_interface.h"
// example specific
#include "{{ model.name }}_model/{{ model.name }}_model.h"
#include "acados_sim_solver_{{ model.name }}.h"
#include "simstruc.h"
#define SAMPLINGTIME {{ solver_options.Tsim }}
static void mdlInitializeSizes (SimStruct *S)
{
// specify the number of continuous and discrete states
ssSetNumContStates(S, 0);
ssSetNumDiscStates(S, 0);
{# compute number of input ports #}
{%- set n_inputs = 1 %} {# x0 #}
{%- if dims.nu > 0 %} {# u0 -#}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif %}
{%- if dims.np > 0 %} {# parameters #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif %}
// specify the number of input ports
if ( !ssSetNumInputPorts(S, {{ n_inputs }}) )
return;
// specify the number of output ports
if ( !ssSetNumOutputPorts(S, 1) )
return;
// specify dimension information for the input ports
{%- set i_input = 0 %}
// x0
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.nx }});
{%- if dims.nu > 0 %}
{%- set i_input = i_input + 1 %}
// u0
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.nu }});
{%- endif %}
{%- if dims.np > 0 %}
{%- set i_input = i_input + 1 %}
// parameters
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.np }});
{%- endif %}
// specify dimension information for the output ports
ssSetOutputPortVectorDimension(S, 0, {{ dims.nx }} ); // xnext
// specify the direct feedthrough status
// should be set to 1 for all inputs used in mdlOutputs
{%- for i in range(end=n_inputs) %}
ssSetInputPortDirectFeedThrough(S, {{ i }}, 1);
{%- endfor %}
// one sample time
ssSetNumSampleTimes(S, 1);
}
#if defined(MATLAB_MEX_FILE)
#define MDL_SET_INPUT_PORT_DIMENSION_INFO
#define MDL_SET_OUTPUT_PORT_DIMENSION_INFO
static void mdlSetInputPortDimensionInfo(SimStruct *S, int_T port, const DimsInfo_T *dimsInfo)
{
if ( !ssSetInputPortDimensionInfo(S, port, dimsInfo) )
return;
}
static void mdlSetOutputPortDimensionInfo(SimStruct *S, int_T port, const DimsInfo_T *dimsInfo)
{
if ( !ssSetOutputPortDimensionInfo(S, port, dimsInfo) )
return;
}
#endif /* MATLAB_MEX_FILE */
static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, SAMPLINGTIME);
ssSetOffsetTime(S, 0, 0.0);
}
static void mdlStart(SimStruct *S)
{
sim_solver_capsule *capsule = {{ model.name }}_acados_sim_solver_create_capsule();
{{ model.name }}_acados_sim_create(capsule);
ssSetUserData(S, (void*)capsule);
}
static void mdlOutputs(SimStruct *S, int_T tid)
{
sim_solver_capsule *capsule = ssGetUserData(S);
sim_config *acados_sim_config = {{ model.name }}_acados_get_sim_config(capsule);
sim_in *acados_sim_in = {{ model.name }}_acados_get_sim_in(capsule);
sim_out *acados_sim_out = {{ model.name }}_acados_get_sim_out(capsule);
void *acados_sim_dims = {{ model.name }}_acados_get_sim_dims(capsule);
// sim_opts * {{ model.name }}_acados_get_sim_opts(capsule);
// sim_solver * {{ model.name }}_acados_get_sim_solver(capsule);
InputRealPtrsType in_sign;
{% set input_sizes = [dims.nx, dims.nu, dims.np] %}
// local buffer
{%- set buffer_size = input_sizes | sort | last %}
real_t buffer[{{ buffer_size }}];
/* go through inputs */
{%- set i_input = 0 %}
// initial condition
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.nx }}; i++)
buffer[i] = (double)(*in_sign[i]);
sim_in_set(acados_sim_config, acados_sim_dims,
acados_sim_in, "x", buffer);
// ssPrintf("\nin acados sim:\n");
// for (int i = 0; i < {{ dims.nx }}; i++) ssPrintf("x0[%d] = %f\n", i, buffer[i]);
// ssPrintf("\n");
{% if dims.nu > 0 %}
// control input - u
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.nu }}; i++)
buffer[i] = (double)(*in_sign[i]);
sim_in_set(acados_sim_config, acados_sim_dims,
acados_sim_in, "u", buffer);
{%- endif %}
{% if dims.np > 0 %}
// parameters
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.np }}; i++)
buffer[i] = (double)(*in_sign[i]);
// update value of parameters
{{ model.name }}_acados_sim_update_params(capsule, buffer, {{ dims.np }});
{%- endif %}
/* call solver */
int acados_status = {{ model.name }}_acados_sim_solve(capsule);
/* set outputs */
real_t *out_x = ssGetOutputPortRealSignal(S, 0);
// get simulated state
sim_out_get(acados_sim_config, acados_sim_dims, acados_sim_out,
"xn", (void *) out_x);
// ssPrintf("\nacados sim solve: returned %d\n", acados_status);
// for (int i = 0; i < {{ dims.nx }}; i++) ssPrintf("x_sim[%d] = %f\n", i, out_x[i]);
// ssPrintf("\n");
}
static void mdlTerminate(SimStruct *S)
{
sim_solver_capsule *capsule = ssGetUserData(S);
{{ model.name }}_acados_sim_free(capsule);
{{ model.name }}_acados_sim_solver_free_capsule(capsule);
}
#ifdef MATLAB_MEX_FILE
#include "simulink.c"
#else
#include "cg_sfun.h"
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,782 @@
/*
* Copyright 2019 Gianluca Frison, Dimitris Kouzoupis, Robin Verschueren,
* Andrea Zanelli, Niels van Duijkeren, Jonathan Frey, Tommaso Sartor,
* Branimir Novoselnik, Rien Quirynen, Rezart Qelibari, Dang Doan,
* Jonas Koenemann, Yutao Chen, Tobias Schöls, Jonas Schlagenhauf, Moritz Diehl
*
* This file is part of acados.
*
* The 2-Clause BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.;
*/
#define S_FUNCTION_NAME acados_solver_sfunction_{{ model.name }}
#define S_FUNCTION_LEVEL 2
#define MDL_START
// acados
// #include "acados/utils/print.h"
#include "acados_c/sim_interface.h"
#include "acados_c/external_function_interface.h"
// example specific
#include "{{ model.name }}_model/{{ model.name }}_model.h"
#include "acados_solver_{{ model.name }}.h"
#include "simstruc.h"
{% if simulink_opts.samplingtime == "t0" -%}
#define SAMPLINGTIME {{ solver_options.time_steps[0] }}
{%- elif simulink_opts.samplingtime == "-1" -%}
#define SAMPLINGTIME -1
{%- else -%}
{{ throw(message = "simulink_opts.samplingtime must be '-1' or 't0', got val") }}
{%- endif %}
static void mdlInitializeSizes (SimStruct *S)
{
// specify the number of continuous and discrete states
ssSetNumContStates(S, 0);
ssSetNumDiscStates(S, 0);
{%- for key, val in simulink_opts.inputs -%}
{%- if val != 0 and val != 1 -%}
{{ throw(message = "simulink_opts.inputs must be 0 or 1, got val") }}
{%- endif -%}
{%- endfor -%}
{#- compute number of input ports #}
{%- set n_inputs = 0 -%}
{%- if dims.nbx_0 > 0 and simulink_opts.inputs.lbx_0 -%} {#- lbx_0 #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.nbx_0 > 0 and simulink_opts.inputs.ubx_0 -%} {#- ubx_0 #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.np > 0 and simulink_opts.inputs.parameter_traj -%} {#- parameter_traj #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.ny_0 > 0 and simulink_opts.inputs.y_ref_0 -%} {#- y_ref_0 -#}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.ny > 0 and dims.N > 1 and simulink_opts.inputs.y_ref -%} {#- y_ref -#}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.ny_e > 0 and dims.N > 0 and simulink_opts.inputs.y_ref_e -%} {#- y_ref_e #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.nbx > 0 and dims.N > 1 and simulink_opts.inputs.lbx -%} {#- lbx #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.nbx > 0 and dims.N > 1 and simulink_opts.inputs.ubx -%} {#- ubx #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.nbx_e > 0 and dims.N > 0 and simulink_opts.inputs.lbx_e -%} {#- lbx_e #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.nbx_e > 0 and dims.N > 0 and simulink_opts.inputs.ubx_e -%} {#- ubx_e #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.nbu > 0 and dims.N > 0 and simulink_opts.inputs.lbu -%} {#- lbu #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.nbu > 0 and dims.N > 0 and simulink_opts.inputs.ubu -%} {#- ubu #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.ng > 0 and simulink_opts.inputs.lg -%} {#- lg #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.ng > 0 and simulink_opts.inputs.ug -%} {#- ug #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.nh > 0 and simulink_opts.inputs.lh -%} {#- lh #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if dims.nh > 0 and simulink_opts.inputs.uh -%} {#- uh #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- for key, val in simulink_opts.inputs -%}
{%- if val != 0 and val != 1 -%}
{{ throw(message = "simulink_opts.inputs must be 0 or 1, got val") }}
{%- endif -%}
{%- endfor -%}
{%- if dims.ny_0 > 0 and simulink_opts.inputs.cost_W_0 %} {#- cost_W_0 #}
{%- set n_inputs = n_inputs + 1 %}
{%- endif -%}
{%- if dims.ny > 0 and simulink_opts.inputs.cost_W %} {#- cost_W #}
{%- set n_inputs = n_inputs + 1 %}
{%- endif -%}
{%- if dims.ny_e > 0 and simulink_opts.inputs.cost_W_e %} {#- cost_W_e #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if simulink_opts.inputs.reset_solver -%} {#- reset_solver #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if simulink_opts.inputs.x_init -%} {#- x_init #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
{%- if simulink_opts.inputs.u_init -%} {#- u_init #}
{%- set n_inputs = n_inputs + 1 -%}
{%- endif -%}
// specify the number of input ports
if ( !ssSetNumInputPorts(S, {{ n_inputs }}) )
return;
// specify the number of output ports
{%- set_global n_outputs = 0 %}
{%- for key, val in simulink_opts.outputs %}
{%- if val == 1 %}
{%- set_global n_outputs = n_outputs + val %}
{%- elif val != 0 %}
{{ throw(message = "simulink_opts.outputs must be 0 or 1, got val") }}
{%- endif %}
{%- endfor %}
if ( !ssSetNumOutputPorts(S, {{ n_outputs }}) )
return;
// specify dimension information for the input ports
{%- set i_input = -1 %}{# note here i_input is 0-based #}
{%- if dims.nbx_0 > 0 and simulink_opts.inputs.lbx_0 -%} {#- lbx_0 #}
{%- set i_input = i_input + 1 %}
// lbx_0
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.nbx_0 }});
{%- endif %}
{%- if dims.nbx_0 > 0 and simulink_opts.inputs.ubx_0 -%} {#- ubx_0 #}
{%- set i_input = i_input + 1 %}
// ubx_0
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.nbx_0 }});
{%- endif %}
{%- if dims.np > 0 and simulink_opts.inputs.parameter_traj -%} {#- parameter_traj #}
{%- set i_input = i_input + 1 %}
// parameters
ssSetInputPortVectorDimension(S, {{ i_input }}, ({{ dims.N }}+1) * {{ dims.np }});
{%- endif %}
{%- if dims.ny > 0 and simulink_opts.inputs.y_ref_0 %}
{%- set i_input = i_input + 1 %}
// y_ref_0
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.ny_0 }});
{%- endif %}
{%- if dims.ny > 0 and dims.N > 1 and simulink_opts.inputs.y_ref %}
{%- set i_input = i_input + 1 %}
// y_ref
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ (dims.N-1) * dims.ny }});
{%- endif %}
{%- if dims.ny_e > 0 and dims.N > 0 and simulink_opts.inputs.y_ref_e %}
{%- set i_input = i_input + 1 %}
// y_ref_e
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.ny_e }});
{%- endif %}
{%- if dims.nbx > 0 and dims.N > 1 and simulink_opts.inputs.lbx -%} {#- lbx #}
{%- set i_input = i_input + 1 %}
// lbx
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ (dims.N-1) * dims.nbx }});
{%- endif %}
{%- if dims.nbx > 0 and dims.N > 1 and simulink_opts.inputs.ubx -%} {#- ubx #}
{%- set i_input = i_input + 1 %}
// ubx
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ (dims.N-1) * dims.nbx }});
{%- endif %}
{%- if dims.nbx_e > 0 and dims.N > 0 and simulink_opts.inputs.lbx_e -%} {#- lbx_e #}
{%- set i_input = i_input + 1 %}
// lbx_e
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.nbx_e }});
{%- endif %}
{%- if dims.nbx_e > 0 and dims.N > 0 and simulink_opts.inputs.ubx_e -%} {#- ubx_e #}
{%- set i_input = i_input + 1 %}
// ubx_e
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.nbx_e }});
{%- endif %}
{%- if dims.nbu > 0 and dims.N > 0 and simulink_opts.inputs.lbu -%} {#- lbu #}
{%- set i_input = i_input + 1 %}
// lbu
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.N*dims.nbu }});
{%- endif -%}
{%- if dims.nbu > 0 and dims.N > 0 and simulink_opts.inputs.ubu -%} {#- ubu #}
{%- set i_input = i_input + 1 %}
// ubu
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.N*dims.nbu }});
{%- endif -%}
{%- if dims.ng > 0 and simulink_opts.inputs.lg -%} {#- lg #}
{%- set i_input = i_input + 1 %}
// lg
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.ng }});
{%- endif -%}
{%- if dims.ng > 0 and simulink_opts.inputs.ug -%} {#- ug #}
{%- set i_input = i_input + 1 %}
// ug
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.ng }});
{%- endif -%}
{%- if dims.nh > 0 and simulink_opts.inputs.lh -%} {#- lh #}
{%- set i_input = i_input + 1 %}
// lh
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.nh }});
{%- endif -%}
{%- if dims.nh > 0 and simulink_opts.inputs.uh -%} {#- uh #}
{%- set i_input = i_input + 1 %}
// uh
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.nh }});
{%- endif -%}
{%- if dims.ny_0 > 0 and simulink_opts.inputs.cost_W_0 %} {#- cost_W_0 #}
{%- set i_input = i_input + 1 %}
// cost_W_0
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.ny_0 * dims.ny_0 }});
{%- endif %}
{%- if dims.ny > 0 and simulink_opts.inputs.cost_W %} {#- cost_W #}
{%- set i_input = i_input + 1 %}
// cost_W
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.ny * dims.ny }});
{%- endif %}
{%- if dims.ny_e > 0 and simulink_opts.inputs.cost_W_e %} {#- cost_W_e #}
{%- set i_input = i_input + 1 %}
// cost_W_e
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.ny_e * dims.ny_e }});
{%- endif %}
{%- if simulink_opts.inputs.reset_solver -%} {#- reset_solver #}
{%- set i_input = i_input + 1 %}
// reset_solver
ssSetInputPortVectorDimension(S, {{ i_input }}, 1);
{%- endif -%}
{%- if simulink_opts.inputs.x_init -%} {#- x_init #}
{%- set i_input = i_input + 1 %}
// x_init
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.nx * (dims.N+1) }});
{%- endif -%}
{%- if simulink_opts.inputs.u_init -%} {#- u_init #}
{%- set i_input = i_input + 1 %}
// u_init
ssSetInputPortVectorDimension(S, {{ i_input }}, {{ dims.nu * (dims.N) }});
{%- endif -%}
/* specify dimension information for the OUTPUT ports */
{%- set i_output = -1 %}{# note here i_output is 0-based #}
{%- if dims.nu > 0 and simulink_opts.outputs.u0 == 1 %}
{%- set i_output = i_output + 1 %}
ssSetOutputPortVectorDimension(S, {{ i_output }}, {{ dims.nu }} );
{%- endif %}
{%- if simulink_opts.outputs.utraj == 1 %}
{%- set i_output = i_output + 1 %}
ssSetOutputPortVectorDimension(S, {{ i_output }}, {{ dims.nu * dims.N }} );
{%- endif %}
{%- if simulink_opts.outputs.xtraj == 1 %}
{%- set i_output = i_output + 1 %}
ssSetOutputPortVectorDimension(S, {{ i_output }}, {{ dims.nx * (dims.N+1) }} );
{%- endif %}
{%- if simulink_opts.outputs.solver_status == 1 %}
{%- set i_output = i_output + 1 %}
ssSetOutputPortVectorDimension(S, {{ i_output }}, 1 );
{%- endif %}
{%- if simulink_opts.outputs.KKT_residual == 1 %}
{%- set i_output = i_output + 1 %}
ssSetOutputPortVectorDimension(S, {{ i_output }}, 1 );
{%- endif %}
{%- if dims.N > 0 and simulink_opts.outputs.x1 == 1 %}
{%- set i_output = i_output + 1 %}
ssSetOutputPortVectorDimension(S, {{ i_output }}, {{ dims.nx }} ); // state at shooting node 1
{%- endif %}
{%- if simulink_opts.outputs.CPU_time == 1 %}
{%- set i_output = i_output + 1 %}
ssSetOutputPortVectorDimension(S, {{ i_output }}, 1);
{%- endif %}
{%- if simulink_opts.outputs.CPU_time_sim == 1 %}
{%- set i_output = i_output + 1 %}
ssSetOutputPortVectorDimension(S, {{ i_output }}, 1);
{%- endif %}
{%- if simulink_opts.outputs.CPU_time_qp == 1 %}
{%- set i_output = i_output + 1 %}
ssSetOutputPortVectorDimension(S, {{ i_output }}, 1);
{%- endif %}
{%- if simulink_opts.outputs.CPU_time_lin == 1 %}
{%- set i_output = i_output + 1 %}
ssSetOutputPortVectorDimension(S, {{ i_output }}, 1);
{%- endif %}
{%- if simulink_opts.outputs.sqp_iter == 1 %}
{%- set i_output = i_output + 1 %}
ssSetOutputPortVectorDimension(S, {{ i_output }}, 1 );
{%- endif %}
// specify the direct feedthrough status
// should be set to 1 for all inputs used in mdlOutputs
{%- for i in range(end=n_inputs) %}
ssSetInputPortDirectFeedThrough(S, {{ i }}, 1);
{%- endfor %}
// one sample time
ssSetNumSampleTimes(S, 1);
}
#if defined(MATLAB_MEX_FILE)
#define MDL_SET_INPUT_PORT_DIMENSION_INFO
#define MDL_SET_OUTPUT_PORT_DIMENSION_INFO
static void mdlSetInputPortDimensionInfo(SimStruct *S, int_T port, const DimsInfo_T *dimsInfo)
{
if ( !ssSetInputPortDimensionInfo(S, port, dimsInfo) )
return;
}
static void mdlSetOutputPortDimensionInfo(SimStruct *S, int_T port, const DimsInfo_T *dimsInfo)
{
if ( !ssSetOutputPortDimensionInfo(S, port, dimsInfo) )
return;
}
#endif /* MATLAB_MEX_FILE */
static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, SAMPLINGTIME);
ssSetOffsetTime(S, 0, 0.0);
}
static void mdlStart(SimStruct *S)
{
{{ model.name }}_solver_capsule *capsule = {{ model.name }}_acados_create_capsule();
{{ model.name }}_acados_create(capsule);
ssSetUserData(S, (void*)capsule);
}
static void mdlOutputs(SimStruct *S, int_T tid)
{
{{ model.name }}_solver_capsule *capsule = ssGetUserData(S);
ocp_nlp_config *nlp_config = {{ model.name }}_acados_get_nlp_config(capsule);
ocp_nlp_dims *nlp_dims = {{ model.name }}_acados_get_nlp_dims(capsule);
ocp_nlp_in *nlp_in = {{ model.name }}_acados_get_nlp_in(capsule);
ocp_nlp_out *nlp_out = {{ model.name }}_acados_get_nlp_out(capsule);
InputRealPtrsType in_sign;
{%- set buffer_sizes = [dims.nbx_0, dims.np, dims.nbx, dims.nbu, dims.ng, dims.nh, dims.nx] -%}
{%- if dims.ny_0 > 0 and simulink_opts.inputs.y_ref_0 %} {# y_ref_0 #}
{%- set buffer_sizes = buffer_sizes | concat(with=(dims.ny_0)) %}
{%- endif %}
{%- if dims.ny > 0 and dims.N > 1 and simulink_opts.inputs.y_ref %} {# y_ref #}
{%- set buffer_sizes = buffer_sizes | concat(with=(dims.ny)) %}
{%- endif %}
{%- if dims.ny_e > 0 and dims.N > 0 and simulink_opts.inputs.y_ref_e %} {# y_ref_e #}
{%- set buffer_sizes = buffer_sizes | concat(with=(dims.ny_e)) %}
{%- endif %}
{%- if dims.ny_0 > 0 and simulink_opts.inputs.cost_W_0 %} {#- cost_W_0 #}
{%- set buffer_sizes = buffer_sizes | concat(with=(dims.ny_0 * dims.ny_0)) %}
{%- endif %}
{%- if dims.ny > 0 and simulink_opts.inputs.cost_W %} {#- cost_W #}
{%- set buffer_sizes = buffer_sizes | concat(with=(dims.ny * dims.ny)) %}
{%- endif %}
{%- if dims.ny_e > 0 and simulink_opts.inputs.cost_W_e %} {#- cost_W_e #}
{%- set buffer_sizes = buffer_sizes | concat(with=(dims.ny_e * dims.ny_e)) %}
{%- endif %}
// local buffer
{%- set buffer_size = buffer_sizes | sort | last %}
real_t buffer[{{ buffer_size }}];
/* go through inputs */
{%- set i_input = -1 %}
{%- if dims.nbx_0 > 0 and simulink_opts.inputs.lbx_0 -%} {#- lbx_0 #}
// lbx_0
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.nbx_0 }}; i++)
buffer[i] = (double)(*in_sign[i]);
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, 0, "lbx", buffer);
{%- endif %}
{%- if dims.nbx_0 > 0 and simulink_opts.inputs.ubx_0 -%} {#- ubx_0 #}
// ubx_0
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.nbx_0 }}; i++)
buffer[i] = (double)(*in_sign[i]);
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, 0, "ubx", buffer);
{%- endif %}
{%- if dims.np > 0 and simulink_opts.inputs.parameter_traj -%} {#- parameter_traj #}
// parameters - stage-variant !!!
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
// update value of parameters
for (int ii = 0; ii <= {{ dims.N }}; ii++)
{
for (int jj = 0; jj < {{ dims.np }}; jj++)
buffer[jj] = (double)(*in_sign[ii*{{dims.np}}+jj]);
{{ model.name }}_acados_update_params(capsule, ii, buffer, {{ dims.np }});
}
{%- endif %}
{% if dims.ny_0 > 0 and simulink_opts.inputs.y_ref_0 %}
// y_ref_0
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.ny_0 }}; i++)
buffer[i] = (double)(*in_sign[i]);
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, 0, "yref", (void *) buffer);
{%- endif %}
{% if dims.ny > 0 and dims.N > 1 and simulink_opts.inputs.y_ref %}
// y_ref - for stages 1 to N-1
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int ii = 1; ii < {{ dims.N }}; ii++)
{
for (int jj = 0; jj < {{ dims.ny }}; jj++)
buffer[jj] = (double)(*in_sign[(ii-1)*{{ dims.ny }}+jj]);
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, ii, "yref", (void *) buffer);
}
{%- endif %}
{% if dims.ny_e > 0 and dims.N > 0 and simulink_opts.inputs.y_ref_e %}
// y_ref_e
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.ny_e }}; i++)
buffer[i] = (double)(*in_sign[i]);
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, {{ dims.N }}, "yref", (void *) buffer);
{%- endif %}
{%- if dims.nbx > 0 and dims.N > 1 and simulink_opts.inputs.lbx -%} {#- lbx #}
// lbx
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int ii = 1; ii < {{ dims.N }}; ii++)
{
for (int jj = 0; jj < {{ dims.nbx }}; jj++)
buffer[jj] = (double)(*in_sign[(ii-1)*{{ dims.nbx }}+jj]);
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, ii, "lbx", (void *) buffer);
}
{%- endif %}
{%- if dims.nbx > 0 and dims.N > 1 and simulink_opts.inputs.ubx -%} {#- ubx #}
// ubx
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int ii = 1; ii < {{ dims.N }}; ii++)
{
for (int jj = 0; jj < {{ dims.nbx }}; jj++)
buffer[jj] = (double)(*in_sign[(ii-1)*{{ dims.nbx }}+jj]);
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, ii, "ubx", (void *) buffer);
}
{%- endif %}
{%- if dims.nbx_e > 0 and dims.N > 0 and simulink_opts.inputs.lbx_e -%} {#- lbx_e #}
// lbx_e
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.nbx_e }}; i++)
buffer[i] = (double)(*in_sign[i]);
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, {{ dims.N }}, "lbx", buffer);
{%- endif %}
{%- if dims.nbx_e > 0 and dims.N > 0 and simulink_opts.inputs.ubx_e -%} {#- ubx_e #}
// ubx_e
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.nbx_e }}; i++)
buffer[i] = (double)(*in_sign[i]);
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, {{ dims.N }}, "ubx", buffer);
{%- endif %}
{%- if dims.nbu > 0 and dims.N > 0 and simulink_opts.inputs.lbu -%} {#- lbu #}
// lbu
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int ii = 0; ii < {{ dims.N }}; ii++)
{
for (int jj = 0; jj < {{ dims.nbu }}; jj++)
buffer[jj] = (double)(*in_sign[ii*{{ dims.nbu }}+jj]);
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, ii, "lbu", (void *) buffer);
}
{%- endif -%}
{%- if dims.nbu > 0 and dims.N > 0 and simulink_opts.inputs.ubu -%} {#- ubu #}
// ubu
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int ii = 0; ii < {{ dims.N }}; ii++)
{
for (int jj = 0; jj < {{ dims.nbu }}; jj++)
buffer[jj] = (double)(*in_sign[ii*{{ dims.nbu }}+jj]);
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, ii, "ubu", (void *) buffer);
}
{%- endif -%}
{%- if dims.ng > 0 and simulink_opts.inputs.lg -%} {#- lg #}
// lg
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.ng }}; i++)
buffer[i] = (double)(*in_sign[i]);
for (int ii = 0; ii < {{ dims.N }}; ii++)
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, ii, "lg", buffer);
{%- endif -%}
{%- if dims.ng > 0 and simulink_opts.inputs.ug -%} {#- ug #}
// ug
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.ng }}; i++)
buffer[i] = (double)(*in_sign[i]);
for (int ii = 0; ii < {{ dims.N }}; ii++)
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, ii, "ug", buffer);
{%- endif -%}
{%- if dims.nh > 0 and simulink_opts.inputs.lh -%} {#- lh #}
// lh
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.nh }}; i++)
buffer[i] = (double)(*in_sign[i]);
for (int ii = 0; ii < {{ dims.N }}; ii++)
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, ii, "lh", buffer);
{%- endif -%}
{%- if dims.nh > 0 and simulink_opts.inputs.uh -%} {#- uh #}
// uh
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.nh }}; i++)
buffer[i] = (double)(*in_sign[i]);
for (int ii = 0; ii < {{ dims.N }}; ii++)
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, ii, "uh", buffer);
{%- endif -%}
{%- if dims.ny_0 > 0 and simulink_opts.inputs.cost_W_0 %} {#- cost_W_0 #}
// cost_W_0
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.ny_0 * dims.ny_0 }}; i++)
buffer[i] = (double)(*in_sign[i]);
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, 0, "W", buffer);
{%- endif %}
{%- if dims.ny > 0 and simulink_opts.inputs.cost_W %} {#- cost_W #}
// cost_W
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.ny * dims.ny }}; i++)
buffer[i] = (double)(*in_sign[i]);
for (int ii = 1; ii < {{ dims.N }}; ii++)
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, ii, "W", buffer);
{%- endif %}
{%- if dims.ny_e > 0 and simulink_opts.inputs.cost_W_e %} {#- cost_W_e #}
// cost_W_e
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int i = 0; i < {{ dims.ny_e * dims.ny_e }}; i++)
buffer[i] = (double)(*in_sign[i]);
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, {{ dims.N }}, "W", buffer);
{%- endif %}
{%- if simulink_opts.inputs.reset_solver %} {#- reset_solver #}
// reset_solver
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
double reset = (double)(*in_sign[0]);
if (reset)
{
{{ model.name }}_acados_reset(capsule);
}
{%- endif %}
{%- if simulink_opts.inputs.x_init %} {#- x_init #}
// x_init
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int ii = 0; ii < {{ dims.N + 1 }}; ii++)
{
for (int jj = 0; jj < {{ dims.nx }}; jj++)
buffer[jj] = (double)(*in_sign[(ii)*{{ dims.nx }}+jj]);
ocp_nlp_out_set(nlp_config, nlp_dims, nlp_out, ii, "x", (void *) buffer);
}
{%- endif %}
{%- if simulink_opts.inputs.u_init %} {#- u_init #}
// u_init
{%- set i_input = i_input + 1 %}
in_sign = ssGetInputPortRealSignalPtrs(S, {{ i_input }});
for (int ii = 0; ii < {{ dims.N }}; ii++)
{
for (int jj = 0; jj < {{ dims.nu }}; jj++)
buffer[jj] = (double)(*in_sign[(ii)*{{ dims.nu }}+jj]);
ocp_nlp_out_set(nlp_config, nlp_dims, nlp_out, ii, "u", (void *) buffer);
}
{%- endif %}
/* call solver */
int rti_phase = 0;
ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "rti_phase", &rti_phase);
int acados_status = {{ model.name }}_acados_solve(capsule);
/* set outputs */
// assign pointers to output signals
real_t *out_u0, *out_utraj, *out_xtraj, *out_status, *out_sqp_iter, *out_KKT_res, *out_x1, *out_cpu_time, *out_cpu_time_sim, *out_cpu_time_qp, *out_cpu_time_lin;
int tmp_int;
{%- set i_output = -1 -%}{# note here i_output is 0-based #}
{%- if dims.nu > 0 and simulink_opts.outputs.u0 == 1 %}
{%- set i_output = i_output + 1 %}
out_u0 = ssGetOutputPortRealSignal(S, {{ i_output }});
ocp_nlp_out_get(nlp_config, nlp_dims, nlp_out, 0, "u", (void *) out_u0);
{%- endif %}
{%- if simulink_opts.outputs.utraj == 1 %}
{%- set i_output = i_output + 1 %}
out_utraj = ssGetOutputPortRealSignal(S, {{ i_output }});
for (int ii = 0; ii < {{ dims.N }}; ii++)
ocp_nlp_out_get(nlp_config, nlp_dims, nlp_out, ii,
"u", (void *) (out_utraj + ii * {{ dims.nu }}));
{%- endif %}
{% if simulink_opts.outputs.xtraj == 1 %}
{%- set i_output = i_output + 1 %}
out_xtraj = ssGetOutputPortRealSignal(S, {{ i_output }});
for (int ii = 0; ii < {{ dims.N + 1 }}; ii++)
ocp_nlp_out_get(nlp_config, nlp_dims, nlp_out, ii,
"x", (void *) (out_xtraj + ii * {{ dims.nx }}));
{%- endif %}
{%- if simulink_opts.outputs.solver_status == 1 %}
{%- set i_output = i_output + 1 %}
out_status = ssGetOutputPortRealSignal(S, {{ i_output }});
*out_status = (real_t) acados_status;
{%- endif %}
{%- if simulink_opts.outputs.KKT_residual == 1 %}
{%- set i_output = i_output + 1 %}
out_KKT_res = ssGetOutputPortRealSignal(S, {{ i_output }});
*out_KKT_res = (real_t) nlp_out->inf_norm_res;
{%- endif %}
{%- if dims.N > 0 and simulink_opts.outputs.x1 == 1 %}
{%- set i_output = i_output + 1 %}
out_x1 = ssGetOutputPortRealSignal(S, {{ i_output }});
ocp_nlp_out_get(nlp_config, nlp_dims, nlp_out, 1, "x", (void *) out_x1);
{%- endif %}
{%- if simulink_opts.outputs.CPU_time == 1 %}
{%- set i_output = i_output + 1 %}
out_cpu_time = ssGetOutputPortRealSignal(S, {{ i_output }});
// get solution time
ocp_nlp_get(nlp_config, capsule->nlp_solver, "time_tot", (void *) out_cpu_time);
{%- endif -%}
{%- if simulink_opts.outputs.CPU_time_sim == 1 %}
{%- set i_output = i_output + 1 %}
out_cpu_time_sim = ssGetOutputPortRealSignal(S, {{ i_output }});
ocp_nlp_get(nlp_config, capsule->nlp_solver, "time_sim", (void *) out_cpu_time_sim);
{%- endif -%}
{%- if simulink_opts.outputs.CPU_time_qp == 1 %}
{%- set i_output = i_output + 1 %}
out_cpu_time_qp = ssGetOutputPortRealSignal(S, {{ i_output }});
ocp_nlp_get(nlp_config, capsule->nlp_solver, "time_qp", (void *) out_cpu_time_qp);
{%- endif -%}
{%- if simulink_opts.outputs.CPU_time_lin == 1 %}
{%- set i_output = i_output + 1 %}
out_cpu_time_lin = ssGetOutputPortRealSignal(S, {{ i_output }});
ocp_nlp_get(nlp_config, capsule->nlp_solver, "time_lin", (void *) out_cpu_time_lin);
{%- endif -%}
{%- if simulink_opts.outputs.sqp_iter == 1 %}
{%- set i_output = i_output + 1 %}
out_sqp_iter = ssGetOutputPortRealSignal(S, {{ i_output }});
// get sqp iter
ocp_nlp_get(nlp_config, capsule->nlp_solver, "sqp_iter", (void *) &tmp_int);
*out_sqp_iter = (real_t) tmp_int;
{%- endif %}
}
static void mdlTerminate(SimStruct *S)
{
{{ model.name }}_solver_capsule *capsule = ssGetUserData(S);
{{ model.name }}_acados_free(capsule);
{{ model.name }}_acados_free_capsule(capsule);
}
#ifdef MATLAB_MEX_FILE
#include "simulink.c"
#else
#include "cg_sfun.h"
#endif
@@ -0,0 +1,216 @@
/*
* Copyright 2019 Gianluca Frison, Dimitris Kouzoupis, Robin Verschueren,
* Andrea Zanelli, Niels van Duijkeren, Jonathan Frey, Tommaso Sartor,
* Branimir Novoselnik, Rien Quirynen, Rezart Qelibari, Dang Doan,
* Jonas Koenemann, Yutao Chen, Tobias Schöls, Jonas Schlagenhauf, Moritz Diehl
*
* This file is part of acados.
*
* The 2-Clause BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.;
*/
// standard
#include <stdio.h>
#include <stdlib.h>
// acados
#include "acados/utils/print.h"
#include "acados/utils/math.h"
#include "acados_c/ocp_nlp_interface.h"
#include "acados_c/external_function_interface.h"
#include "acados_solver_{{ model.name }}.h"
#define NX {{ model.name | upper }}_NX
#define NZ {{ model.name | upper }}_NZ
#define NU {{ model.name | upper }}_NU
#define NP {{ model.name | upper }}_NP
#define NBX {{ model.name | upper }}_NBX
#define NBX0 {{ model.name | upper }}_NBX0
#define NBU {{ model.name | upper }}_NBU
#define NSBX {{ model.name | upper }}_NSBX
#define NSBU {{ model.name | upper }}_NSBU
#define NSH {{ model.name | upper }}_NSH
#define NSG {{ model.name | upper }}_NSG
#define NSPHI {{ model.name | upper }}_NSPHI
#define NSHN {{ model.name | upper }}_NSHN
#define NSGN {{ model.name | upper }}_NSGN
#define NSPHIN {{ model.name | upper }}_NSPHIN
#define NSBXN {{ model.name | upper }}_NSBXN
#define NS {{ model.name | upper }}_NS
#define NSN {{ model.name | upper }}_NSN
#define NG {{ model.name | upper }}_NG
#define NBXN {{ model.name | upper }}_NBXN
#define NGN {{ model.name | upper }}_NGN
#define NY0 {{ model.name | upper }}_NY0
#define NY {{ model.name | upper }}_NY
#define NYN {{ model.name | upper }}_NYN
#define NH {{ model.name | upper }}_NH
#define NPHI {{ model.name | upper }}_NPHI
#define NHN {{ model.name | upper }}_NHN
#define NPHIN {{ model.name | upper }}_NPHIN
#define NR {{ model.name | upper }}_NR
int main()
{
{{ model.name }}_solver_capsule *acados_ocp_capsule = {{ model.name }}_acados_create_capsule();
// there is an opportunity to change the number of shooting intervals in C without new code generation
int N = {{ model.name | upper }}_N;
// allocate the array and fill it accordingly
double* new_time_steps = NULL;
int status = {{ model.name }}_acados_create_with_discretization(acados_ocp_capsule, N, new_time_steps);
if (status)
{
printf("{{ model.name }}_acados_create() returned status %d. Exiting.\n", status);
exit(1);
}
ocp_nlp_config *nlp_config = {{ model.name }}_acados_get_nlp_config(acados_ocp_capsule);
ocp_nlp_dims *nlp_dims = {{ model.name }}_acados_get_nlp_dims(acados_ocp_capsule);
ocp_nlp_in *nlp_in = {{ model.name }}_acados_get_nlp_in(acados_ocp_capsule);
ocp_nlp_out *nlp_out = {{ model.name }}_acados_get_nlp_out(acados_ocp_capsule);
ocp_nlp_solver *nlp_solver = {{ model.name }}_acados_get_nlp_solver(acados_ocp_capsule);
void *nlp_opts = {{ model.name }}_acados_get_nlp_opts(acados_ocp_capsule);
// initial condition
int idxbx0[NBX0];
{%- for i in range(end=dims.nbx_0) %}
idxbx0[{{ i }}] = {{ constraints.idxbx_0[i] }};
{%- endfor %}
double lbx0[NBX0];
double ubx0[NBX0];
{%- for i in range(end=dims.nbx_0) %}
lbx0[{{ i }}] = {{ constraints.lbx_0[i] }};
ubx0[{{ i }}] = {{ constraints.ubx_0[i] }};
{%- endfor %}
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, 0, "idxbx", idxbx0);
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, 0, "lbx", lbx0);
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, 0, "ubx", ubx0);
// initialization for state values
double x_init[NX];
{%- for i in range(end=dims.nx) %}
x_init[{{ i }}] = 0.0;
{%- endfor %}
// initial value for control input
double u0[NU];
{%- for i in range(end=dims.nu) %}
u0[{{ i }}] = 0.0;
{%- endfor %}
{%- if dims.np > 0 %}
// set parameters
double p[NP];
{%- for item in parameter_values %}
p[{{ loop.index0 }}] = {{ item }};
{%- endfor %}
for (int ii = 0; ii <= N; ii++)
{
{{ model.name }}_acados_update_params(acados_ocp_capsule, ii, p, NP);
}
{% endif %}{# if np > 0 #}
// prepare evaluation
int NTIMINGS = 1;
double min_time = 1e12;
double kkt_norm_inf;
double elapsed_time;
int sqp_iter;
double xtraj[NX * (N+1)];
double utraj[NU * N];
// solve ocp in loop
int rti_phase = 0;
for (int ii = 0; ii < NTIMINGS; ii++)
{
// initialize solution
for (int i = 0; i < N; i++)
{
ocp_nlp_out_set(nlp_config, nlp_dims, nlp_out, i, "x", x_init);
ocp_nlp_out_set(nlp_config, nlp_dims, nlp_out, i, "u", u0);
}
ocp_nlp_out_set(nlp_config, nlp_dims, nlp_out, N, "x", x_init);
ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "rti_phase", &rti_phase);
status = {{ model.name }}_acados_solve(acados_ocp_capsule);
ocp_nlp_get(nlp_config, nlp_solver, "time_tot", &elapsed_time);
min_time = MIN(elapsed_time, min_time);
}
/* print solution and statistics */
for (int ii = 0; ii <= nlp_dims->N; ii++)
ocp_nlp_out_get(nlp_config, nlp_dims, nlp_out, ii, "x", &xtraj[ii*NX]);
for (int ii = 0; ii < nlp_dims->N; ii++)
ocp_nlp_out_get(nlp_config, nlp_dims, nlp_out, ii, "u", &utraj[ii*NU]);
printf("\n--- xtraj ---\n");
d_print_exp_tran_mat( NX, N+1, xtraj, NX);
printf("\n--- utraj ---\n");
d_print_exp_tran_mat( NU, N, utraj, NU );
// ocp_nlp_out_print(nlp_solver->dims, nlp_out);
printf("\nsolved ocp %d times, solution printed above\n\n", NTIMINGS);
if (status == ACADOS_SUCCESS)
{
printf("{{ model.name }}_acados_solve(): SUCCESS!\n");
}
else
{
printf("{{ model.name }}_acados_solve() failed with status %d.\n", status);
}
// get solution
ocp_nlp_out_get(nlp_config, nlp_dims, nlp_out, 0, "kkt_norm_inf", &kkt_norm_inf);
ocp_nlp_get(nlp_config, nlp_solver, "sqp_iter", &sqp_iter);
{{ model.name }}_acados_print_stats(acados_ocp_capsule);
printf("\nSolver info:\n");
printf(" SQP iterations %2d\n minimum time for %d solve %f [ms]\n KKT %e\n",
sqp_iter, NTIMINGS, min_time*1000, kkt_norm_inf);
// free solver
status = {{ model.name }}_acados_free(acados_ocp_capsule);
if (status) {
printf("{{ model.name }}_acados_free() returned status %d. \n", status);
}
// free solver capsule
status = {{ model.name }}_acados_free_capsule(acados_ocp_capsule);
if (status) {
printf("{{ model.name }}_acados_free_capsule() returned status %d. \n", status);
}
return status;
}
@@ -0,0 +1,184 @@
/*
* Copyright 2019 Gianluca Frison, Dimitris Kouzoupis, Robin Verschueren,
* Andrea Zanelli, Niels van Duijkeren, Jonathan Frey, Tommaso Sartor,
* Branimir Novoselnik, Rien Quirynen, Rezart Qelibari, Dang Doan,
* Jonas Koenemann, Yutao Chen, Tobias Schöls, Jonas Schlagenhauf, Moritz Diehl
*
* This file is part of acados.
*
* The 2-Clause BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.;
*/
// standard
#include <stdio.h>
#include <stdlib.h>
// acados
#include "acados/utils/print.h"
#include "acados/utils/math.h"
#include "acados_c/ocp_nlp_interface.h"
#include "acados_solver_{{ model.name }}.h"
// mex
#include "mex.h"
/* auxilary mex */
// prints a matrix in column-major format (exponential notation)
void MEX_print_exp_mat(int m, int n, double *A, int lda)
{
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
{
mexPrintf("%e\t", A[i+lda*j]);
}
mexPrintf("\n");
}
mexPrintf("\n");
}
// prints the transposed of a matrix in column-major format (exponential notation)
void MEX_print_exp_tran_mat(int row, int col, double *A, int lda)
{
for (int j=0; j<col; j++)
{
for (int i=0; i<row; i++)
{
mexPrintf("%e\t", A[i+lda*j]);
}
mexPrintf("\n");
}
mexPrintf("\n");
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int status = 0;
status = {{ model.name }}_acados_create();
if (status)
{
mexPrintf("{{ model.name }}_acados_create() returned status %d. Exiting.\n", status);
exit(1);
}
// get pointers to nlp solver related objects
ocp_nlp_config *nlp_config = {{ model.name }}_acados_get_nlp_config();
ocp_nlp_dims *nlp_dims = {{ model.name }}_acados_get_nlp_dims();
ocp_nlp_in *nlp_in = {{ model.name }}_acados_get_nlp_in();
ocp_nlp_out *nlp_out = {{ model.name }}_acados_get_nlp_out();
ocp_nlp_solver *nlp_solver = {{ model.name }}_acados_get_nlp_solver();
void *nlp_opts = {{ model.name }}_acados_get_nlp_opts();
// initial condition
int idxbx0[{{ dims.nbx_0 }}];
{% for i in range(end=dims.nbx_0) %}
idxbx0[{{ i }}] = {{ constraints.idxbx_0[i] }};
{%- endfor %}
double lbx0[{{ dims.nbx_0 }}];
double ubx0[{{ dims.nbx_0 }}];
{% for i in range(end=dims.nbx_0) %}
lbx0[{{ i }}] = {{ constraints.lbx_0[i] }};
ubx0[{{ i }}] = {{ constraints.ubx_0[i] }};
{%- endfor %}
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, 0, "idxbx", idxbx0);
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, 0, "lbx", lbx0);
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, 0, "ubx", ubx0);
// initialization for state values
double x_init[{{ dims.nx }}];
{%- for i in range(end=dims.nx) %}
x_init[{{ i }}] = 0.0;
{%- endfor %}
// initial value for control input
double u0[{{ dims.nu }}];
{%- for i in range(end=dims.nu) %}
u0[{{ i }}] = 0.0;
{%- endfor %}
// prepare evaluation
int NTIMINGS = 10;
double min_time = 1e12;
double kkt_norm_inf;
double elapsed_time;
int sqp_iter;
double xtraj[{{ dims.nx }} * ({{ dims.N }}+1)];
double utraj[{{ dims.nu }} * ({{ dims.N }})];
// solve ocp in loop
for (int ii = 0; ii < NTIMINGS; ii++)
{
// initialize primal solution
for (int i = 0; i <= nlp_dims->N; i++)
{
ocp_nlp_out_set(nlp_config, nlp_dims, nlp_out, i, "x", x_init);
ocp_nlp_out_set(nlp_config, nlp_dims, nlp_out, i, "u", u0);
}
status = {{ model.name }}_acados_solve();
ocp_nlp_get(nlp_config, nlp_solver, "time_tot", &elapsed_time);
min_time = MIN(elapsed_time, min_time);
}
/* print solution and statistics */
for (int ii = 0; ii <= nlp_dims->N; ii++)
ocp_nlp_out_get(nlp_config, nlp_dims, nlp_out, ii, "x", &xtraj[ii*{{ dims.nx }}]);
for (int ii = 0; ii < nlp_dims->N; ii++)
ocp_nlp_out_get(nlp_config, nlp_dims, nlp_out, ii, "u", &utraj[ii*{{ dims.nu }}]);
mexPrintf("\n--- xtraj ---\n");
MEX_print_exp_tran_mat( {{ dims.nx }}, {{ dims.N }}+1, xtraj, {{ dims.nx }} );
mexPrintf("\n--- utraj ---\n");
MEX_print_exp_tran_mat( {{ dims.nu }}, {{ dims.N }}, utraj, {{ dims.nu }} );
mexPrintf("\nsolved ocp %d times, solution printed above\n\n", NTIMINGS);
if (status == ACADOS_SUCCESS)
mexPrintf("{{ model.name }}_acados_solve(): SUCCESS!\n");
else
mexPrintf("{{ model.name }}_acados_solve() failed with status %d.\n", status);
// get solution
ocp_nlp_out_get(nlp_config, nlp_dims, nlp_out, 0, "kkt_norm_inf", &kkt_norm_inf);
ocp_nlp_get(nlp_config, nlp_solver, "sqp_iter", &sqp_iter);
mexPrintf("\nSolver info:\n");
mexPrintf(" SQP iterations %2d\n minimum time for 1 solve %f [ms]\n KKT %e\n",
sqp_iter, min_time*1000, kkt_norm_inf);
// free solver
status = {{ model.name }}_acados_free();
if (status)
{
mexPrintf("{{ model.name }}_acados_free() returned status %d.\n", status);
}
return;
}
@@ -0,0 +1,135 @@
/*
* Copyright 2019 Gianluca Frison, Dimitris Kouzoupis, Robin Verschueren,
* Andrea Zanelli, Niels van Duijkeren, Jonathan Frey, Tommaso Sartor,
* Branimir Novoselnik, Rien Quirynen, Rezart Qelibari, Dang Doan,
* Jonas Koenemann, Yutao Chen, Tobias Schöls, Jonas Schlagenhauf, Moritz Diehl
*
* This file is part of acados.
*
* The 2-Clause BSD License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.;
*/
// standard
#include <stdio.h>
#include <stdlib.h>
// acados
#include "acados/utils/print.h"
#include "acados/utils/math.h"
#include "acados_c/sim_interface.h"
#include "acados_sim_solver_{{ model.name }}.h"
#define NX {{ model.name | upper }}_NX
#define NZ {{ model.name | upper }}_NZ
#define NU {{ model.name | upper }}_NU
#define NP {{ model.name | upper }}_NP
int main()
{
int status = 0;
sim_solver_capsule *capsule = {{ model.name }}_acados_sim_solver_create_capsule();
status = {{ model.name }}_acados_sim_create(capsule);
if (status)
{
printf("acados_create() returned status %d. Exiting.\n", status);
exit(1);
}
sim_config *acados_sim_config = {{ model.name }}_acados_get_sim_config(capsule);
sim_in *acados_sim_in = {{ model.name }}_acados_get_sim_in(capsule);
sim_out *acados_sim_out = {{ model.name }}_acados_get_sim_out(capsule);
void *acados_sim_dims = {{ model.name }}_acados_get_sim_dims(capsule);
// initial condition
double x_current[NX];
{%- for i in range(end=dims.nx) %}
x_current[{{ i }}] = 0.0;
{%- endfor %}
{% if constraints.lbx_0 %}
{%- for i in range(end=dims.nbx_0) %}
x_current[{{ constraints.idxbx_0[i] }}] = {{ constraints.lbx_0[i] }};
{%- endfor %}
{% if dims.nbx_0 != dims.nx %}
printf("main_sim: NOTE: initial state not fully defined via lbx_0, using 0.0 for indices that are not in idxbx_0.");
{%- endif %}
{% else %}
printf("main_sim: initial state not defined, should be in lbx_0, using zero vector.");
{%- endif %}
// initial value for control input
double u0[NU];
{%- for i in range(end=dims.nu) %}
u0[{{ i }}] = 0.0;
{%- endfor %}
{%- if dims.np > 0 %}
// set parameters
double p[NP];
{%- for item in parameter_values %}
p[{{ loop.index0 }}] = {{ item }};
{%- endfor %}
{{ model.name }}_acados_sim_update_params(capsule, p, NP);
{% endif %}{# if np > 0 #}
int n_sim_steps = 3;
// solve ocp in loop
for (int ii = 0; ii < n_sim_steps; ii++)
{
sim_in_set(acados_sim_config, acados_sim_dims,
acados_sim_in, "x", x_current);
status = {{ model.name }}_acados_sim_solve(capsule);
if (status != ACADOS_SUCCESS)
{
printf("acados_solve() failed with status %d.\n", status);
}
sim_out_get(acados_sim_config, acados_sim_dims,
acados_sim_out, "x", x_current);
printf("\nx_current, %d\n", ii);
for (int jj = 0; jj < NX; jj++)
{
printf("%e\n", x_current[jj]);
}
}
printf("\nPerformed %d simulation steps with acados integrator successfully.\n\n", n_sim_steps);
// free solver
status = {{ model.name }}_acados_sim_free(capsule);
if (status) {
printf("{{ model.name }}_acados_sim_free() returned status %d. \n", status);
}
{{ model.name }}_acados_sim_solver_free_capsule(capsule);
return status;
}
-1
View File
@@ -1 +0,0 @@
/data/openpilot/third_party/acados/larch64/lib
Binary file not shown.
Binary file not shown.
+218
View File
@@ -0,0 +1,218 @@
//
// C++ standalone verion of fastcluster by Daniel Müllner
//
// Copyright: Christoph Dalitz, 2018
// Daniel Müllner, 2011
// License: BSD style license
// (see the file LICENSE for details)
//
#include <vector>
#include <algorithm>
#include <cmath>
extern "C" {
#include "fastcluster.h"
}
// Code by Daniel Müllner
// workaround to make it usable as a standalone version (without R)
bool fc_isnan(double x) { return false; }
#include "fastcluster_dm.cpp"
#include "fastcluster_R_dm.cpp"
extern "C" {
//
// Assigns cluster labels (0, ..., nclust-1) to the n points such
// that the cluster result is split into nclust clusters.
//
// Input arguments:
// n = number of observables
// merge = clustering result in R format
// nclust = number of clusters
// Output arguments:
// labels = allocated integer array of size n for result
//
void cutree_k(int n, const int* merge, int nclust, int* labels) {
int k,m1,m2,j,l;
if (nclust > n || nclust < 2) {
for (j=0; j<n; j++) labels[j] = 0;
return;
}
// assign to each observable the number of its last merge step
// beware: indices of observables in merge start at 1 (R convention)
std::vector<int> last_merge(n, 0);
for (k=1; k<=(n-nclust); k++) {
// (m1,m2) = merge[k,]
m1 = merge[k-1];
m2 = merge[n-1+k-1];
if (m1 < 0 && m2 < 0) { // both single observables
last_merge[-m1-1] = last_merge[-m2-1] = k;
}
else if (m1 < 0 || m2 < 0) { // one is a cluster
if(m1 < 0) { j = -m1; m1 = m2; } else j = -m2;
// merging single observable and cluster
for(l = 0; l < n; l++)
if (last_merge[l] == m1)
last_merge[l] = k;
last_merge[j-1] = k;
}
else { // both cluster
for(l=0; l < n; l++) {
if( last_merge[l] == m1 || last_merge[l] == m2 )
last_merge[l] = k;
}
}
}
// assign cluster labels
int label = 0;
std::vector<int> z(n,-1);
for (j=0; j<n; j++) {
if (last_merge[j] == 0) { // still singleton
labels[j] = label++;
} else {
if (z[last_merge[j]] < 0) {
z[last_merge[j]] = label++;
}
labels[j] = z[last_merge[j]];
}
}
}
//
// Assigns cluster labels (0, ..., nclust-1) to the n points such
// that the hierarchical clustering is stopped when cluster distance >= cdist
//
// Input arguments:
// n = number of observables
// merge = clustering result in R format
// height = cluster distance at each merge step
// cdist = cutoff cluster distance
// Output arguments:
// labels = allocated integer array of size n for result
//
void cutree_cdist(int n, const int* merge, double* height, double cdist, int* labels) {
int k;
for (k=0; k<(n-1); k++) {
if (height[k] >= cdist) {
break;
}
}
cutree_k(n, merge, n-k, labels);
}
//
// Hierarchical clustering with one of Daniel Muellner's fast algorithms
//
// Input arguments:
// n = number of observables
// distmat = condensed distance matrix, i.e. an n*(n-1)/2 array representing
// the upper triangle (without diagonal elements) of the distance
// matrix, e.g. for n=4:
// d00 d01 d02 d03
// d10 d11 d12 d13 -> d01 d02 d03 d12 d13 d23
// d20 d21 d22 d23
// d30 d31 d32 d33
// method = cluster metric (see enum method_code)
// Output arguments:
// merge = allocated (n-1)x2 matrix (2*(n-1) array) for storing result.
// Result follows R hclust convention:
// - observabe indices start with one
// - merge[i][] contains the merged nodes in step i
// - merge[i][j] is negative when the node is an atom
// height = allocated (n-1) array with distances at each merge step
// Return code:
// 0 = ok
// 1 = invalid method
//
int hclust_fast(int n, double* distmat, int method, int* merge, double* height) {
// call appropriate culstering function
cluster_result Z2(n-1);
if (method == HCLUST_METHOD_SINGLE) {
// single link
MST_linkage_core(n, distmat, Z2);
}
else if (method == HCLUST_METHOD_COMPLETE) {
// complete link
NN_chain_core<METHOD_METR_COMPLETE, t_float>(n, distmat, NULL, Z2);
}
else if (method == HCLUST_METHOD_AVERAGE) {
// best average distance
double* members = new double[n];
for (int i=0; i<n; i++) members[i] = 1;
NN_chain_core<METHOD_METR_AVERAGE, t_float>(n, distmat, members, Z2);
delete[] members;
}
else if (method == HCLUST_METHOD_MEDIAN) {
// best median distance (beware: O(n^3))
generic_linkage<METHOD_METR_MEDIAN, t_float>(n, distmat, NULL, Z2);
}
else if (method == HCLUST_METHOD_CENTROID) {
// best centroid distance (beware: O(n^3))
double* members = new double[n];
for (int i=0; i<n; i++) members[i] = 1;
generic_linkage<METHOD_METR_CENTROID, t_float>(n, distmat, members, Z2);
delete[] members;
}
else {
return 1;
}
int* order = new int[n];
if (method == HCLUST_METHOD_MEDIAN || method == HCLUST_METHOD_CENTROID) {
generate_R_dendrogram<true>(merge, height, order, Z2, n);
} else {
generate_R_dendrogram<false>(merge, height, order, Z2, n);
}
delete[] order; // only needed for visualization
return 0;
}
// Build condensed distance matrix
// Input arguments:
// n = number of observables
// m = dimension of observable
// Output arguments:
// out = allocated integer array of size n * (n - 1) / 2 for result
void hclust_pdist(int n, int m, double* pts, double* out) {
int ii = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
// Compute euclidian distance
double d = 0;
for (int k = 0; k < m; k ++) {
double error = pts[i * m + k] - pts[j * m + k];
d += (error * error);
}
out[ii] = d;//sqrt(d);
ii++;
}
}
}
void cluster_points_centroid(int n, int m, double* pts, double dist, int* idx) {
double* pdist = new double[n * (n - 1) / 2];
int* merge = new int[2 * (n - 1)];
double* height = new double[n - 1];
hclust_pdist(n, m, pts, pdist);
hclust_fast(n, pdist, HCLUST_METHOD_CENTROID, merge, height);
cutree_cdist(n, merge, height, dist, idx);
delete[] pdist;
delete[] merge;
delete[] height;
}
}
Binary file not shown.
+115
View File
@@ -0,0 +1,115 @@
//
// Excerpt from fastcluster_R.cpp
//
// Copyright: Daniel Müllner, 2011 <http://danifold.net>
//
struct pos_node {
t_index pos;
int node;
};
void order_nodes(const int N, const int * const merge, const t_index * const node_size, int * const order) {
/* Parameters:
N : number of data points
merge : (N-1)×2 array which specifies the node indices which are
merged in each step of the clustering procedure.
Negative entries -1...-N point to singleton nodes, while
positive entries 1...(N-1) point to nodes which are themselves
parents of other nodes.
node_size : array of node sizes - makes it easier
order : output array of size N
Runtime: Θ(N)
*/
auto_array_ptr<pos_node> queue(N/2);
int parent;
int child;
t_index pos = 0;
queue[0].pos = 0;
queue[0].node = N-2;
t_index idx = 1;
do {
--idx;
pos = queue[idx].pos;
parent = queue[idx].node;
// First child
child = merge[parent];
if (child<0) { // singleton node, write this into the 'order' array.
order[pos] = -child;
++pos;
}
else { /* compound node: put it on top of the queue and decompose it
in a later iteration. */
queue[idx].pos = pos;
queue[idx].node = child-1; // convert index-1 based to index-0 based
++idx;
pos += node_size[child-1];
}
// Second child
child = merge[parent+N-1];
if (child<0) {
order[pos] = -child;
}
else {
queue[idx].pos = pos;
queue[idx].node = child-1;
++idx;
}
} while (idx>0);
}
#define size_(r_) ( ((r_<N) ? 1 : node_size[r_-N]) )
template <const bool sorted>
void generate_R_dendrogram(int * const merge, double * const height, int * const order, cluster_result & Z2, const int N) {
// The array "nodes" is a union-find data structure for the cluster
// identites (only needed for unsorted cluster_result input).
union_find nodes(sorted ? 0 : N);
if (!sorted) {
std::stable_sort(Z2[0], Z2[N-1]);
}
t_index node1, node2;
auto_array_ptr<t_index> node_size(N-1);
for (t_index i=0; i<N-1; ++i) {
// Get two data points whose clusters are merged in step i.
// Find the cluster identifiers for these points.
if (sorted) {
node1 = Z2[i]->node1;
node2 = Z2[i]->node2;
}
else {
node1 = nodes.Find(Z2[i]->node1);
node2 = nodes.Find(Z2[i]->node2);
// Merge the nodes in the union-find data structure by making them
// children of a new node.
nodes.Union(node1, node2);
}
// Sort the nodes in the output array.
if (node1>node2) {
t_index tmp = node1;
node1 = node2;
node2 = tmp;
}
/* Conversion between labeling conventions.
Input: singleton nodes 0,...,N-1
compound nodes N,...,2N-2
Output: singleton nodes -1,...,-N
compound nodes 1,...,N
*/
merge[i] = (node1<N) ? -static_cast<int>(node1)-1
: static_cast<int>(node1)-N+1;
merge[i+N-1] = (node2<N) ? -static_cast<int>(node2)-1
: static_cast<int>(node2)-N+1;
height[i] = Z2[i]->dist;
node_size[i] = size_(node1) + size_(node2);
}
order_nodes(N, merge, node_size, order);
}
File diff suppressed because it is too large Load Diff
+35
View File
@@ -0,0 +1,35 @@
#include <cassert>
extern "C" {
#include "fastcluster.h"
}
int main(int argc, const char* argv[]) {
const int n = 11;
const int m = 3;
double* pts = new double[n*m]{59.26000137, -9.35999966, -5.42500019,
91.61999817, -0.31999999, -2.75,
31.38000031, 0.40000001, -0.2,
89.57999725, -8.07999992, -18.04999924,
53.42000122, 0.63999999, -0.175,
31.38000031, 0.47999999, -0.2,
36.33999939, 0.16, -0.2,
53.33999939, 0.95999998, -0.175,
59.26000137, -9.76000023, -5.44999981,
33.93999977, 0.40000001, -0.22499999,
106.74000092, -5.76000023, -18.04999924};
int * idx = new int[n];
int * correct_idx = new int[n]{0, 1, 2, 3, 4, 2, 5, 4, 0, 5, 6};
cluster_points_centroid(n, m, pts, 2.5 * 2.5, idx);
for (int i = 0; i < n; i++) {
assert(idx[i] == correct_idx[i]);
}
delete[] idx;
delete[] correct_idx;
delete[] pts;
}
+784
View File
@@ -0,0 +1,784 @@
/* Copyright (c) 2013 Dropbox, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "json11.hpp"
#include <cassert>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <limits>
namespace json11 {
static const int max_depth = 200;
using std::string;
using std::vector;
using std::map;
using std::make_shared;
using std::initializer_list;
using std::move;
/* Helper for representing null - just a do-nothing struct, plus comparison
* operators so the helpers in JsonValue work. We can't use nullptr_t because
* it may not be orderable.
*/
struct NullStruct {
bool operator==(NullStruct) const { return true; }
bool operator<(NullStruct) const { return false; }
};
/* * * * * * * * * * * * * * * * * * * *
* Serialization
*/
static void dump(NullStruct, string &out) {
out += "null";
}
static void dump(double value, string &out) {
if (std::isfinite(value)) {
char buf[32];
snprintf(buf, sizeof buf, "%.17g", value);
out += buf;
} else {
out += "null";
}
}
static void dump(int value, string &out) {
char buf[32];
snprintf(buf, sizeof buf, "%d", value);
out += buf;
}
static void dump(bool value, string &out) {
out += value ? "true" : "false";
}
static void dump(const string &value, string &out) {
out += '"';
for (size_t i = 0; i < value.length(); i++) {
const char ch = value[i];
if (ch == '\\') {
out += "\\\\";
} else if (ch == '"') {
out += "\\\"";
} else if (ch == '\b') {
out += "\\b";
} else if (ch == '\f') {
out += "\\f";
} else if (ch == '\n') {
out += "\\n";
} else if (ch == '\r') {
out += "\\r";
} else if (ch == '\t') {
out += "\\t";
} else if (static_cast<uint8_t>(ch) <= 0x1f) {
char buf[8];
snprintf(buf, sizeof buf, "\\u%04x", ch);
out += buf;
} else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80
&& static_cast<uint8_t>(value[i+2]) == 0xa8) {
out += "\\u2028";
i += 2;
} else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80
&& static_cast<uint8_t>(value[i+2]) == 0xa9) {
out += "\\u2029";
i += 2;
} else {
out += ch;
}
}
out += '"';
}
static void dump(const Json::array &values, string &out) {
bool first = true;
out += "[";
for (const auto &value : values) {
if (!first)
out += ", ";
value.dump(out);
first = false;
}
out += "]";
}
static void dump(const Json::object &values, string &out) {
bool first = true;
out += "{";
for (const auto &kv : values) {
if (!first)
out += ", ";
dump(kv.first, out);
out += ": ";
kv.second.dump(out);
first = false;
}
out += "}";
}
void Json::dump(string &out) const {
m_ptr->dump(out);
}
/* * * * * * * * * * * * * * * * * * * *
* Value wrappers
*/
template <Json::Type tag, typename T>
class Value : public JsonValue {
protected:
// Constructors
explicit Value(const T &value) : m_value(value) {}
explicit Value(T &&value) : m_value(move(value)) {}
// Get type tag
Json::Type type() const override {
return tag;
}
// Comparisons
bool equals(const JsonValue * other) const override {
return m_value == static_cast<const Value<tag, T> *>(other)->m_value;
}
bool less(const JsonValue * other) const override {
return m_value < static_cast<const Value<tag, T> *>(other)->m_value;
}
const T m_value;
void dump(string &out) const override { json11::dump(m_value, out); }
};
class JsonDouble final : public Value<Json::NUMBER, double> {
double number_value() const override { return m_value; }
int int_value() const override { return static_cast<int>(m_value); }
bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
bool less(const JsonValue * other) const override { return m_value < other->number_value(); }
public:
explicit JsonDouble(double value) : Value(value) {}
};
class JsonInt final : public Value<Json::NUMBER, int> {
double number_value() const override { return m_value; }
int int_value() const override { return m_value; }
bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
bool less(const JsonValue * other) const override { return m_value < other->number_value(); }
public:
explicit JsonInt(int value) : Value(value) {}
};
class JsonBoolean final : public Value<Json::BOOL, bool> {
bool bool_value() const override { return m_value; }
public:
explicit JsonBoolean(bool value) : Value(value) {}
};
class JsonString final : public Value<Json::STRING, string> {
const string &string_value() const override { return m_value; }
public:
explicit JsonString(const string &value) : Value(value) {}
explicit JsonString(string &&value) : Value(move(value)) {}
};
class JsonArray final : public Value<Json::ARRAY, Json::array> {
const Json::array &array_items() const override { return m_value; }
const Json & operator[](size_t i) const override;
public:
explicit JsonArray(const Json::array &value) : Value(value) {}
explicit JsonArray(Json::array &&value) : Value(move(value)) {}
};
class JsonObject final : public Value<Json::OBJECT, Json::object> {
const Json::object &object_items() const override { return m_value; }
const Json & operator[](const string &key) const override;
public:
explicit JsonObject(const Json::object &value) : Value(value) {}
explicit JsonObject(Json::object &&value) : Value(move(value)) {}
};
class JsonNull final : public Value<Json::NUL, NullStruct> {
public:
JsonNull() : Value({}) {}
};
/* * * * * * * * * * * * * * * * * * * *
* Static globals - static-init-safe
*/
struct Statics {
const std::shared_ptr<JsonValue> null = make_shared<JsonNull>();
const std::shared_ptr<JsonValue> t = make_shared<JsonBoolean>(true);
const std::shared_ptr<JsonValue> f = make_shared<JsonBoolean>(false);
const string empty_string;
const vector<Json> empty_vector;
const map<string, Json> empty_map;
Statics() {}
};
static const Statics & statics() {
static const Statics s {};
return s;
}
static const Json & static_null() {
// This has to be separate, not in Statics, because Json() accesses statics().null.
static const Json json_null;
return json_null;
}
/* * * * * * * * * * * * * * * * * * * *
* Constructors
*/
Json::Json() noexcept : m_ptr(statics().null) {}
Json::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {}
Json::Json(double value) : m_ptr(make_shared<JsonDouble>(value)) {}
Json::Json(int value) : m_ptr(make_shared<JsonInt>(value)) {}
Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {}
Json::Json(const string &value) : m_ptr(make_shared<JsonString>(value)) {}
Json::Json(string &&value) : m_ptr(make_shared<JsonString>(move(value))) {}
Json::Json(const char * value) : m_ptr(make_shared<JsonString>(value)) {}
Json::Json(const Json::array &values) : m_ptr(make_shared<JsonArray>(values)) {}
Json::Json(Json::array &&values) : m_ptr(make_shared<JsonArray>(move(values))) {}
Json::Json(const Json::object &values) : m_ptr(make_shared<JsonObject>(values)) {}
Json::Json(Json::object &&values) : m_ptr(make_shared<JsonObject>(move(values))) {}
/* * * * * * * * * * * * * * * * * * * *
* Accessors
*/
Json::Type Json::type() const { return m_ptr->type(); }
double Json::number_value() const { return m_ptr->number_value(); }
int Json::int_value() const { return m_ptr->int_value(); }
bool Json::bool_value() const { return m_ptr->bool_value(); }
const string & Json::string_value() const { return m_ptr->string_value(); }
const vector<Json> & Json::array_items() const { return m_ptr->array_items(); }
const map<string, Json> & Json::object_items() const { return m_ptr->object_items(); }
const Json & Json::operator[] (size_t i) const { return (*m_ptr)[i]; }
const Json & Json::operator[] (const string &key) const { return (*m_ptr)[key]; }
double JsonValue::number_value() const { return 0; }
int JsonValue::int_value() const { return 0; }
bool JsonValue::bool_value() const { return false; }
const string & JsonValue::string_value() const { return statics().empty_string; }
const vector<Json> & JsonValue::array_items() const { return statics().empty_vector; }
const map<string, Json> & JsonValue::object_items() const { return statics().empty_map; }
const Json & JsonValue::operator[] (size_t) const { return static_null(); }
const Json & JsonValue::operator[] (const string &) const { return static_null(); }
const Json & JsonObject::operator[] (const string &key) const {
auto iter = m_value.find(key);
return (iter == m_value.end()) ? static_null() : iter->second;
}
const Json & JsonArray::operator[] (size_t i) const {
if (i >= m_value.size()) return static_null();
else return m_value[i];
}
/* * * * * * * * * * * * * * * * * * * *
* Comparison
*/
bool Json::operator== (const Json &other) const {
if (m_ptr->type() != other.m_ptr->type())
return false;
return m_ptr->equals(other.m_ptr.get());
}
bool Json::operator< (const Json &other) const {
if (m_ptr->type() != other.m_ptr->type())
return m_ptr->type() < other.m_ptr->type();
return m_ptr->less(other.m_ptr.get());
}
/* * * * * * * * * * * * * * * * * * * *
* Parsing
*/
/* esc(c)
*
* Format char c suitable for printing in an error message.
*/
static inline string esc(char c) {
char buf[12];
if (static_cast<uint8_t>(c) >= 0x20 && static_cast<uint8_t>(c) <= 0x7f) {
snprintf(buf, sizeof buf, "'%c' (%d)", c, c);
} else {
snprintf(buf, sizeof buf, "(%d)", c);
}
return string(buf);
}
static inline bool in_range(long x, long lower, long upper) {
return (x >= lower && x <= upper);
}
namespace {
/* JsonParser
*
* Object that tracks all state of an in-progress parse.
*/
struct JsonParser final {
/* State
*/
const string &str;
size_t i;
string &err;
bool failed;
const JsonParse strategy;
/* fail(msg, err_ret = Json())
*
* Mark this parse as failed.
*/
Json fail(string &&msg) {
return fail(move(msg), Json());
}
template <typename T>
T fail(string &&msg, const T err_ret) {
if (!failed)
err = std::move(msg);
failed = true;
return err_ret;
}
/* consume_whitespace()
*
* Advance until the current character is non-whitespace.
*/
void consume_whitespace() {
while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t')
i++;
}
/* consume_comment()
*
* Advance comments (c-style inline and multiline).
*/
bool consume_comment() {
bool comment_found = false;
if (str[i] == '/') {
i++;
if (i == str.size())
return fail("unexpected end of input after start of comment", false);
if (str[i] == '/') { // inline comment
i++;
// advance until next line, or end of input
while (i < str.size() && str[i] != '\n') {
i++;
}
comment_found = true;
}
else if (str[i] == '*') { // multiline comment
i++;
if (i > str.size()-2)
return fail("unexpected end of input inside multi-line comment", false);
// advance until closing tokens
while (!(str[i] == '*' && str[i+1] == '/')) {
i++;
if (i > str.size()-2)
return fail(
"unexpected end of input inside multi-line comment", false);
}
i += 2;
comment_found = true;
}
else
return fail("malformed comment", false);
}
return comment_found;
}
/* consume_garbage()
*
* Advance until the current character is non-whitespace and non-comment.
*/
void consume_garbage() {
consume_whitespace();
if(strategy == JsonParse::COMMENTS) {
bool comment_found = false;
do {
comment_found = consume_comment();
if (failed) return;
consume_whitespace();
}
while(comment_found);
}
}
/* get_next_token()
*
* Return the next non-whitespace character. If the end of the input is reached,
* flag an error and return 0.
*/
char get_next_token() {
consume_garbage();
if (failed) return (char)0;
if (i == str.size())
return fail("unexpected end of input", (char)0);
return str[i++];
}
/* encode_utf8(pt, out)
*
* Encode pt as UTF-8 and add it to out.
*/
void encode_utf8(long pt, string & out) {
if (pt < 0)
return;
if (pt < 0x80) {
out += static_cast<char>(pt);
} else if (pt < 0x800) {
out += static_cast<char>((pt >> 6) | 0xC0);
out += static_cast<char>((pt & 0x3F) | 0x80);
} else if (pt < 0x10000) {
out += static_cast<char>((pt >> 12) | 0xE0);
out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
out += static_cast<char>((pt & 0x3F) | 0x80);
} else {
out += static_cast<char>((pt >> 18) | 0xF0);
out += static_cast<char>(((pt >> 12) & 0x3F) | 0x80);
out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
out += static_cast<char>((pt & 0x3F) | 0x80);
}
}
/* parse_string()
*
* Parse a string, starting at the current position.
*/
string parse_string() {
string out;
long last_escaped_codepoint = -1;
while (true) {
if (i == str.size())
return fail("unexpected end of input in string", "");
char ch = str[i++];
if (ch == '"') {
encode_utf8(last_escaped_codepoint, out);
return out;
}
if (in_range(ch, 0, 0x1f))
return fail("unescaped " + esc(ch) + " in string", "");
// The usual case: non-escaped characters
if (ch != '\\') {
encode_utf8(last_escaped_codepoint, out);
last_escaped_codepoint = -1;
out += ch;
continue;
}
// Handle escapes
if (i == str.size())
return fail("unexpected end of input in string", "");
ch = str[i++];
if (ch == 'u') {
// Extract 4-byte escape sequence
string esc = str.substr(i, 4);
// Explicitly check length of the substring. The following loop
// relies on std::string returning the terminating NUL when
// accessing str[length]. Checking here reduces brittleness.
if (esc.length() < 4) {
return fail("bad \\u escape: " + esc, "");
}
for (size_t j = 0; j < 4; j++) {
if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F')
&& !in_range(esc[j], '0', '9'))
return fail("bad \\u escape: " + esc, "");
}
long codepoint = strtol(esc.data(), nullptr, 16);
// JSON specifies that characters outside the BMP shall be encoded as a pair
// of 4-hex-digit \u escapes encoding their surrogate pair components. Check
// whether we're in the middle of such a beast: the previous codepoint was an
// escaped lead (high) surrogate, and this is a trail (low) surrogate.
if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF)
&& in_range(codepoint, 0xDC00, 0xDFFF)) {
// Reassemble the two surrogate pairs into one astral-plane character, per
// the UTF-16 algorithm.
encode_utf8((((last_escaped_codepoint - 0xD800) << 10)
| (codepoint - 0xDC00)) + 0x10000, out);
last_escaped_codepoint = -1;
} else {
encode_utf8(last_escaped_codepoint, out);
last_escaped_codepoint = codepoint;
}
i += 4;
continue;
}
encode_utf8(last_escaped_codepoint, out);
last_escaped_codepoint = -1;
if (ch == 'b') {
out += '\b';
} else if (ch == 'f') {
out += '\f';
} else if (ch == 'n') {
out += '\n';
} else if (ch == 'r') {
out += '\r';
} else if (ch == 't') {
out += '\t';
} else if (ch == '"' || ch == '\\' || ch == '/') {
out += ch;
} else {
return fail("invalid escape character " + esc(ch), "");
}
}
}
/* parse_number()
*
* Parse a double.
*/
Json parse_number() {
size_t start_pos = i;
if (str[i] == '-')
i++;
// Integer part
if (str[i] == '0') {
i++;
if (in_range(str[i], '0', '9'))
return fail("leading 0s not permitted in numbers");
} else if (in_range(str[i], '1', '9')) {
i++;
while (in_range(str[i], '0', '9'))
i++;
} else {
return fail("invalid " + esc(str[i]) + " in number");
}
if (str[i] != '.' && str[i] != 'e' && str[i] != 'E'
&& (i - start_pos) <= static_cast<size_t>(std::numeric_limits<int>::digits10)) {
return std::atoi(str.c_str() + start_pos);
}
// Decimal part
if (str[i] == '.') {
i++;
if (!in_range(str[i], '0', '9'))
return fail("at least one digit required in fractional part");
while (in_range(str[i], '0', '9'))
i++;
}
// Exponent part
if (str[i] == 'e' || str[i] == 'E') {
i++;
if (str[i] == '+' || str[i] == '-')
i++;
if (!in_range(str[i], '0', '9'))
return fail("at least one digit required in exponent");
while (in_range(str[i], '0', '9'))
i++;
}
return std::strtod(str.c_str() + start_pos, nullptr);
}
/* expect(str, res)
*
* Expect that 'str' starts at the character that was just read. If it does, advance
* the input and return res. If not, flag an error.
*/
Json expect(const string &expected, Json res) {
assert(i != 0);
i--;
if (str.compare(i, expected.length(), expected) == 0) {
i += expected.length();
return res;
} else {
return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length()));
}
}
/* parse_json()
*
* Parse a JSON object.
*/
Json parse_json(int depth) {
if (depth > max_depth) {
return fail("exceeded maximum nesting depth");
}
char ch = get_next_token();
if (failed)
return Json();
if (ch == '-' || (ch >= '0' && ch <= '9')) {
i--;
return parse_number();
}
if (ch == 't')
return expect("true", true);
if (ch == 'f')
return expect("false", false);
if (ch == 'n')
return expect("null", Json());
if (ch == '"')
return parse_string();
if (ch == '{') {
map<string, Json> data;
ch = get_next_token();
if (ch == '}')
return data;
while (1) {
if (ch != '"')
return fail("expected '\"' in object, got " + esc(ch));
string key = parse_string();
if (failed)
return Json();
ch = get_next_token();
if (ch != ':')
return fail("expected ':' in object, got " + esc(ch));
data[std::move(key)] = parse_json(depth + 1);
if (failed)
return Json();
ch = get_next_token();
if (ch == '}')
break;
if (ch != ',')
return fail("expected ',' in object, got " + esc(ch));
ch = get_next_token();
}
return data;
}
if (ch == '[') {
vector<Json> data;
ch = get_next_token();
if (ch == ']')
return data;
while (1) {
i--;
data.push_back(parse_json(depth + 1));
if (failed)
return Json();
ch = get_next_token();
if (ch == ']')
break;
if (ch != ',')
return fail("expected ',' in list, got " + esc(ch));
ch = get_next_token();
(void)ch;
}
return data;
}
return fail("expected value, got " + esc(ch));
}
};
}//namespace {
Json Json::parse(const string &in, string &err, JsonParse strategy) {
JsonParser parser { in, 0, err, false, strategy };
Json result = parser.parse_json(0);
// Check for any trailing garbage
parser.consume_garbage();
if (parser.failed)
return Json();
if (parser.i != in.size())
return parser.fail("unexpected trailing " + esc(in[parser.i]));
return result;
}
// Documented in json11.hpp
vector<Json> Json::parse_multi(const string &in,
std::string::size_type &parser_stop_pos,
string &err,
JsonParse strategy) {
JsonParser parser { in, 0, err, false, strategy };
parser_stop_pos = 0;
vector<Json> json_vec;
while (parser.i != in.size() && !parser.failed) {
json_vec.push_back(parser.parse_json(0));
if (parser.failed)
break;
// Check for another object
parser.consume_garbage();
if (parser.failed)
break;
parser_stop_pos = parser.i;
}
return json_vec;
}
/* * * * * * * * * * * * * * * * * * * *
* Shape-checking
*/
bool Json::has_shape(const shape & types, string & err) const {
if (!is_object()) {
err = "expected JSON object, got " + dump();
return false;
}
for (auto & item : types) {
if ((*this)[item.first].type() != item.second) {
err = "bad type for " + item.first + " in " + dump();
return false;
}
}
return true;
}
} // namespace json11
+689
View File
@@ -0,0 +1,689 @@
#include <kaitai/kaitaistream.h>
#if defined(__APPLE__)
#include <machine/endian.h>
#include <libkern/OSByteOrder.h>
#define bswap_16(x) OSSwapInt16(x)
#define bswap_32(x) OSSwapInt32(x)
#define bswap_64(x) OSSwapInt64(x)
#define __BYTE_ORDER BYTE_ORDER
#define __BIG_ENDIAN BIG_ENDIAN
#define __LITTLE_ENDIAN LITTLE_ENDIAN
#elif defined(_MSC_VER) // !__APPLE__
#include <stdlib.h>
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
#define __BYTE_ORDER __LITTLE_ENDIAN
#define bswap_16(x) _byteswap_ushort(x)
#define bswap_32(x) _byteswap_ulong(x)
#define bswap_64(x) _byteswap_uint64(x)
#else // !__APPLE__ or !_MSC_VER
#include <endian.h>
#include <byteswap.h>
#endif
#include <iostream>
#include <vector>
#include <stdexcept>
kaitai::kstream::kstream(std::istream* io) {
m_io = io;
init();
}
kaitai::kstream::kstream(std::string& data): m_io_str(data) {
m_io = &m_io_str;
init();
}
void kaitai::kstream::init() {
exceptions_enable();
align_to_byte();
}
void kaitai::kstream::close() {
// m_io->close();
}
void kaitai::kstream::exceptions_enable() const {
m_io->exceptions(
std::istream::eofbit |
std::istream::failbit |
std::istream::badbit
);
}
// ========================================================================
// Stream positioning
// ========================================================================
bool kaitai::kstream::is_eof() const {
if (m_bits_left > 0) {
return false;
}
char t;
m_io->exceptions(
std::istream::badbit
);
m_io->get(t);
if (m_io->eof()) {
m_io->clear();
exceptions_enable();
return true;
} else {
m_io->unget();
exceptions_enable();
return false;
}
}
void kaitai::kstream::seek(uint64_t pos) {
m_io->seekg(pos);
}
uint64_t kaitai::kstream::pos() {
return m_io->tellg();
}
uint64_t kaitai::kstream::size() {
std::iostream::pos_type cur_pos = m_io->tellg();
m_io->seekg(0, std::ios::end);
std::iostream::pos_type len = m_io->tellg();
m_io->seekg(cur_pos);
return len;
}
// ========================================================================
// Integer numbers
// ========================================================================
// ------------------------------------------------------------------------
// Signed
// ------------------------------------------------------------------------
int8_t kaitai::kstream::read_s1() {
char t;
m_io->get(t);
return t;
}
// ........................................................................
// Big-endian
// ........................................................................
int16_t kaitai::kstream::read_s2be() {
int16_t t;
m_io->read(reinterpret_cast<char *>(&t), 2);
#if __BYTE_ORDER == __LITTLE_ENDIAN
t = bswap_16(t);
#endif
return t;
}
int32_t kaitai::kstream::read_s4be() {
int32_t t;
m_io->read(reinterpret_cast<char *>(&t), 4);
#if __BYTE_ORDER == __LITTLE_ENDIAN
t = bswap_32(t);
#endif
return t;
}
int64_t kaitai::kstream::read_s8be() {
int64_t t;
m_io->read(reinterpret_cast<char *>(&t), 8);
#if __BYTE_ORDER == __LITTLE_ENDIAN
t = bswap_64(t);
#endif
return t;
}
// ........................................................................
// Little-endian
// ........................................................................
int16_t kaitai::kstream::read_s2le() {
int16_t t;
m_io->read(reinterpret_cast<char *>(&t), 2);
#if __BYTE_ORDER == __BIG_ENDIAN
t = bswap_16(t);
#endif
return t;
}
int32_t kaitai::kstream::read_s4le() {
int32_t t;
m_io->read(reinterpret_cast<char *>(&t), 4);
#if __BYTE_ORDER == __BIG_ENDIAN
t = bswap_32(t);
#endif
return t;
}
int64_t kaitai::kstream::read_s8le() {
int64_t t;
m_io->read(reinterpret_cast<char *>(&t), 8);
#if __BYTE_ORDER == __BIG_ENDIAN
t = bswap_64(t);
#endif
return t;
}
// ------------------------------------------------------------------------
// Unsigned
// ------------------------------------------------------------------------
uint8_t kaitai::kstream::read_u1() {
char t;
m_io->get(t);
return t;
}
// ........................................................................
// Big-endian
// ........................................................................
uint16_t kaitai::kstream::read_u2be() {
uint16_t t;
m_io->read(reinterpret_cast<char *>(&t), 2);
#if __BYTE_ORDER == __LITTLE_ENDIAN
t = bswap_16(t);
#endif
return t;
}
uint32_t kaitai::kstream::read_u4be() {
uint32_t t;
m_io->read(reinterpret_cast<char *>(&t), 4);
#if __BYTE_ORDER == __LITTLE_ENDIAN
t = bswap_32(t);
#endif
return t;
}
uint64_t kaitai::kstream::read_u8be() {
uint64_t t;
m_io->read(reinterpret_cast<char *>(&t), 8);
#if __BYTE_ORDER == __LITTLE_ENDIAN
t = bswap_64(t);
#endif
return t;
}
// ........................................................................
// Little-endian
// ........................................................................
uint16_t kaitai::kstream::read_u2le() {
uint16_t t;
m_io->read(reinterpret_cast<char *>(&t), 2);
#if __BYTE_ORDER == __BIG_ENDIAN
t = bswap_16(t);
#endif
return t;
}
uint32_t kaitai::kstream::read_u4le() {
uint32_t t;
m_io->read(reinterpret_cast<char *>(&t), 4);
#if __BYTE_ORDER == __BIG_ENDIAN
t = bswap_32(t);
#endif
return t;
}
uint64_t kaitai::kstream::read_u8le() {
uint64_t t;
m_io->read(reinterpret_cast<char *>(&t), 8);
#if __BYTE_ORDER == __BIG_ENDIAN
t = bswap_64(t);
#endif
return t;
}
// ========================================================================
// Floating point numbers
// ========================================================================
// ........................................................................
// Big-endian
// ........................................................................
float kaitai::kstream::read_f4be() {
uint32_t t;
m_io->read(reinterpret_cast<char *>(&t), 4);
#if __BYTE_ORDER == __LITTLE_ENDIAN
t = bswap_32(t);
#endif
return reinterpret_cast<float&>(t);
}
double kaitai::kstream::read_f8be() {
uint64_t t;
m_io->read(reinterpret_cast<char *>(&t), 8);
#if __BYTE_ORDER == __LITTLE_ENDIAN
t = bswap_64(t);
#endif
return reinterpret_cast<double&>(t);
}
// ........................................................................
// Little-endian
// ........................................................................
float kaitai::kstream::read_f4le() {
uint32_t t;
m_io->read(reinterpret_cast<char *>(&t), 4);
#if __BYTE_ORDER == __BIG_ENDIAN
t = bswap_32(t);
#endif
return reinterpret_cast<float&>(t);
}
double kaitai::kstream::read_f8le() {
uint64_t t;
m_io->read(reinterpret_cast<char *>(&t), 8);
#if __BYTE_ORDER == __BIG_ENDIAN
t = bswap_64(t);
#endif
return reinterpret_cast<double&>(t);
}
// ========================================================================
// Unaligned bit values
// ========================================================================
void kaitai::kstream::align_to_byte() {
m_bits_left = 0;
m_bits = 0;
}
uint64_t kaitai::kstream::read_bits_int_be(int n) {
int bits_needed = n - m_bits_left;
if (bits_needed > 0) {
// 1 bit => 1 byte
// 8 bits => 1 byte
// 9 bits => 2 bytes
int bytes_needed = ((bits_needed - 1) / 8) + 1;
if (bytes_needed > 8)
throw std::runtime_error("read_bits_int: more than 8 bytes requested");
char buf[8];
m_io->read(buf, bytes_needed);
for (int i = 0; i < bytes_needed; i++) {
uint8_t b = buf[i];
m_bits <<= 8;
m_bits |= b;
m_bits_left += 8;
}
}
// raw mask with required number of 1s, starting from lowest bit
uint64_t mask = get_mask_ones(n);
// shift mask to align with highest bits available in @bits
int shift_bits = m_bits_left - n;
mask <<= shift_bits;
// derive reading result
uint64_t res = (m_bits & mask) >> shift_bits;
// clear top bits that we've just read => AND with 1s
m_bits_left -= n;
mask = get_mask_ones(m_bits_left);
m_bits &= mask;
return res;
}
// Deprecated, use read_bits_int_be() instead.
uint64_t kaitai::kstream::read_bits_int(int n) {
return read_bits_int_be(n);
}
uint64_t kaitai::kstream::read_bits_int_le(int n) {
int bits_needed = n - m_bits_left;
if (bits_needed > 0) {
// 1 bit => 1 byte
// 8 bits => 1 byte
// 9 bits => 2 bytes
int bytes_needed = ((bits_needed - 1) / 8) + 1;
if (bytes_needed > 8)
throw std::runtime_error("read_bits_int_le: more than 8 bytes requested");
char buf[8];
m_io->read(buf, bytes_needed);
for (int i = 0; i < bytes_needed; i++) {
uint8_t b = buf[i];
m_bits |= (static_cast<uint64_t>(b) << m_bits_left);
m_bits_left += 8;
}
}
// raw mask with required number of 1s, starting from lowest bit
uint64_t mask = get_mask_ones(n);
// derive reading result
uint64_t res = m_bits & mask;
// remove bottom bits that we've just read by shifting
m_bits >>= n;
m_bits_left -= n;
return res;
}
uint64_t kaitai::kstream::get_mask_ones(int n) {
if (n == 64) {
return 0xFFFFFFFFFFFFFFFF;
} else {
return ((uint64_t) 1 << n) - 1;
}
}
// ========================================================================
// Byte arrays
// ========================================================================
std::string kaitai::kstream::read_bytes(std::streamsize len) {
std::vector<char> result(len);
// NOTE: streamsize type is signed, negative values are only *supposed* to not be used.
// http://en.cppreference.com/w/cpp/io/streamsize
if (len < 0) {
throw std::runtime_error("read_bytes: requested a negative amount");
}
if (len > 0) {
m_io->read(&result[0], len);
}
return std::string(result.begin(), result.end());
}
std::string kaitai::kstream::read_bytes_full() {
std::iostream::pos_type p1 = m_io->tellg();
m_io->seekg(0, std::ios::end);
std::iostream::pos_type p2 = m_io->tellg();
size_t len = p2 - p1;
// Note: this requires a std::string to be backed with a
// contiguous buffer. Officially, it's a only requirement since
// C++11 (C++98 and C++03 didn't have this requirement), but all
// major implementations had contiguous buffers anyway.
std::string result(len, ' ');
m_io->seekg(p1);
m_io->read(&result[0], len);
return result;
}
std::string kaitai::kstream::read_bytes_term(char term, bool include, bool consume, bool eos_error) {
std::string result;
std::getline(*m_io, result, term);
if (m_io->eof()) {
// encountered EOF
if (eos_error) {
throw std::runtime_error("read_bytes_term: encountered EOF");
}
} else {
// encountered terminator
if (include)
result.push_back(term);
if (!consume)
m_io->unget();
}
return result;
}
std::string kaitai::kstream::ensure_fixed_contents(std::string expected) {
std::string actual = read_bytes(expected.length());
if (actual != expected) {
// NOTE: I think printing it outright is not best idea, it could contain non-ascii charactes like backspace and beeps and whatnot. It would be better to print hexlified version, and also to redirect it to stderr.
throw std::runtime_error("ensure_fixed_contents: actual data does not match expected data");
}
return actual;
}
std::string kaitai::kstream::bytes_strip_right(std::string src, char pad_byte) {
std::size_t new_len = src.length();
while (new_len > 0 && src[new_len - 1] == pad_byte)
new_len--;
return src.substr(0, new_len);
}
std::string kaitai::kstream::bytes_terminate(std::string src, char term, bool include) {
std::size_t new_len = 0;
std::size_t max_len = src.length();
while (new_len < max_len && src[new_len] != term)
new_len++;
if (include && new_len < max_len)
new_len++;
return src.substr(0, new_len);
}
// ========================================================================
// Byte array processing
// ========================================================================
std::string kaitai::kstream::process_xor_one(std::string data, uint8_t key) {
size_t len = data.length();
std::string result(len, ' ');
for (size_t i = 0; i < len; i++)
result[i] = data[i] ^ key;
return result;
}
std::string kaitai::kstream::process_xor_many(std::string data, std::string key) {
size_t len = data.length();
size_t kl = key.length();
std::string result(len, ' ');
size_t ki = 0;
for (size_t i = 0; i < len; i++) {
result[i] = data[i] ^ key[ki];
ki++;
if (ki >= kl)
ki = 0;
}
return result;
}
std::string kaitai::kstream::process_rotate_left(std::string data, int amount) {
size_t len = data.length();
std::string result(len, ' ');
for (size_t i = 0; i < len; i++) {
uint8_t bits = data[i];
result[i] = (bits << amount) | (bits >> (8 - amount));
}
return result;
}
#ifdef KS_ZLIB
#include <zlib.h>
std::string kaitai::kstream::process_zlib(std::string data) {
int ret;
unsigned char *src_ptr = reinterpret_cast<unsigned char*>(&data[0]);
std::stringstream dst_strm;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
ret = inflateInit(&strm);
if (ret != Z_OK)
throw std::runtime_error("process_zlib: inflateInit error");
strm.next_in = src_ptr;
strm.avail_in = data.length();
unsigned char outbuffer[ZLIB_BUF_SIZE];
std::string outstring;
// get the decompressed bytes blockwise using repeated calls to inflate
do {
strm.next_out = reinterpret_cast<Bytef*>(outbuffer);
strm.avail_out = sizeof(outbuffer);
ret = inflate(&strm, 0);
if (outstring.size() < strm.total_out)
outstring.append(reinterpret_cast<char*>(outbuffer), strm.total_out - outstring.size());
} while (ret == Z_OK);
if (ret != Z_STREAM_END) { // an error occurred that was not EOF
std::ostringstream exc_msg;
exc_msg << "process_zlib: error #" << ret << "): " << strm.msg;
throw std::runtime_error(exc_msg.str());
}
if (inflateEnd(&strm) != Z_OK)
throw std::runtime_error("process_zlib: inflateEnd error");
return outstring;
}
#endif
// ========================================================================
// Misc utility methods
// ========================================================================
int kaitai::kstream::mod(int a, int b) {
if (b <= 0)
throw std::invalid_argument("mod: divisor b <= 0");
int r = a % b;
if (r < 0)
r += b;
return r;
}
#include <stdio.h>
std::string kaitai::kstream::to_string(int val) {
// if int is 32 bits, "-2147483648" is the longest string representation
// => 11 chars + zero => 12 chars
// if int is 64 bits, "-9223372036854775808" is the longest
// => 20 chars + zero => 21 chars
char buf[25];
int got_len = snprintf(buf, sizeof(buf), "%d", val);
// should never happen, but check nonetheless
if (got_len > sizeof(buf))
throw std::invalid_argument("to_string: integer is longer than string buffer");
return std::string(buf);
}
#include <algorithm>
std::string kaitai::kstream::reverse(std::string val) {
std::reverse(val.begin(), val.end());
return val;
}
uint8_t kaitai::kstream::byte_array_min(const std::string val) {
uint8_t min = 0xff; // UINT8_MAX
std::string::const_iterator end = val.end();
for (std::string::const_iterator it = val.begin(); it != end; ++it) {
uint8_t cur = static_cast<uint8_t>(*it);
if (cur < min) {
min = cur;
}
}
return min;
}
uint8_t kaitai::kstream::byte_array_max(const std::string val) {
uint8_t max = 0; // UINT8_MIN
std::string::const_iterator end = val.end();
for (std::string::const_iterator it = val.begin(); it != end; ++it) {
uint8_t cur = static_cast<uint8_t>(*it);
if (cur > max) {
max = cur;
}
}
return max;
}
// ========================================================================
// Other internal methods
// ========================================================================
#ifndef KS_STR_DEFAULT_ENCODING
#define KS_STR_DEFAULT_ENCODING "UTF-8"
#endif
#ifdef KS_STR_ENCODING_ICONV
#include <iconv.h>
#include <cerrno>
#include <stdexcept>
std::string kaitai::kstream::bytes_to_str(std::string src, std::string src_enc) {
iconv_t cd = iconv_open(KS_STR_DEFAULT_ENCODING, src_enc.c_str());
if (cd == (iconv_t) -1) {
if (errno == EINVAL) {
throw std::runtime_error("bytes_to_str: invalid encoding pair conversion requested");
} else {
throw std::runtime_error("bytes_to_str: error opening iconv");
}
}
size_t src_len = src.length();
size_t src_left = src_len;
// Start with a buffer length of double the source length.
size_t dst_len = src_len * 2;
std::string dst(dst_len, ' ');
size_t dst_left = dst_len;
char *src_ptr = &src[0];
char *dst_ptr = &dst[0];
while (true) {
size_t res = iconv(cd, &src_ptr, &src_left, &dst_ptr, &dst_left);
if (res == (size_t) -1) {
if (errno == E2BIG) {
// dst buffer is not enough to accomodate whole string
// enlarge the buffer and try again
size_t dst_used = dst_len - dst_left;
dst_left += dst_len;
dst_len += dst_len;
dst.resize(dst_len);
// dst.resize might have allocated destination buffer in another area
// of memory, thus our previous pointer "dst" will be invalid; re-point
// it using "dst_used".
dst_ptr = &dst[dst_used];
} else {
throw std::runtime_error("bytes_to_str: iconv error");
}
} else {
// conversion successful
dst.resize(dst_len - dst_left);
break;
}
}
if (iconv_close(cd) != 0) {
throw std::runtime_error("bytes_to_str: iconv close error");
}
return dst;
}
#elif defined(KS_STR_ENCODING_NONE)
std::string kaitai::kstream::bytes_to_str(std::string src, std::string src_enc) {
return src;
}
#else
#error Need to decide how to handle strings: please define one of: KS_STR_ENCODING_ICONV, KS_STR_ENCODING_NONE
#endif