casadi_ldl.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 "ldl"
21 // Calculate the nonzeros of the transposed L factor (strictly lower entries only)
22 // as well as D for an LDL^T factorization
23 // len[w] >= n
24 template<typename T1>
25 void casadi_ldl(const casadi_int* sp_a, const T1* a,
26  const casadi_int* sp_lt, T1* lt, T1* d, const casadi_int* p, T1* w) {
27  const casadi_int *lt_colind, *lt_row, *a_colind, *a_row;
28  casadi_int n, r, c, c1, k, k2;
29  // Extract sparsities
30  n=sp_lt[1];
31  lt_colind=sp_lt+2; lt_row=sp_lt+2+n+1;
32  a_colind=sp_a+2; a_row=sp_a+2+n+1;
33  // Clear w
34  for (r=0; r<n; ++r) w[r] = 0;
35  // Sparse copy of A to L and D
36  for (c=0; c<n; ++c) {
37  c1 = p[c];
38  for (k=a_colind[c1]; k<a_colind[c1+1]; ++k) w[a_row[k]] = a[k];
39  for (k=lt_colind[c]; k<lt_colind[c+1]; ++k) lt[k] = w[p[lt_row[k]]];
40  d[c] = w[p[c]];
41  for (k=a_colind[c1]; k<a_colind[c1+1]; ++k) w[a_row[k]] = 0;
42  }
43  // Loop over columns of L
44  for (c=0; c<n; ++c) {
45  for (k=lt_colind[c]; k<lt_colind[c+1]; ++k) {
46  r = lt_row[k];
47  // Calculate l(r,c) with r<c
48  for (k2=lt_colind[r]; k2<lt_colind[r+1]; ++k2) {
49  lt[k] -= lt[k2] * w[lt_row[k2]];
50  }
51  w[r] = lt[k];
52  lt[k] /= d[r];
53  // Update d(c)
54  d[c] -= w[r]*lt[k];
55  }
56  // Clear w
57  for (k=lt_colind[c]; k<lt_colind[c+1]; ++k) w[lt_row[k]] = 0;
58  }
59 }
60 
61 // SYMBOL "ldl_trs"
62 // Solve for (I+R) with R an optionally transposed strictly upper triangular matrix.
63 template<typename T1>
64 void casadi_ldl_trs(const casadi_int* sp_r, const T1* nz_r, T1* x, casadi_int tr) {
65  casadi_int ncol, c, k;
66  const casadi_int *colind, *row;
67  // Extract sparsity
68  ncol=sp_r[1];
69  colind=sp_r+2; row=sp_r+2+ncol+1;
70  if (tr) {
71  // Forward substitution
72  for (c=0; c<ncol; ++c) {
73  for (k=colind[c]; k<colind[c+1]; ++k) {
74  x[c] -= nz_r[k]*x[row[k]];
75  }
76  }
77  } else {
78  // Backward substitution
79  for (c=ncol-1; c>=0; --c) {
80  for (k=colind[c+1]-1; k>=colind[c]; --k) {
81  x[row[k]] -= nz_r[k]*x[c];
82  }
83  }
84  }
85 }
86 
87 // SYMBOL "ldl_solve"
88 // Linear solve using an LDL^T factorized linear system
89 template<typename T1>
90 void casadi_ldl_solve(T1* x, casadi_int nrhs, const casadi_int* sp_lt, const T1* lt,
91  const T1* d, const casadi_int* p, T1* w) {
92  casadi_int i, k;
93  casadi_int n = sp_lt[1];
94  for (k=0; k<nrhs; ++k) {
95  // P' L D L' P x = b <=> x = P' L' \ D \ L \ P b
96  // Multiply by P
97  for (i=0; i<n; ++i) w[i] = x[p[i]];
98  // Solve for L
99  casadi_ldl_trs(sp_lt, lt, w, 1);
100  // Divide by D
101  for (i=0; i<n; ++i) w[i] /= d[i];
102  // Solve for L'
103  casadi_ldl_trs(sp_lt, lt, w, 0);
104  // Multiply by P'
105  for (i=0; i<n; ++i) x[p[i]] = w[i];
106  // Next rhs
107  x += n;
108  }
109 }