casadi_kron_contract_inner.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_inner"
21 // Y[i,j] = sum over (r,s) of M[i*mB+r, j*nB+s] * B[r,s]
22 // where M has CSC sparsity sp_m of size (mA*mB)x(nA*nB),
23 // B has CSC sparsity sp_b of size mB x nB,
24 // Y has CSC sparsity sp_y of size mA x nA.
25 // w is scratch of length mB*nB used to densify b.
26 template<typename T1>
27 void casadi_kron_contract_inner(const T1* m, const casadi_int* sp_m,
28  const T1* b, const casadi_int* sp_b,
29  T1* y, const casadi_int* sp_y,
30  T1* w) {
31  casadi_int nA = sp_y[1];
32  const casadi_int* y_colind = sp_y+2;
33  const casadi_int* y_row = sp_y+2+nA+1;
34  casadi_int mB = sp_b[0];
35  casadi_int nB = sp_b[1];
36  const casadi_int* b_colind = sp_b+2;
37  const casadi_int* b_row = sp_b+2+nB+1;
38  casadi_int m_ncol = sp_m[1];
39  const casadi_int* m_colind = sp_m+2;
40  const casadi_int* m_row = sp_m+2+m_ncol+1;
41 
42  casadi_int k, cc, el, j, s, rr, i, r, y_el, y_col_start, y_col_end;
43  T1 b_val;
44 
45  // Densify b into w (column-major, mB*nB entries)
46  for (k=0; k<mB*nB; ++k) w[k] = 0;
47  for (cc=0; cc<nB; ++cc) {
48  for (el=b_colind[cc]; el<b_colind[cc+1]; ++el) {
49  w[cc*mB + b_row[el]] = b[el];
50  }
51  }
52 
53  // Zero y
54  for (k=0; k<y_colind[nA]; ++k) y[k] = 0;
55 
56  // Walk M block-column by block-column; (j, s) ARE the column decomposition
57  // (no per-column / or %). Row decomposition still uses / and % per nonzero.
58  for (j=0; j<nA; ++j) {
59  y_col_start = y_colind[j];
60  y_col_end = y_colind[j+1];
61  if (y_col_start == y_col_end) continue;
62  for (s=0; s<nB; ++s) {
63  cc = j*nB + s;
64  for (el=m_colind[cc]; el<m_colind[cc+1]; ++el) {
65  rr = m_row[el];
66  i = rr / mB;
67  r = rr % mB;
68  b_val = w[s*mB + r];
69  // Linear scan y's column j for row i. y_row is sorted ascending.
70  for (y_el=y_col_start; y_el<y_col_end; ++y_el) {
71  if (y_row[y_el] == i) { y[y_el] += m[el] * b_val; break; }
72  if (y_row[y_el] > i) break;
73  }
74  }
75  }
76  }
77 }