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 }