conspire/math/tensor/rank_2/inverse/
mod.rs1#[cfg(test)]
2mod test;
3
4use super::{Rank2, Tensor, TensorArray, TensorRank0, TensorRank2};
5use crate::ABS_TOL;
6
7impl<const D: usize, const I: usize, const J: usize> TensorRank2<D, I, J> {
8 pub fn determinant(&self) -> TensorRank0 {
10 if D == 2 {
11 self[0][0] * self[1][1] - self[0][1] * self[1][0]
12 } else if D == 3 {
13 let c_00 = self[1][1] * self[2][2] - self[1][2] * self[2][1];
14 let c_10 = self[1][2] * self[2][0] - self[1][0] * self[2][2];
15 let c_20 = self[1][0] * self[2][1] - self[1][1] * self[2][0];
16 self[0][0] * c_00 + self[0][1] * c_10 + self[0][2] * c_20
17 } else if D == 4 {
18 let s0 = self[0][0] * self[1][1] - self[0][1] * self[1][0];
19 let s1 = self[0][0] * self[1][2] - self[0][2] * self[1][0];
20 let s2 = self[0][0] * self[1][3] - self[0][3] * self[1][0];
21 let s3 = self[0][1] * self[1][2] - self[0][2] * self[1][1];
22 let s4 = self[0][1] * self[1][3] - self[0][3] * self[1][1];
23 let s5 = self[0][2] * self[1][3] - self[0][3] * self[1][2];
24 let c5 = self[2][2] * self[3][3] - self[2][3] * self[3][2];
25 let c4 = self[2][1] * self[3][3] - self[2][3] * self[3][1];
26 let c3 = self[2][1] * self[3][2] - self[2][2] * self[3][1];
27 let c2 = self[2][0] * self[3][3] - self[2][3] * self[3][0];
28 let c1 = self[2][0] * self[3][2] - self[2][2] * self[3][0];
29 let c0 = self[2][0] * self[3][1] - self[2][1] * self[3][0];
30 s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0
31 } else {
32 let (_, u, p) = self.lu_decomposition();
33 let num_swaps = p.iter().enumerate().filter(|(i, p_i)| p_i != &i).count();
34 u.into_iter()
35 .enumerate()
36 .map(|(i, u_i)| u_i[i])
37 .product::<TensorRank0>()
38 * if num_swaps % 2 == 0 { 1.0 } else { -1.0 }
39 }
40 }
41 pub fn inverse(&self) -> TensorRank2<D, J, I> {
43 if D == 2 {
44 let mut adjugate = TensorRank2::<D, J, I>::zero();
45 adjugate[0][0] = self[1][1];
46 adjugate[0][1] = -self[0][1];
47 adjugate[1][0] = -self[1][0];
48 adjugate[1][1] = self[0][0];
49 adjugate / self.determinant()
50 } else if D == 3 {
51 let mut adjugate = TensorRank2::<D, J, I>::zero();
52 let c_00 = self[1][1] * self[2][2] - self[1][2] * self[2][1];
53 let c_10 = self[1][2] * self[2][0] - self[1][0] * self[2][2];
54 let c_20 = self[1][0] * self[2][1] - self[1][1] * self[2][0];
55 adjugate[0][0] = c_00;
56 adjugate[0][1] = self[0][2] * self[2][1] - self[0][1] * self[2][2];
57 adjugate[0][2] = self[0][1] * self[1][2] - self[0][2] * self[1][1];
58 adjugate[1][0] = c_10;
59 adjugate[1][1] = self[0][0] * self[2][2] - self[0][2] * self[2][0];
60 adjugate[1][2] = self[0][2] * self[1][0] - self[0][0] * self[1][2];
61 adjugate[2][0] = c_20;
62 adjugate[2][1] = self[0][1] * self[2][0] - self[0][0] * self[2][1];
63 adjugate[2][2] = self[0][0] * self[1][1] - self[0][1] * self[1][0];
64 adjugate / (self[0][0] * c_00 + self[0][1] * c_10 + self[0][2] * c_20)
65 } else if D == 4 {
66 let mut adjugate = TensorRank2::<D, J, I>::zero();
67 let s0 = self[0][0] * self[1][1] - self[0][1] * self[1][0];
68 let s1 = self[0][0] * self[1][2] - self[0][2] * self[1][0];
69 let s2 = self[0][0] * self[1][3] - self[0][3] * self[1][0];
70 let s3 = self[0][1] * self[1][2] - self[0][2] * self[1][1];
71 let s4 = self[0][1] * self[1][3] - self[0][3] * self[1][1];
72 let s5 = self[0][2] * self[1][3] - self[0][3] * self[1][2];
73 let c5 = self[2][2] * self[3][3] - self[2][3] * self[3][2];
74 let c4 = self[2][1] * self[3][3] - self[2][3] * self[3][1];
75 let c3 = self[2][1] * self[3][2] - self[2][2] * self[3][1];
76 let c2 = self[2][0] * self[3][3] - self[2][3] * self[3][0];
77 let c1 = self[2][0] * self[3][2] - self[2][2] * self[3][0];
78 let c0 = self[2][0] * self[3][1] - self[2][1] * self[3][0];
79 adjugate[0][0] = self[1][1] * c5 - self[1][2] * c4 + self[1][3] * c3;
80 adjugate[0][1] = self[0][2] * c4 - self[0][1] * c5 - self[0][3] * c3;
81 adjugate[0][2] = self[3][1] * s5 - self[3][2] * s4 + self[3][3] * s3;
82 adjugate[0][3] = self[2][2] * s4 - self[2][1] * s5 - self[2][3] * s3;
83 adjugate[1][0] = self[1][2] * c2 - self[1][0] * c5 - self[1][3] * c1;
84 adjugate[1][1] = self[0][0] * c5 - self[0][2] * c2 + self[0][3] * c1;
85 adjugate[1][2] = self[3][2] * s2 - self[3][0] * s5 - self[3][3] * s1;
86 adjugate[1][3] = self[2][0] * s5 - self[2][2] * s2 + self[2][3] * s1;
87 adjugate[2][0] = self[1][0] * c4 - self[1][1] * c2 + self[1][3] * c0;
88 adjugate[2][1] = self[0][1] * c2 - self[0][0] * c4 - self[0][3] * c0;
89 adjugate[2][2] = self[3][0] * s4 - self[3][1] * s2 + self[3][3] * s0;
90 adjugate[2][3] = self[2][1] * s2 - self[2][0] * s4 - self[2][3] * s0;
91 adjugate[3][0] = self[1][1] * c1 - self[1][0] * c3 - self[1][2] * c0;
92 adjugate[3][1] = self[0][0] * c3 - self[0][1] * c1 + self[0][2] * c0;
93 adjugate[3][2] = self[3][1] * s1 - self[3][0] * s3 - self[3][2] * s0;
94 adjugate[3][3] = self[2][0] * s3 - self[2][1] * s1 + self[2][2] * s0;
95 adjugate / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0)
96 } else {
97 let (l_inverse, u_inverse, p) = self.lu_decomposition_inverse();
98 let mut q = [0; D];
99 p.into_iter().enumerate().for_each(|(i, p_i)| q[p_i] = i);
100 u_inverse
101 .into_iter()
102 .map(|u_inverse_i| {
103 q.iter()
104 .map(|&q_j| {
105 u_inverse_i
106 .iter()
107 .zip(l_inverse.iter())
108 .map(|(u_inverse_ik, l_inverse_k)| u_inverse_ik * l_inverse_k[q_j])
109 .sum()
110 })
111 .collect()
112 })
113 .collect()
114 }
115 }
116 pub fn inverse_and_determinant(&self) -> (TensorRank2<D, J, I>, TensorRank0) {
118 if D == 2 {
119 let mut adjugate = TensorRank2::<D, J, I>::zero();
120 adjugate[0][0] = self[1][1];
121 adjugate[0][1] = -self[0][1];
122 adjugate[1][0] = -self[1][0];
123 adjugate[1][1] = self[0][0];
124 let determinant = self.determinant();
125 (adjugate / determinant, determinant)
126 } else if D == 3 {
127 let mut adjugate = TensorRank2::<D, J, I>::zero();
128 let c_00 = self[1][1] * self[2][2] - self[1][2] * self[2][1];
129 let c_10 = self[1][2] * self[2][0] - self[1][0] * self[2][2];
130 let c_20 = self[1][0] * self[2][1] - self[1][1] * self[2][0];
131 let determinant = self[0][0] * c_00 + self[0][1] * c_10 + self[0][2] * c_20;
132 adjugate[0][0] = c_00;
133 adjugate[0][1] = self[0][2] * self[2][1] - self[0][1] * self[2][2];
134 adjugate[0][2] = self[0][1] * self[1][2] - self[0][2] * self[1][1];
135 adjugate[1][0] = c_10;
136 adjugate[1][1] = self[0][0] * self[2][2] - self[0][2] * self[2][0];
137 adjugate[1][2] = self[0][2] * self[1][0] - self[0][0] * self[1][2];
138 adjugate[2][0] = c_20;
139 adjugate[2][1] = self[0][1] * self[2][0] - self[0][0] * self[2][1];
140 adjugate[2][2] = self[0][0] * self[1][1] - self[0][1] * self[1][0];
141 (adjugate / determinant, determinant)
142 } else if D == 4 {
143 let mut adjugate = TensorRank2::<D, J, I>::zero();
144 let s0 = self[0][0] * self[1][1] - self[0][1] * self[1][0];
145 let s1 = self[0][0] * self[1][2] - self[0][2] * self[1][0];
146 let s2 = self[0][0] * self[1][3] - self[0][3] * self[1][0];
147 let s3 = self[0][1] * self[1][2] - self[0][2] * self[1][1];
148 let s4 = self[0][1] * self[1][3] - self[0][3] * self[1][1];
149 let s5 = self[0][2] * self[1][3] - self[0][3] * self[1][2];
150 let c5 = self[2][2] * self[3][3] - self[2][3] * self[3][2];
151 let c4 = self[2][1] * self[3][3] - self[2][3] * self[3][1];
152 let c3 = self[2][1] * self[3][2] - self[2][2] * self[3][1];
153 let c2 = self[2][0] * self[3][3] - self[2][3] * self[3][0];
154 let c1 = self[2][0] * self[3][2] - self[2][2] * self[3][0];
155 let c0 = self[2][0] * self[3][1] - self[2][1] * self[3][0];
156 let determinant = s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0;
157 adjugate[0][0] = self[1][1] * c5 - self[1][2] * c4 + self[1][3] * c3;
158 adjugate[0][1] = self[0][2] * c4 - self[0][1] * c5 - self[0][3] * c3;
159 adjugate[0][2] = self[3][1] * s5 - self[3][2] * s4 + self[3][3] * s3;
160 adjugate[0][3] = self[2][2] * s4 - self[2][1] * s5 - self[2][3] * s3;
161 adjugate[1][0] = self[1][2] * c2 - self[1][0] * c5 - self[1][3] * c1;
162 adjugate[1][1] = self[0][0] * c5 - self[0][2] * c2 + self[0][3] * c1;
163 adjugate[1][2] = self[3][2] * s2 - self[3][0] * s5 - self[3][3] * s1;
164 adjugate[1][3] = self[2][0] * s5 - self[2][2] * s2 + self[2][3] * s1;
165 adjugate[2][0] = self[1][0] * c4 - self[1][1] * c2 + self[1][3] * c0;
166 adjugate[2][1] = self[0][1] * c2 - self[0][0] * c4 - self[0][3] * c0;
167 adjugate[2][2] = self[3][0] * s4 - self[3][1] * s2 + self[3][3] * s0;
168 adjugate[2][3] = self[2][1] * s2 - self[2][0] * s4 - self[2][3] * s0;
169 adjugate[3][0] = self[1][1] * c1 - self[1][0] * c3 - self[1][2] * c0;
170 adjugate[3][1] = self[0][0] * c3 - self[0][1] * c1 + self[0][2] * c0;
171 adjugate[3][2] = self[3][1] * s1 - self[3][0] * s3 - self[3][2] * s0;
172 adjugate[3][3] = self[2][0] * s3 - self[2][1] * s1 + self[2][2] * s0;
173 (adjugate / determinant, determinant)
174 } else {
175 (self.inverse(), self.determinant())
176 }
177 }
178 pub fn inverse_transpose(&self) -> Self {
180 if D == 2 {
181 let mut adjugate_transpose = TensorRank2::<D, I, J>::zero();
182 adjugate_transpose[0][0] = self[1][1];
183 adjugate_transpose[0][1] = -self[1][0];
184 adjugate_transpose[1][0] = -self[0][1];
185 adjugate_transpose[1][1] = self[0][0];
186 adjugate_transpose / self.determinant()
187 } else if D == 3 {
188 let mut adjugate_transpose = TensorRank2::<D, I, J>::zero();
189 let c_00 = self[1][1] * self[2][2] - self[1][2] * self[2][1];
190 let c_10 = self[1][2] * self[2][0] - self[1][0] * self[2][2];
191 let c_20 = self[1][0] * self[2][1] - self[1][1] * self[2][0];
192 adjugate_transpose[0][0] = c_00;
193 adjugate_transpose[1][0] = self[0][2] * self[2][1] - self[0][1] * self[2][2];
194 adjugate_transpose[2][0] = self[0][1] * self[1][2] - self[0][2] * self[1][1];
195 adjugate_transpose[0][1] = c_10;
196 adjugate_transpose[1][1] = self[0][0] * self[2][2] - self[0][2] * self[2][0];
197 adjugate_transpose[2][1] = self[0][2] * self[1][0] - self[0][0] * self[1][2];
198 adjugate_transpose[0][2] = c_20;
199 adjugate_transpose[1][2] = self[0][1] * self[2][0] - self[0][0] * self[2][1];
200 adjugate_transpose[2][2] = self[0][0] * self[1][1] - self[0][1] * self[1][0];
201 adjugate_transpose / (self[0][0] * c_00 + self[0][1] * c_10 + self[0][2] * c_20)
202 } else if D == 4 {
203 let mut adjugate_transpose = TensorRank2::<D, I, J>::zero();
204 let s0 = self[0][0] * self[1][1] - self[0][1] * self[1][0];
205 let s1 = self[0][0] * self[1][2] - self[0][2] * self[1][0];
206 let s2 = self[0][0] * self[1][3] - self[0][3] * self[1][0];
207 let s3 = self[0][1] * self[1][2] - self[0][2] * self[1][1];
208 let s4 = self[0][1] * self[1][3] - self[0][3] * self[1][1];
209 let s5 = self[0][2] * self[1][3] - self[0][3] * self[1][2];
210 let c5 = self[2][2] * self[3][3] - self[2][3] * self[3][2];
211 let c4 = self[2][1] * self[3][3] - self[2][3] * self[3][1];
212 let c3 = self[2][1] * self[3][2] - self[2][2] * self[3][1];
213 let c2 = self[2][0] * self[3][3] - self[2][3] * self[3][0];
214 let c1 = self[2][0] * self[3][2] - self[2][2] * self[3][0];
215 let c0 = self[2][0] * self[3][1] - self[2][1] * self[3][0];
216 adjugate_transpose[0][0] = self[1][1] * c5 - self[1][2] * c4 + self[1][3] * c3;
217 adjugate_transpose[1][0] = self[0][2] * c4 - self[0][1] * c5 - self[0][3] * c3;
218 adjugate_transpose[2][0] = self[3][1] * s5 - self[3][2] * s4 + self[3][3] * s3;
219 adjugate_transpose[3][0] = self[2][2] * s4 - self[2][1] * s5 - self[2][3] * s3;
220 adjugate_transpose[0][1] = self[1][2] * c2 - self[1][0] * c5 - self[1][3] * c1;
221 adjugate_transpose[1][1] = self[0][0] * c5 - self[0][2] * c2 + self[0][3] * c1;
222 adjugate_transpose[2][1] = self[3][2] * s2 - self[3][0] * s5 - self[3][3] * s1;
223 adjugate_transpose[3][1] = self[2][0] * s5 - self[2][2] * s2 + self[2][3] * s1;
224 adjugate_transpose[0][2] = self[1][0] * c4 - self[1][1] * c2 + self[1][3] * c0;
225 adjugate_transpose[1][2] = self[0][1] * c2 - self[0][0] * c4 - self[0][3] * c0;
226 adjugate_transpose[2][2] = self[3][0] * s4 - self[3][1] * s2 + self[3][3] * s0;
227 adjugate_transpose[3][2] = self[2][1] * s2 - self[2][0] * s4 - self[2][3] * s0;
228 adjugate_transpose[0][3] = self[1][1] * c1 - self[1][0] * c3 - self[1][2] * c0;
229 adjugate_transpose[1][3] = self[0][0] * c3 - self[0][1] * c1 + self[0][2] * c0;
230 adjugate_transpose[2][3] = self[3][1] * s1 - self[3][0] * s3 - self[3][2] * s0;
231 adjugate_transpose[3][3] = self[2][0] * s3 - self[2][1] * s1 + self[2][2] * s0;
232 adjugate_transpose / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0)
233 } else {
234 self.inverse().transpose()
235 }
236 }
237 pub fn inverse_transpose_and_determinant(&self) -> (Self, TensorRank0) {
239 if D == 2 {
240 let mut adjugate_transpose = TensorRank2::<D, I, J>::zero();
241 adjugate_transpose[0][0] = self[1][1];
242 adjugate_transpose[0][1] = -self[1][0];
243 adjugate_transpose[1][0] = -self[0][1];
244 adjugate_transpose[1][1] = self[0][0];
245 let determinant = self.determinant();
246 (adjugate_transpose / determinant, determinant)
247 } else if D == 3 {
248 let mut adjugate_transpose = TensorRank2::<D, I, J>::zero();
249 let c_00 = self[1][1] * self[2][2] - self[1][2] * self[2][1];
250 let c_10 = self[1][2] * self[2][0] - self[1][0] * self[2][2];
251 let c_20 = self[1][0] * self[2][1] - self[1][1] * self[2][0];
252 let determinant = self[0][0] * c_00 + self[0][1] * c_10 + self[0][2] * c_20;
253 adjugate_transpose[0][0] = c_00;
254 adjugate_transpose[1][0] = self[0][2] * self[2][1] - self[0][1] * self[2][2];
255 adjugate_transpose[2][0] = self[0][1] * self[1][2] - self[0][2] * self[1][1];
256 adjugate_transpose[0][1] = c_10;
257 adjugate_transpose[1][1] = self[0][0] * self[2][2] - self[0][2] * self[2][0];
258 adjugate_transpose[2][1] = self[0][2] * self[1][0] - self[0][0] * self[1][2];
259 adjugate_transpose[0][2] = c_20;
260 adjugate_transpose[1][2] = self[0][1] * self[2][0] - self[0][0] * self[2][1];
261 adjugate_transpose[2][2] = self[0][0] * self[1][1] - self[0][1] * self[1][0];
262 (adjugate_transpose / determinant, determinant)
263 } else if D == 4 {
264 let mut adjugate_transpose = TensorRank2::<D, I, J>::zero();
265 let s0 = self[0][0] * self[1][1] - self[0][1] * self[1][0];
266 let s1 = self[0][0] * self[1][2] - self[0][2] * self[1][0];
267 let s2 = self[0][0] * self[1][3] - self[0][3] * self[1][0];
268 let s3 = self[0][1] * self[1][2] - self[0][2] * self[1][1];
269 let s4 = self[0][1] * self[1][3] - self[0][3] * self[1][1];
270 let s5 = self[0][2] * self[1][3] - self[0][3] * self[1][2];
271 let c5 = self[2][2] * self[3][3] - self[2][3] * self[3][2];
272 let c4 = self[2][1] * self[3][3] - self[2][3] * self[3][1];
273 let c3 = self[2][1] * self[3][2] - self[2][2] * self[3][1];
274 let c2 = self[2][0] * self[3][3] - self[2][3] * self[3][0];
275 let c1 = self[2][0] * self[3][2] - self[2][2] * self[3][0];
276 let c0 = self[2][0] * self[3][1] - self[2][1] * self[3][0];
277 let determinant = s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0;
278 adjugate_transpose[0][0] = self[1][1] * c5 - self[1][2] * c4 + self[1][3] * c3;
279 adjugate_transpose[1][0] = self[0][2] * c4 - self[0][1] * c5 - self[0][3] * c3;
280 adjugate_transpose[2][0] = self[3][1] * s5 - self[3][2] * s4 + self[3][3] * s3;
281 adjugate_transpose[3][0] = self[2][2] * s4 - self[2][1] * s5 - self[2][3] * s3;
282 adjugate_transpose[0][1] = self[1][2] * c2 - self[1][0] * c5 - self[1][3] * c1;
283 adjugate_transpose[1][1] = self[0][0] * c5 - self[0][2] * c2 + self[0][3] * c1;
284 adjugate_transpose[2][1] = self[3][2] * s2 - self[3][0] * s5 - self[3][3] * s1;
285 adjugate_transpose[3][1] = self[2][0] * s5 - self[2][2] * s2 + self[2][3] * s1;
286 adjugate_transpose[0][2] = self[1][0] * c4 - self[1][1] * c2 + self[1][3] * c0;
287 adjugate_transpose[1][2] = self[0][1] * c2 - self[0][0] * c4 - self[0][3] * c0;
288 adjugate_transpose[2][2] = self[3][0] * s4 - self[3][1] * s2 + self[3][3] * s0;
289 adjugate_transpose[3][2] = self[2][1] * s2 - self[2][0] * s4 - self[2][3] * s0;
290 adjugate_transpose[0][3] = self[1][1] * c1 - self[1][0] * c3 - self[1][2] * c0;
291 adjugate_transpose[1][3] = self[0][0] * c3 - self[0][1] * c1 + self[0][2] * c0;
292 adjugate_transpose[2][3] = self[3][1] * s1 - self[3][0] * s3 - self[3][2] * s0;
293 adjugate_transpose[3][3] = self[2][0] * s3 - self[2][1] * s1 + self[2][2] * s0;
294 (adjugate_transpose / determinant, determinant)
295 } else {
296 (self.inverse_transpose(), self.determinant())
297 }
298 }
299 pub fn lu_decomposition(&self) -> (TensorRank2<D, I, 88>, TensorRank2<D, 88, J>, Vec<usize>) {
301 let n = D;
302 let mut p: Vec<usize> = (0..n).collect();
303 let mut factor;
304 let mut lu = self.clone();
305 let mut max_row;
306 let mut max_val;
307 let mut pivot;
308 for i in 0..n {
309 max_row = i;
310 max_val = lu[max_row][i].abs();
311 for k in i + 1..n {
312 if lu[k][i].abs() > max_val {
313 max_row = k;
314 max_val = lu[max_row][i].abs();
315 }
316 }
317 if max_row != i {
318 lu.0.swap(i, max_row);
319 p.swap(i, max_row);
320 }
321 pivot = lu[i][i];
322 if pivot.abs() < ABS_TOL {
323 panic!("LU decomposition failed (zero pivot).")
324 }
325 for j in i + 1..n {
326 if lu[j][i] != 0.0 {
327 lu[j][i] /= pivot;
328 factor = lu[j][i];
329 for k in i + 1..n {
330 lu[j][k] -= factor * lu[i][k];
331 }
332 }
333 }
334 }
335 let mut l = TensorRank2::identity();
336 for i in 0..D {
337 for j in 0..i {
338 l[i][j] = lu[i][j]
339 }
340 }
341 let mut u = TensorRank2::zero();
342 for i in 0..D {
343 for j in i..D {
344 u[i][j] = lu[i][j]
345 }
346 }
347 (l, u, p)
348 }
349 pub fn lu_decomposition_inverse(
351 &self,
352 ) -> (TensorRank2<D, I, 88>, TensorRank2<D, 88, J>, Vec<usize>) {
353 let (mut tensor_l, mut tensor_u, p) = self.lu_decomposition();
354 let mut sum;
355 for i in 0..D {
356 tensor_l[i][i] = 1.0 / tensor_l[i][i];
357 for j in 0..i {
358 sum = 0.0;
359 for k in j..i {
360 sum += tensor_l[i][k] * tensor_l[k][j];
361 }
362 tensor_l[i][j] = -sum * tensor_l[i][i];
363 }
364 }
365 for i in 0..D {
366 tensor_u[i][i] = 1.0 / tensor_u[i][i];
367 for j in 0..i {
368 sum = 0.0;
369 for k in j..i {
370 sum += tensor_u[j][k] * tensor_u[k][i];
371 }
372 tensor_u[j][i] = -sum * tensor_u[i][i];
373 }
374 }
375 (tensor_l, tensor_u, p)
376 }
377}