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