Divergence with generated code in 0.6.0 but not 0.3.1

I am having an interesting issue with generated code for a very simple problem:

H = eye(2);
G = eye(2);
g = [0;0];
u = [2;2];
l = [1;1];

When I solve in MATLAB via emosqp calling generated code, the correct answer [1 1] is returned.

However, if I take that same generated code and solve in a Simulink block using a call to coder.ceval(‘osqp_harness’), where osqp_harness is a little C function whose only line (other than #includes) is

osqp_solve(&workspace);

then when I interrogate the solution I see it has diverged. All elements of x and y are returned as identical values on the order of 2e9, solver iterations are 100, and solution status is -7 (nonconvex).

This happens with OSQP 0.6.0–but with OSQP 0.3.1 the Simulink process described above returns the correct solution [1 1]. I suspect this behavior actually appeared starting in 0.4.0, but need to go back and verify.

Some slight complexities should be noted with the generated code:

  • I manually added #DLONG to glob_opts
  • I manually changed all instances of “util” to “osqp_util” (including in filenames)
    I made these same modifications for both OSQP versions (0.3.1 or 0.6.0).

I can try to put together a standalone minimum working example, but in the meantime I am wondering whether this issue rings a bell for anyone?

Thanks,

Matt

How are you getting the data back from the coder.ceval call? The emosqp function has a wrapper to translate the OSQP data into MATLAB structures/variables after the solve is finished (see https://github.com/oxfordcontrol/osqp-matlab/blob/master/codegen/files_to_generate/emosqp_mex.c). It could be there is an issue with the variable representations you are getting back from this call.

Good question… I get the data back via another coder.ceval() call to a C function that returns selected values from OSQP “workspace”. I know this function works for both 0.3.1 and 0.6.0. With 0.3.1 I get the correct solution back, and with 0.6.0 if I interrogate “workspace” before solving the QP then I get the correct termination code (-10) and values for x and y (all zeros). This suggests that the -7 termination code and extreme values for x and y described in my original post are genuinely the values returned by the solver–and this is consistent with divergence being the trigger for the -7 termination code.

In that case it would be useful to see a minimal example of this interaction so we can play with it ourselves.

I haven’t used OSQP through a coder.ceval interface in Simulink, instead I have worked with @paul.goulart on a simple Simulink interface (https://github.com/imciner2/osqp-matlab/tree/im/simulink_cg) using an M-S function. This might solve some of your issues if you want to try it (it is experimental at this point though).

Thanks for your reply Ian.

On further investigation the issue is definitely associated with my attempt to modify the standalone generated C code to enforce DLONG. My use case does not involve CMake so I need to assert DLONG in the C code itself.

For OSQP 0.3.1 and prior, I successfully accomplish this by manually adding “#define DLONG” at line 11 of glob_opts.h.

For OSQP 0.6.0 this manual addition breaks the solver. I tried instead to add
#define DLONG” at line 32 of osqp_configure.h, but this also breaks the solver.

Any suggestions for how to accomplish this?

Thanks,

Matt

I think that the osqp_configure.h file is the correct place to define DLONG. Could the problem be that you are not providing a compatible definition in the QDLDL code (assuming that you are using QDLDL)? You should have a compatible type defined for QDLDL_float in the qdldl_types.h header. There will be a similar issue with PARDISO if you are using that instead.

Thanks Paul–that worked!