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