1 module types; 2 3 nothrow @nogc extern(C): 4 5 import glob_opts; 6 import constants; 7 import qdldl_types; // for QDLDL_int and others 8 9 10 version(PRINTING){ 11 import core.stdc.stdio; 12 } // ifdef PRINTING 13 14 /****************** 15 * Internal types * 16 ******************/ 17 18 /** 19 * Matrix in compressed-column form. 20 * The structure is used internally to store matrices in the triplet form as well, 21 * but the API requires that the matrices are in the CSC format. 22 */ 23 struct csc { 24 25 c_int nzmax; ///< maximum number of entries 26 c_int m; ///< number of rows 27 c_int n; ///< number of columns 28 c_int *p; ///< column pointers (size n+1); col indices (size nzmax) start from 0 when using triplet format (direct KKT matrix formation) 29 c_int *i; ///< row indices, size nzmax starting from 0 30 c_float *x; ///< numerical values, size nzmax 31 c_int nz; ///< number of entries in triplet matrix, -1 for csc 32 }; 33 34 /** 35 * Linear system solver structure (sublevel objects initialize it differently) 36 */ 37 38 //typedef struct linsys_solver LinSysSolver; 39 //alias linsys_solver = LinSysSolver; 40 alias LinSysSolver = linsys_solver; // todo : check it 41 42 /** 43 * OSQP Timer for statistics 44 */ 45 46 47 /********************************* 48 * Timer Structs and Functions * * 49 *********************************/ 50 51 /*! \cond PRIVATE */ 52 53 version(PROFILING){ 54 55 // Windows 56 version(Windows){ 57 58 // Some R packages clash with elements 59 // of the windows.h header, so use a 60 version(R_LANG){ 61 //#define NOGDI 62 enum bool NOGDI = true; // todo : test it 63 } 64 65 //# include <windows.h> 66 // import windows; // todo 67 68 struct OSQPTimer { 69 ulong tic; 70 ulong toc; 71 ulong freq; 72 }; 73 74 } else version(OSX) 75 { 76 //# include <mach/mach_time.h> 77 import core.time: mach_timebase_info_data_t; // todo 78 79 /* Use MAC OSX mach_time for timing */ 80 struct OSQPTimer { 81 ulong tic; 82 ulong toc; 83 mach_timebase_info_data_t tinfo; 84 }; 85 } 86 else version(linux) 87 { 88 89 /* Use POSIX clock_gettime() for timing on non-Windows machines */ 90 import core.sys.posix.sys.time; 91 92 struct OSQPTimer { 93 timespec tic; 94 timespec toc; 95 }; 96 } 97 }/* END #ifdef PROFILING */ 98 99 /** 100 * Problem scaling matrices stored as vectors 101 */ 102 struct OSQPScaling { 103 c_float c; ///< cost function scaling 104 c_float *D; ///< primal variable scaling 105 c_float *E; ///< dual variable scaling 106 c_float cinv; ///< cost function rescaling 107 c_float *Dinv; ///< primal variable rescaling 108 c_float *Einv; ///< dual variable rescaling 109 }; 110 111 /** 112 * Solution structure 113 */ 114 struct OSQPSolution{ 115 c_float *x; ///< primal solution 116 c_float *y; ///< Lagrange multiplier associated to \f$l <= Ax <= u\f$ 117 }; 118 119 120 /** 121 * Solver return information 122 */ 123 struct OSQPInfo{ 124 c_int iter; ///< number of iterations taken 125 char [32] status; ///< status string, e.g. 'solved' 126 c_int status_val; ///< status as c_int, defined in constants.h 127 128 version(EMBEDDED){} 129 else { 130 c_int status_polish; ///< polish status: successful (1), unperformed (0), (-1) unsuccessful 131 } // ifndef EMBEDDED 132 133 c_float obj_val; ///< primal objective 134 c_float pri_res; ///< norm of primal residual 135 c_float dua_res; ///< norm of dual residual 136 137 version(PROFILING){ 138 c_float setup_time; ///< time taken for setup phase (seconds) 139 c_float solve_time; ///< time taken for solve phase (seconds) 140 c_float update_time; ///< time taken for update phase (seconds) 141 c_float polish_time; ///< time taken for polish phase (seconds) 142 c_float run_time; ///< total time (seconds) 143 } // ifdef PROFILING 144 145 version(EMBEDDED_1){} 146 else { // if EMBEDDED != 1 147 c_int rho_updates; ///< number of rho updates 148 c_float rho_estimate; ///< best rho estimate so far from residuals 149 } 150 }; 151 152 version (EMBEDDED){} 153 else { 154 155 /** 156 * Polish structure 157 */ 158 struct OSQPPolish{ 159 csc *Ared; ///< active rows of A 160 ///< Ared = vstack[Alow, Aupp] 161 c_int n_low; ///< number of lower-active rows 162 c_int n_upp; ///< number of upper-active rows 163 c_int *A_to_Alow; ///< Maps indices in A to indices in Alow 164 c_int *A_to_Aupp; ///< Maps indices in A to indices in Aupp 165 c_int *Alow_to_A; ///< Maps indices in Alow to indices in A 166 c_int *Aupp_to_A; ///< Maps indices in Aupp to indices in A 167 c_float *x; ///< optimal x-solution obtained by polish 168 c_float *z; ///< optimal z-solution obtained by polish 169 c_float *y; ///< optimal y-solution obtained by polish 170 c_float obj_val; ///< objective value at polished solution 171 c_float pri_res; ///< primal residual at polished solution 172 c_float dua_res; ///< dual residual at polished solution 173 }; 174 } // !version (EMBEDDED) 175 176 177 /********************************** 178 * Main structures and Data Types * 179 **********************************/ 180 181 /** 182 * Data structure 183 */ 184 struct OSQPData{ 185 c_int n; ///< number of variables n 186 c_int m; ///< number of constraints m 187 csc *P; ///< the upper triangular part of the quadratic cost matrix P in csc format (size n x n). 188 csc *A; ///< linear constraints matrix A in csc format (size m x n) 189 c_float *q; ///< dense array for linear part of cost function (size n) 190 c_float *l; ///< dense array for lower bound (size m) 191 c_float *u; ///< dense array for upper bound (size m) 192 }; 193 194 195 /** 196 * Settings struct 197 */ 198 struct OSQPSettings{ 199 c_float rho; ///< ADMM step rho 200 c_float sigma; ///< ADMM step sigma 201 c_int scaling; ///< heuristic data scaling iterations; if 0, then disabled. 202 203 version(EMBEDDED_1){} 204 else { // if EMBEDDED != 1 205 206 c_int adaptive_rho; ///< boolean, is rho step size adaptive? 207 c_int adaptive_rho_interval; ///< number of iterations between rho adaptations; if 0, then it is automatic 208 c_float adaptive_rho_tolerance; ///< tolerance X for adapting rho. The new rho has to be X times larger or 1/X times smaller than the current one to trigger a new factorization. 209 version(PROFILING){ 210 c_float adaptive_rho_fraction; ///< interval for adapting rho (fraction of the setup time) 211 } // Profiling 212 } 213 214 c_int max_iter; ///< maximum number of iterations 215 c_float eps_abs; ///< absolute convergence tolerance 216 c_float eps_rel; ///< relative convergence tolerance 217 c_float eps_prim_inf; ///< primal infeasibility tolerance 218 c_float eps_dual_inf; ///< dual infeasibility tolerance 219 c_float alpha; ///< relaxation parameter 220 linsys_solver_type linsys_solver; ///< linear system solver to use 221 222 version(EMBEDDED){} 223 else { // ifndef EMBEDDED 224 c_float delta; ///< regularization parameter for polishing 225 c_int polish; ///< boolean, polish ADMM solution 226 c_int polish_refine_iter; ///< number of iterative refinement steps in polishing 227 228 c_int verbose; ///< boolean, write out progress 229 } // ifndef EMBEDDED 230 231 c_int scaled_termination; ///< boolean, use scaled termination criteria 232 c_int check_termination; ///< integer, check termination interval; if 0, then termination checking is disabled 233 c_int warm_start; ///< boolean, warm start 234 235 version(PROFILING){ 236 c_float time_limit; ///< maximum number of seconds allowed to solve the problem; if 0, then disabled 237 } // ifdef PROFILING 238 }; 239 240 241 /** 242 * OSQP Workspace 243 */ 244 struct OSQPWorkspace{ 245 /// Problem data to work on (possibly scaled) 246 OSQPData *data; 247 248 /// Linear System solver structure 249 LinSysSolver *linsys_solver; 250 251 version(EMBEDDED){} 252 else { // ifndef EMBEDDED 253 /// Polish structure 254 OSQPPolish *pol; 255 } // ifndef EMBEDDED 256 257 /** 258 * @name Vector used to store a vectorized rho parameter 259 * @{ 260 */ 261 c_float *rho_vec; ///< vector of rho values 262 c_float *rho_inv_vec; ///< vector of inv rho values 263 264 /** @} */ 265 266 version(EMBEDDED_1){} 267 else { // if EMBEDDED != 1 268 c_int *constr_type; ///< Type of constraints: loose (-1), equality (1), inequality (0) 269 } // if EMBEDDED != 1 270 271 /** 272 * @name Iterates 273 * @{ 274 */ 275 c_float *x; ///< Iterate x 276 c_float *y; ///< Iterate y 277 c_float *z; ///< Iterate z 278 c_float *xz_tilde; ///< Iterate xz_tilde 279 280 c_float *x_prev; ///< Previous x 281 282 /**< NB: Used also as workspace vector for dual residual */ 283 c_float *z_prev; ///< Previous z 284 285 /**< NB: Used also as workspace vector for primal residual */ 286 287 /** 288 * @name Primal and dual residuals workspace variables 289 * 290 * Needed for residuals computation, tolerances computation, 291 * approximate tolerances computation and adapting rho 292 * @{ 293 */ 294 c_float *Ax; ///< scaled A * x 295 c_float *Px; ///< scaled P * x 296 c_float *Aty; ///< scaled A * x 297 298 /** @} */ 299 300 /** 301 * @name Primal infeasibility variables 302 * @{ 303 */ 304 c_float *delta_y; ///< difference between consecutive dual iterates 305 c_float *Atdelta_y; ///< A' * delta_y 306 307 /** @} */ 308 309 /** 310 * @name Dual infeasibility variables 311 * @{ 312 */ 313 c_float *delta_x; ///< difference between consecutive primal iterates 314 c_float *Pdelta_x; ///< P * delta_x 315 c_float *Adelta_x; ///< A * delta_x 316 317 /** @} */ 318 319 /** 320 * @name Temporary vectors used in scaling 321 * @{ 322 */ 323 324 c_float *D_temp; ///< temporary primal variable scaling vectors 325 c_float *D_temp_A; ///< temporary primal variable scaling vectors storing norms of A columns 326 c_float *E_temp; ///< temporary constraints scaling vectors storing norms of A' columns 327 328 329 /** @} */ 330 331 OSQPSettings *settings; ///< problem settings 332 OSQPScaling *scaling; ///< scaling vectors 333 OSQPSolution *solution; ///< problem solution 334 OSQPInfo *info; ///< solver information 335 336 version(PROFILING){ 337 OSQPTimer *timer; ///< timer object 338 339 /// flag indicating whether the solve function has been run before 340 c_int first_run; 341 342 /// flag indicating whether the update_time should be cleared 343 c_int clear_update_time; 344 345 /// flag indicating that osqp_update_rho is called from osqp_solve function 346 c_int rho_update_from_solve; 347 } // ifdef PROFILING 348 349 version(PRINTING){ 350 c_int summary_printed; ///< Has last summary been printed? (true/false) 351 } // ifdef PRINTING 352 353 }; 354 355 356 /** 357 * Define linsys_solver prototype structure 358 * 359 * NB: The details are defined when the linear solver is initialized depending 360 * on the choice 361 */ 362 alias solve_t = c_int function(LinSysSolver* self, c_float* b); 363 alias update_matrices_t = c_int function(LinSysSolver* s, const csc* P, const csc* A); 364 alias update_rho_vec_t = c_int function(LinSysSolver* s, const c_float* rho_vec); 365 alias free_t = void function(LinSysSolver* self); 366 367 struct linsys_solver { 368 linsys_solver_type type; ///< linear system solver type functions 369 //c_int (*solve)(LinSysSolver *self, 370 // c_float *b); ///< solve linear system 371 solve_t solve; 372 373 version(EMBEDDED){} 374 else { // ifndef EMBEDDED 375 //void (*free)(LinSysSolver *self); ///< free linear system solver (only in desktop version) 376 free_t free; // todo 377 } // ifndef EMBEDDED 378 379 version(EMBEDDED_1){} 380 else { // ifndef EMBEDDED 381 //c_int (*update_matrices)(LinSysSolver *s, 382 // const csc *P, ///< update matrices P 383 // const csc *A); // and A in the solver 384 update_matrices_t update_matrices; 385 386 //c_int (*update_rho_vec)(LinSysSolver *s, 387 // const c_float *rho_vec); ///< Update rho_vec 388 update_rho_vec_t update_rho_vec; 389 } // if EMBEDDED != 1 390 391 version(EMBEDDED){} 392 else { // ifndef EMBEDDED 393 c_int nthreads; ///< number of threads active 394 } // ifndef EMBEDDED 395 };