1 2 module lin_alg; 3 4 nothrow @nogc extern(C): 5 6 import glob_opts; 7 import types; 8 import constants; // for OSQP_NULL 9 10 11 /* VECTOR FUNCTIONS ----------------------------------------------------------*/ 12 13 14 void vec_add_scaled(c_float *c, 15 const c_float *a, 16 const c_float *b, 17 c_int n, 18 c_float sc) { 19 c_int i; 20 21 for (i = 0; i < n; i++) { 22 c[i] = a[i] + sc * b[i]; 23 } 24 } 25 26 c_float vec_scaled_norm_inf(const c_float *S, const c_float *v, c_int l) { 27 c_int i; 28 c_float abs_Sv_i; 29 c_float max = 0.0; 30 31 for (i = 0; i < l; i++) { 32 abs_Sv_i = c_absval(S[i] * v[i]); 33 34 if (abs_Sv_i > max) max = abs_Sv_i; 35 } 36 return max; 37 } 38 39 c_float vec_norm_inf(const c_float *v, c_int l) { 40 c_int i; 41 c_float abs_v_i; 42 c_float max = 0.0; 43 44 for (i = 0; i < l; i++) { 45 abs_v_i = c_absval(v[i]); 46 47 if (abs_v_i > max) max = abs_v_i; 48 } 49 return max; 50 } 51 52 c_float vec_norm_inf_diff(const c_float *a, const c_float *b, c_int l) { 53 c_float nmDiff = 0.0, tmp; 54 c_int i; 55 56 for (i = 0; i < l; i++) { 57 tmp = c_absval(a[i] - b[i]); 58 59 if (tmp > nmDiff) nmDiff = tmp; 60 } 61 return nmDiff; 62 } 63 64 c_float vec_mean(const c_float *a, c_int n) { 65 c_float mean = 0.0; 66 c_int i; 67 68 for (i = 0; i < n; i++) { 69 mean += a[i]; 70 } 71 mean /= cast(c_float)n; 72 73 return mean; 74 } 75 76 void int_vec_set_scalar(c_int *a, c_int sc, c_int n) { 77 c_int i; 78 79 for (i = 0; i < n; i++) { 80 a[i] = sc; 81 } 82 } 83 84 void vec_set_scalar(c_float *a, c_float sc, c_int n) { 85 c_int i; 86 87 for (i = 0; i < n; i++) { 88 a[i] = sc; 89 } 90 } 91 92 void vec_add_scalar(c_float *a, c_float sc, c_int n) { 93 c_int i; 94 95 for (i = 0; i < n; i++) { 96 a[i] += sc; 97 } 98 } 99 100 void vec_mult_scalar(c_float *a, c_float sc, c_int n) { 101 c_int i; 102 103 for (i = 0; i < n; i++) { 104 a[i] *= sc; 105 } 106 } 107 108 version(EMBEDDED){} 109 else { 110 c_float* vec_copy(c_float *a, c_int n) { 111 c_float *b; 112 c_int i; 113 114 b = cast(c_float*)c_malloc(n * (c_float.sizeof)); 115 if (!b) return OSQP_NULL; 116 117 for (i = 0; i < n; i++) { 118 b[i] = a[i]; 119 } 120 121 return b; 122 } 123 124 } // end ! EMBEDDED 125 126 127 void prea_int_vec_copy(const c_int *a, c_int *b, c_int n) { 128 c_int i; 129 130 for (i = 0; i < n; i++) { 131 b[i] = a[i]; 132 } 133 } 134 135 void prea_vec_copy(const c_float *a, c_float *b, c_int n) { 136 c_int i; 137 138 for (i = 0; i < n; i++) { 139 b[i] = a[i]; 140 } 141 } 142 143 void vec_ew_recipr(const c_float *a, c_float *b, c_int n) { 144 c_int i; 145 146 for (i = 0; i < n; i++) { 147 b[i] = cast(c_float)1.0 / a[i]; 148 } 149 } 150 151 c_float vec_prod(const c_float *a, const c_float *b, c_int n) { 152 c_float prod = 0.0; 153 c_int i; // Index 154 155 for (i = 0; i < n; i++) { 156 prod += a[i] * b[i]; 157 } 158 159 return prod; 160 } 161 162 void vec_ew_prod(const c_float *a, const c_float *b, c_float *c, c_int n) { 163 c_int i; 164 165 for (i = 0; i < n; i++) { 166 c[i] = b[i] * a[i]; 167 } 168 } 169 170 version(EMBEDDED_1){} 171 else { 172 void vec_ew_sqrt(c_float *a, c_int n) { 173 c_int i; 174 175 for (i = 0; i < n; i++) { 176 a[i] = c_sqrt(a[i]); 177 } 178 } 179 180 void vec_ew_max(c_float *a, c_int n, c_float max_val) { 181 c_int i; 182 183 for (i = 0; i < n; i++) { 184 a[i] = c_max(a[i], max_val); 185 } 186 } 187 188 void vec_ew_min(c_float *a, c_int n, c_float min_val) { 189 c_int i; 190 191 for (i = 0; i < n; i++) { 192 a[i] = c_min(a[i], min_val); 193 } 194 } 195 196 void vec_ew_max_vec(const c_float *a, const c_float *b, c_float *c, c_int n) { 197 c_int i; 198 199 for (i = 0; i < n; i++) { 200 c[i] = c_max(a[i], b[i]); 201 } 202 } 203 204 void vec_ew_min_vec(const c_float *a, const c_float *b, c_float *c, c_int n) { 205 c_int i; 206 207 for (i = 0; i < n; i++) { 208 c[i] = c_min(a[i], b[i]); 209 } 210 } 211 212 } // EMBEDDED != 1 213 214 215 /* MATRIX FUNCTIONS ----------------------------------------------------------*/ 216 217 /* multiply scalar to matrix */ 218 void mat_mult_scalar(csc *A, c_float sc) { 219 c_int i; 220 c_int nnzA; 221 222 nnzA = A.p[A.n]; 223 224 for (i = 0; i < nnzA; i++) { 225 A.x[i] *= sc; 226 } 227 } 228 229 void mat_premult_diag(csc *A, const c_float *d) { 230 c_int j; 231 c_int i; 232 233 for (j = 0; j < A.n; j++) { // Cycle over columns 234 for (i = A.p[j]; i < A.p[j + 1]; i++) { // Cycle every row in the column 235 A.x[i] *= d[A.i[i]]; // Scale by corresponding element 236 // of d for row i 237 } 238 } 239 } 240 241 void mat_postmult_diag(csc *A, const c_float *d) { 242 c_int j; 243 c_int i; 244 245 for (j = 0; j < A.n; j++) { // Cycle over columns j 246 for (i = A.p[j]; i < A.p[j + 1]; i++) { // Cycle every row i in column j 247 A.x[i] *= d[j]; // Scale by corresponding element 248 // of d for column j 249 } 250 } 251 } 252 253 void mat_vec(const csc *A, const c_float *x, c_float *y, c_int plus_eq) { 254 c_int i; 255 c_int j; 256 257 if (!plus_eq) { 258 // y = 0 259 for (i = 0; i < A.m; i++) { 260 y[i] = 0; 261 } 262 } 263 264 // if A is empty 265 if (A.p[A.n] == 0) { 266 return; 267 } 268 269 if (plus_eq == -1) { 270 // y -= A*x 271 for (j = 0; j < A.n; j++) { 272 for (i = A.p[j]; i < A.p[j + 1]; i++) { 273 y[A.i[i]] -= A.x[i] * x[j]; 274 } 275 } 276 } else { 277 // y += A*x 278 for (j = 0; j < A.n; j++) { 279 for (i = A.p[j]; i < A.p[j + 1]; i++) { 280 y[A.i[i]] += A.x[i] * x[j]; 281 } 282 } 283 } 284 } 285 286 void mat_tpose_vec(const csc *A, const c_float *x, c_float *y, 287 c_int plus_eq, c_int skip_diag) { 288 c_int i; 289 c_int j; 290 c_int k; 291 292 if (!plus_eq) { 293 // y = 0 294 for (i = 0; i < A.n; i++) { 295 y[i] = 0; 296 } 297 } 298 299 // if A is empty 300 if (A.p[A.n] == 0) { 301 return; 302 } 303 304 if (plus_eq == -1) { 305 // y -= A*x 306 if (skip_diag) { 307 for (j = 0; j < A.n; j++) { 308 for (k = A.p[j]; k < A.p[j + 1]; k++) { 309 i = A.i[k]; 310 y[j] -= i == j ? 0 : A.x[k] * x[i]; 311 } 312 } 313 } else { 314 for (j = 0; j < A.n; j++) { 315 for (k = A.p[j]; k < A.p[j + 1]; k++) { 316 y[j] -= A.x[k] * x[A.i[k]]; 317 } 318 } 319 } 320 } else { 321 // y += A*x 322 if (skip_diag) { 323 for (j = 0; j < A.n; j++) { 324 for (k = A.p[j]; k < A.p[j + 1]; k++) { 325 i = A.i[k]; 326 y[j] += i == j ? 0 : A.x[k] * x[i]; 327 } 328 } 329 } else { 330 for (j = 0; j < A.n; j++) { 331 for (k = A.p[j]; k < A.p[j + 1]; k++) { 332 y[j] += A.x[k] * x[A.i[k]]; 333 } 334 } 335 } 336 } 337 } 338 339 version(EMBEDDED_1){} 340 else { 341 void mat_inf_norm_cols(const csc *M, c_float *E) { 342 c_int j; 343 c_int ptr; 344 345 // Initialize zero max elements 346 for (j = 0; j < M.n; j++) { 347 E[j] = 0.; 348 } 349 350 // Compute maximum across columns 351 for (j = 0; j < M.n; j++) { 352 for (ptr = M.p[j]; ptr < M.p[j + 1]; ptr++) { 353 E[j] = c_max(c_absval(M.x[ptr]), E[j]); 354 } 355 } 356 } 357 358 void mat_inf_norm_rows(const csc *M, c_float *E) { 359 c_int i; 360 c_int j; 361 c_int ptr; 362 363 // Initialize zero max elements 364 for (j = 0; j < M.m; j++) { 365 E[j] = 0.; 366 } 367 368 // Compute maximum across rows 369 for (j = 0; j < M.n; j++) { 370 for (ptr = M.p[j]; ptr < M.p[j + 1]; ptr++) { 371 i = M.i[ptr]; 372 E[i] = c_max(c_absval(M.x[ptr]), E[i]); 373 } 374 } 375 } 376 377 void mat_inf_norm_cols_sym_triu(const csc *M, c_float *E) { 378 c_int i; 379 c_int j; 380 c_int ptr; 381 c_float abs_x; 382 383 // Initialize zero max elements 384 for (j = 0; j < M.n; j++) { 385 E[j] = 0.; 386 } 387 388 // Compute maximum across columns 389 // Note that element (i, j) contributes to 390 // . Column j (as expected in any matrices) 391 // . Column i (which is equal to row i for symmetric matrices) 392 for (j = 0; j < M.n; j++) { 393 for (ptr = M.p[j]; ptr < M.p[j + 1]; ptr++) { 394 i = M.i[ptr]; 395 abs_x = c_absval(M.x[ptr]); 396 E[j] = c_max(abs_x, E[j]); 397 398 if (i != j) { 399 E[i] = c_max(abs_x, E[i]); 400 } 401 } 402 } 403 } 404 } /* if EMBEDDED != 1 */ 405 406 407 c_float quad_form(const csc *P, const c_float *x) { 408 c_float quad_form = 0.; 409 c_int i; 410 c_int j; 411 c_int ptr; // Pointers to iterate over 412 // matrix: (i,j) a element 413 // pointer 414 415 for (j = 0; j < P.n; j++) { // Iterate over columns 416 for (ptr = P.p[j]; ptr < P.p[j + 1]; ptr++) { // Iterate over rows 417 i = P.i[ptr]; // Row index 418 419 if (i == j) { // Diagonal element 420 quad_form += cast(c_float).5 * P.x[ptr] * x[i] * x[i]; 421 } 422 else if (i < j) { // Off-diagonal element 423 quad_form += P.x[ptr] * x[i] * x[j]; 424 } 425 else { // Element in lower diagonal 426 // part 427 version(PRINTING){ 428 c_eprint("ERROR in %s: quad_form matrix is not upper triangular\n", __FUNCTION__.ptr); 429 } /* ifdef PRINTING */ 430 return cast(c_float)OSQP_NULL; 431 } 432 } 433 } 434 return quad_form; 435 }