casadi_norm_inf_mul.hpp
1 //
2 // MIT No Attribution
3 //
4 // Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl, KU Leuven.
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy of this
7 // software and associated documentation files (the "Software"), to deal in the Software
8 // without restriction, including without limitation the rights to use, copy, modify,
9 // merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13 // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
15 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
16 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
17 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18 //
19 
20 // C-REPLACE "fmax" "casadi_fmax"
21 // C-REPLACE "fabs" "casadi_fabs"
22 
23 // SYMBOL "norm_inf_mul"
24 template<typename T1>
25 T1 casadi_norm_inf_mul(const T1* x, const casadi_int* sp_x, const T1* y, const casadi_int* sp_y, T1* dwork, casadi_int* iwork) { // NOLINT(whitespace/line_length)
26  casadi_int nrow_x, ncol_x, ncol_y, i, jj, kk, nnz;
27  const casadi_int *colind_x, *row_x, *colind_y, *row_y;
28  casadi_int *mask, *next;
29 
30  T1 res = 0;
31  // Get sparsities
32  nrow_x = sp_x[0]; ncol_x = sp_x[1];
33  colind_x = sp_x+2; row_x = sp_x + 2 + ncol_x+1;
34  ncol_y = sp_y[1];
35  colind_y = sp_y+2; row_y = sp_y + 2 + ncol_y+1;
36 
37  // Implementation inspired on Scipy's sparsetools/csr.h
38  // method that uses O(n) temp storage
39  mask = iwork + ncol_y+1;
40 
41  // Pass 1
42  for (i=0; i<nrow_x; ++i) mask[i] = -1;
43  iwork[0] = 0;
44  nnz = 0;
45  for (i=0; i<ncol_y; ++i) {
46  casadi_int next_nnz;
47  casadi_int row_nnz = 0;
48  for (jj=colind_y[i]; jj < colind_y[i+1]; jj++) {
49  casadi_int j = row_y[jj];
50  for (kk=colind_x[j]; kk < colind_x[j+1]; kk++) {
51  casadi_int k = row_x[kk];
52  if (mask[k] != i) {
53  mask[k] = i;
54  row_nnz++;
55  }
56  }
57  }
58  next_nnz = nnz + row_nnz;
59  nnz = next_nnz;
60  iwork[i+1] = nnz;
61  }
62 
63  // Pass 2
64  next = iwork + ncol_y+1;
65  for (i=0; i<nrow_x; ++i) next[i] = -1;
66  T1* sums = dwork;
67  for (i=0; i<nrow_x; ++i) sums[i] = 0;
68  nnz = 0;
69  iwork[0] = 0;
70  for (i=0; i<ncol_y; ++i) {
71  casadi_int head, length, jj_start, jj_end;
72  head = -2;
73  length = 0;
74  jj_start = colind_y[i];
75  jj_end = colind_y[i+1];
76  for (jj=jj_start; jj<jj_end; ++jj) {
77  casadi_int j, kk_start, kk_end;
78  T1 v;
79  j = row_y[jj];
80  v = y[jj];
81  kk_start = colind_x[j];
82  kk_end = colind_x[j+1];
83  for (kk = kk_start; kk<kk_end; ++kk) {
84  casadi_int k = row_x[kk];
85  sums[k] += v*x[kk];
86  if (next[k] == -1) {
87  next[k] = head;
88  head = k;
89  length++;
90  }
91  }
92  }
93  for (jj=0; jj<length; ++jj) {
94  casadi_int temp;
95  if (!is_zero(sums[head])) {
96  T1 a = fabs(sums[head]);
97  res = fmax(res, a);
98  nnz++;
99  }
100  temp = head;
101  head = next[head];
102  next[temp] = -1; //clear arrays
103  sums[temp] = 0;
104  }
105  iwork[i+1] = nnz;
106  }
107  return res;
108 }
bool is_zero(const T &x)