casadi_kron_contract_outer_sparse_dense.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 // SYMBOL "kron_contract_outer_sparse_dense"
21 // y[r,s] = sum_{i,j} a[i,j] * m[i*mB+r, j*nB+s]
22 // where m has CSC sparsity sp_m (mA*mB, nA*nB), a is dense (mA, nA),
23 // y has CSC sparsity sp_y (mB, nB). Walks m's nonzeros only.
24 template<typename T1>
25 void casadi_kron_contract_outer_sparse_dense(const T1* m, const casadi_int* sp_m,
26  const T1* a, casadi_int mA, casadi_int nA,
27  T1* y, const casadi_int* sp_y) {
28  casadi_int nB = sp_y[1];
29  const casadi_int* y_colind = sp_y+2;
30  const casadi_int* y_row = sp_y+2+nB+1;
31  casadi_int m_ncol = sp_m[1];
32  casadi_int mB = sp_y[0];
33  const casadi_int* m_colind = sp_m+2;
34  const casadi_int* m_row = sp_m+2+m_ncol+1;
35  casadi_int cc, j, s, el, rr, i, r, y_el, y_col_start, y_col_end, k;
36  T1 a_val;
37  for (k=0; k<y_colind[nB]; ++k) y[k] = 0;
38  // Nested (j, s) loop avoids per-column cc / nB and cc % nB.
39  for (j=0; j<nA; ++j) {
40  for (s=0; s<nB; ++s) {
41  cc = j*nB + s;
42  y_col_start = y_colind[s];
43  y_col_end = y_colind[s+1];
44  if (y_col_start == y_col_end) continue;
45  for (el=m_colind[cc]; el<m_colind[cc+1]; ++el) {
46  rr = m_row[el];
47  i = rr / mB;
48  r = rr % mB;
49  a_val = a[j*mA + i];
50  for (y_el=y_col_start; y_el<y_col_end; ++y_el) {
51  if (y_row[y_el] == r) { y[y_el] += a_val * m[el]; break; }
52  if (y_row[y_el] > r) break;
53  }
54  }
55  }
56  }
57 }