conspire/math/tensor/rank_2/
mod.rs

1#[cfg(test)]
2mod test;
3
4pub mod list;
5pub mod list_2d;
6pub mod vec;
7pub mod vec_2d;
8
9use std::{
10    array::{IntoIter, from_fn},
11    f64::consts::TAU,
12    fmt::{self, Display, Formatter},
13    iter::Sum,
14    mem::transmute,
15    ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
16};
17
18use super::{
19    super::assert_eq_within_tols,
20    Hessian, Jacobian, Rank2, Solution, SquareMatrix, Tensor, TensorArray, TensorError, Vector,
21    rank_0::{TensorRank0, list::TensorRank0List},
22    rank_1::{
23        TensorRank1, list::TensorRank1List, tensor_rank_1, vec::TensorRank1Vec,
24        zero as tensor_rank_1_zero,
25    },
26    rank_4::TensorRank4,
27};
28use crate::ABS_TOL;
29use list_2d::TensorRank2List2D;
30use vec_2d::TensorRank2Vec2D;
31
32#[cfg(test)]
33use super::test::ErrorTensor;
34
35/// A *d*-dimensional tensor of rank 2.
36///
37/// `D` is the dimension, `I`, `J` are the configurations.
38#[repr(transparent)]
39#[derive(Clone, Debug, PartialEq)]
40pub struct TensorRank2<const D: usize, const I: usize, const J: usize>([TensorRank1<D, J>; D]);
41
42impl<const D: usize, const I: usize, const J: usize> Default for TensorRank2<D, I, J> {
43    fn default() -> Self {
44        Self::zero()
45    }
46}
47
48pub const fn tensor_rank_2<const D: usize, const I: usize, const J: usize>(
49    array: [TensorRank1<D, J>; D],
50) -> TensorRank2<D, I, J> {
51    TensorRank2(array)
52}
53
54pub const fn get_levi_civita_parts<const I: usize, const J: usize>() -> [TensorRank2<3, I, J>; 3] {
55    [
56        TensorRank2([
57            tensor_rank_1_zero(),
58            tensor_rank_1([0.0, 0.0, 1.0]),
59            tensor_rank_1([0.0, -1.0, 0.0]),
60        ]),
61        TensorRank2([
62            tensor_rank_1([0.0, 0.0, -1.0]),
63            tensor_rank_1_zero(),
64            tensor_rank_1([1.0, 0.0, 0.0]),
65        ]),
66        TensorRank2([
67            tensor_rank_1([0.0, 1.0, 0.0]),
68            tensor_rank_1([-1.0, 0.0, 0.0]),
69            tensor_rank_1_zero(),
70        ]),
71    ]
72}
73
74pub const fn get_identity_1010_parts_1<const I: usize, const J: usize>() -> [TensorRank2<3, I, J>; 3]
75{
76    [
77        TensorRank2([
78            tensor_rank_1([1.0, 0.0, 0.0]),
79            tensor_rank_1_zero(),
80            tensor_rank_1_zero(),
81        ]),
82        TensorRank2([
83            tensor_rank_1([0.0, 1.0, 0.0]),
84            tensor_rank_1_zero(),
85            tensor_rank_1_zero(),
86        ]),
87        TensorRank2([
88            tensor_rank_1([0.0, 0.0, 1.0]),
89            tensor_rank_1_zero(),
90            tensor_rank_1_zero(),
91        ]),
92    ]
93}
94
95pub const fn get_identity_1010_parts_2<const I: usize, const J: usize>() -> [TensorRank2<3, I, J>; 3]
96{
97    [
98        TensorRank2([
99            tensor_rank_1_zero(),
100            tensor_rank_1([1.0, 0.0, 0.0]),
101            tensor_rank_1_zero(),
102        ]),
103        TensorRank2([
104            tensor_rank_1_zero(),
105            tensor_rank_1([0.0, 1.0, 0.0]),
106            tensor_rank_1_zero(),
107        ]),
108        TensorRank2([
109            tensor_rank_1_zero(),
110            tensor_rank_1([0.0, 0.0, 1.0]),
111            tensor_rank_1_zero(),
112        ]),
113    ]
114}
115
116pub const fn get_identity_1010_parts_3<const I: usize, const J: usize>() -> [TensorRank2<3, I, J>; 3]
117{
118    [
119        TensorRank2([
120            tensor_rank_1_zero(),
121            tensor_rank_1_zero(),
122            tensor_rank_1([1.0, 0.0, 0.0]),
123        ]),
124        TensorRank2([
125            tensor_rank_1_zero(),
126            tensor_rank_1_zero(),
127            tensor_rank_1([0.0, 1.0, 0.0]),
128        ]),
129        TensorRank2([
130            tensor_rank_1_zero(),
131            tensor_rank_1_zero(),
132            tensor_rank_1([0.0, 0.0, 1.0]),
133        ]),
134    ]
135}
136
137pub const IDENTITY: TensorRank2<3, 1, 1> = TensorRank2([
138    tensor_rank_1([1.0, 0.0, 0.0]),
139    tensor_rank_1([0.0, 1.0, 0.0]),
140    tensor_rank_1([0.0, 0.0, 1.0]),
141]);
142
143pub const IDENTITY_00: TensorRank2<3, 0, 0> = TensorRank2([
144    tensor_rank_1([1.0, 0.0, 0.0]),
145    tensor_rank_1([0.0, 1.0, 0.0]),
146    tensor_rank_1([0.0, 0.0, 1.0]),
147]);
148
149pub const IDENTITY_10: TensorRank2<3, 1, 0> = TensorRank2([
150    tensor_rank_1([1.0, 0.0, 0.0]),
151    tensor_rank_1([0.0, 1.0, 0.0]),
152    tensor_rank_1([0.0, 0.0, 1.0]),
153]);
154
155pub const IDENTITY_22: TensorRank2<3, 2, 2> = TensorRank2([
156    tensor_rank_1([1.0, 0.0, 0.0]),
157    tensor_rank_1([0.0, 1.0, 0.0]),
158    tensor_rank_1([0.0, 0.0, 1.0]),
159]);
160
161pub const ZERO: TensorRank2<3, 1, 1> = TensorRank2([
162    tensor_rank_1_zero(),
163    tensor_rank_1_zero(),
164    tensor_rank_1_zero(),
165]);
166
167pub const ZERO_10: TensorRank2<3, 1, 0> = TensorRank2([
168    tensor_rank_1_zero(),
169    tensor_rank_1_zero(),
170    tensor_rank_1_zero(),
171]);
172
173impl<const D: usize, const I: usize, const J: usize> From<(TensorRank1<D, I>, TensorRank1<D, J>)>
174    for TensorRank2<D, I, J>
175{
176    fn from((vector_a, vector_b): (TensorRank1<D, I>, TensorRank1<D, J>)) -> Self {
177        vector_a
178            .into_iter()
179            .map(|vector_a_i| {
180                vector_b
181                    .iter()
182                    .map(|vector_b_j| vector_a_i * vector_b_j)
183                    .collect()
184            })
185            .collect()
186    }
187}
188
189impl<const D: usize, const I: usize, const J: usize> From<(TensorRank1<D, I>, &TensorRank1<D, J>)>
190    for TensorRank2<D, I, J>
191{
192    fn from((vector_a, vector_b): (TensorRank1<D, I>, &TensorRank1<D, J>)) -> Self {
193        vector_a
194            .into_iter()
195            .map(|vector_a_i| {
196                vector_b
197                    .iter()
198                    .map(|vector_b_j| vector_a_i * vector_b_j)
199                    .collect()
200            })
201            .collect()
202    }
203}
204
205impl<const D: usize, const I: usize, const J: usize> From<(&TensorRank1<D, I>, TensorRank1<D, J>)>
206    for TensorRank2<D, I, J>
207{
208    fn from((vector_a, vector_b): (&TensorRank1<D, I>, TensorRank1<D, J>)) -> Self {
209        vector_a
210            .iter()
211            .map(|vector_a_i| {
212                vector_b
213                    .iter()
214                    .map(|vector_b_j| vector_a_i * vector_b_j)
215                    .collect()
216            })
217            .collect()
218    }
219}
220
221impl<const D: usize, const I: usize, const J: usize> From<(&TensorRank1<D, I>, &TensorRank1<D, J>)>
222    for TensorRank2<D, I, J>
223{
224    fn from((vector_a, vector_b): (&TensorRank1<D, I>, &TensorRank1<D, J>)) -> Self {
225        vector_a
226            .iter()
227            .map(|vector_a_i| {
228                vector_b
229                    .iter()
230                    .map(|vector_b_j| vector_a_i * vector_b_j)
231                    .collect()
232            })
233            .collect()
234    }
235}
236
237impl<const D: usize, const I: usize, const J: usize> From<Vec<Vec<TensorRank0>>>
238    for TensorRank2<D, I, J>
239{
240    fn from(vec: Vec<Vec<TensorRank0>>) -> Self {
241        assert_eq!(vec.len(), D);
242        vec.iter().for_each(|entry| assert_eq!(entry.len(), D));
243        vec.into_iter()
244            .map(|entry| entry.into_iter().collect())
245            .collect()
246    }
247}
248
249impl<const D: usize, const I: usize, const J: usize> From<TensorRank2<D, I, J>>
250    for Vec<Vec<TensorRank0>>
251{
252    fn from(tensor: TensorRank2<D, I, J>) -> Self {
253        tensor
254            .iter()
255            .map(|entry| entry.iter().copied().collect())
256            .collect()
257    }
258}
259
260impl<const D: usize, const I: usize, const J: usize> Display for TensorRank2<D, I, J> {
261    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
262        write!(f, "[")?;
263        self.iter()
264            .enumerate()
265            .try_for_each(|(i, row)| write!(f, "{row},\n\x1B[u\x1B[{}B", i + 1))?;
266        write!(f, "\x1B[u\x1B[1A\x1B[{}C]", 16 * D)
267    }
268}
269
270#[cfg(test)]
271impl<const D: usize, const I: usize, const J: usize> ErrorTensor for TensorRank2<D, I, J> {
272    fn error_fd(&self, comparator: &Self, epsilon: TensorRank0) -> Option<(bool, usize)> {
273        let error_count = self
274            .iter()
275            .zip(comparator.iter())
276            .map(|(self_i, comparator_i)| {
277                self_i
278                    .iter()
279                    .zip(comparator_i.iter())
280                    .filter(|&(&self_ij, &comparator_ij)| {
281                        (self_ij / comparator_ij - 1.0).abs() >= epsilon
282                            && (self_ij.abs() >= epsilon || comparator_ij.abs() >= epsilon)
283                    })
284                    .count()
285            })
286            .sum();
287        if error_count > 0 {
288            Some((true, error_count))
289        } else {
290            None
291        }
292    }
293}
294
295impl<const D: usize, const I: usize, const J: usize> TensorRank2<D, I, J> {
296    /// Returns a raw pointer to the slice’s buffer.
297    pub const fn as_ptr(&self) -> *const TensorRank1<D, J> {
298        self.0.as_ptr()
299    }
300    /// Returns the rank-2 tensor reshaped as a rank-1 tensor.
301    pub fn as_tensor_rank_1(&self) -> TensorRank1<9, 88> {
302        assert_eq!(D, 3);
303        let mut tensor_rank_1 = TensorRank1::<9, 88>::zero();
304        self.iter().enumerate().for_each(|(i, self_i)| {
305            self_i
306                .iter()
307                .enumerate()
308                .for_each(|(j, self_ij)| tensor_rank_1[3 * i + j] = *self_ij)
309        });
310        tensor_rank_1
311    }
312    /// Returns the determinant of the rank-2 tensor.
313    pub fn determinant(&self) -> TensorRank0 {
314        if D == 2 {
315            self[0][0] * self[1][1] - self[0][1] * self[1][0]
316        } else if D == 3 {
317            let c_00 = self[1][1] * self[2][2] - self[1][2] * self[2][1];
318            let c_10 = self[1][2] * self[2][0] - self[1][0] * self[2][2];
319            let c_20 = self[1][0] * self[2][1] - self[1][1] * self[2][0];
320            self[0][0] * c_00 + self[0][1] * c_10 + self[0][2] * c_20
321        } else if D == 4 {
322            let s0 = self[0][0] * self[1][1] - self[0][1] * self[1][0];
323            let s1 = self[0][0] * self[1][2] - self[0][2] * self[1][0];
324            let s2 = self[0][0] * self[1][3] - self[0][3] * self[1][0];
325            let s3 = self[0][1] * self[1][2] - self[0][2] * self[1][1];
326            let s4 = self[0][1] * self[1][3] - self[0][3] * self[1][1];
327            let s5 = self[0][2] * self[1][3] - self[0][3] * self[1][2];
328            let c5 = self[2][2] * self[3][3] - self[2][3] * self[3][2];
329            let c4 = self[2][1] * self[3][3] - self[2][3] * self[3][1];
330            let c3 = self[2][1] * self[3][2] - self[2][2] * self[3][1];
331            let c2 = self[2][0] * self[3][3] - self[2][3] * self[3][0];
332            let c1 = self[2][0] * self[3][2] - self[2][2] * self[3][0];
333            let c0 = self[2][0] * self[3][1] - self[2][1] * self[3][0];
334            s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0
335        } else {
336            let (_, u, p) = self.lu_decomposition();
337            let num_swaps = p.iter().enumerate().filter(|(i, p_i)| p_i != &i).count();
338            u.into_iter()
339                .enumerate()
340                .map(|(i, u_i)| u_i[i])
341                .product::<TensorRank0>()
342                * if num_swaps % 2 == 0 { 1.0 } else { -1.0 }
343        }
344    }
345    /// Returns the inverse of the rank-2 tensor.
346    pub fn inverse(&self) -> TensorRank2<D, J, I> {
347        if D == 2 {
348            let mut adjugate = TensorRank2::<D, J, I>::zero();
349            adjugate[0][0] = self[1][1];
350            adjugate[0][1] = -self[0][1];
351            adjugate[1][0] = -self[1][0];
352            adjugate[1][1] = self[0][0];
353            adjugate / self.determinant()
354        } else if D == 3 {
355            let mut adjugate = TensorRank2::<D, J, I>::zero();
356            let c_00 = self[1][1] * self[2][2] - self[1][2] * self[2][1];
357            let c_10 = self[1][2] * self[2][0] - self[1][0] * self[2][2];
358            let c_20 = self[1][0] * self[2][1] - self[1][1] * self[2][0];
359            adjugate[0][0] = c_00;
360            adjugate[0][1] = self[0][2] * self[2][1] - self[0][1] * self[2][2];
361            adjugate[0][2] = self[0][1] * self[1][2] - self[0][2] * self[1][1];
362            adjugate[1][0] = c_10;
363            adjugate[1][1] = self[0][0] * self[2][2] - self[0][2] * self[2][0];
364            adjugate[1][2] = self[0][2] * self[1][0] - self[0][0] * self[1][2];
365            adjugate[2][0] = c_20;
366            adjugate[2][1] = self[0][1] * self[2][0] - self[0][0] * self[2][1];
367            adjugate[2][2] = self[0][0] * self[1][1] - self[0][1] * self[1][0];
368            adjugate / (self[0][0] * c_00 + self[0][1] * c_10 + self[0][2] * c_20)
369        } else if D == 4 {
370            let mut adjugate = TensorRank2::<D, J, I>::zero();
371            let s0 = self[0][0] * self[1][1] - self[0][1] * self[1][0];
372            let s1 = self[0][0] * self[1][2] - self[0][2] * self[1][0];
373            let s2 = self[0][0] * self[1][3] - self[0][3] * self[1][0];
374            let s3 = self[0][1] * self[1][2] - self[0][2] * self[1][1];
375            let s4 = self[0][1] * self[1][3] - self[0][3] * self[1][1];
376            let s5 = self[0][2] * self[1][3] - self[0][3] * self[1][2];
377            let c5 = self[2][2] * self[3][3] - self[2][3] * self[3][2];
378            let c4 = self[2][1] * self[3][3] - self[2][3] * self[3][1];
379            let c3 = self[2][1] * self[3][2] - self[2][2] * self[3][1];
380            let c2 = self[2][0] * self[3][3] - self[2][3] * self[3][0];
381            let c1 = self[2][0] * self[3][2] - self[2][2] * self[3][0];
382            let c0 = self[2][0] * self[3][1] - self[2][1] * self[3][0];
383            adjugate[0][0] = self[1][1] * c5 - self[1][2] * c4 + self[1][3] * c3;
384            adjugate[0][1] = self[0][2] * c4 - self[0][1] * c5 - self[0][3] * c3;
385            adjugate[0][2] = self[3][1] * s5 - self[3][2] * s4 + self[3][3] * s3;
386            adjugate[0][3] = self[2][2] * s4 - self[2][1] * s5 - self[2][3] * s3;
387            adjugate[1][0] = self[1][2] * c2 - self[1][0] * c5 - self[1][3] * c1;
388            adjugate[1][1] = self[0][0] * c5 - self[0][2] * c2 + self[0][3] * c1;
389            adjugate[1][2] = self[3][2] * s2 - self[3][0] * s5 - self[3][3] * s1;
390            adjugate[1][3] = self[2][0] * s5 - self[2][2] * s2 + self[2][3] * s1;
391            adjugate[2][0] = self[1][0] * c4 - self[1][1] * c2 + self[1][3] * c0;
392            adjugate[2][1] = self[0][1] * c2 - self[0][0] * c4 - self[0][3] * c0;
393            adjugate[2][2] = self[3][0] * s4 - self[3][1] * s2 + self[3][3] * s0;
394            adjugate[2][3] = self[2][1] * s2 - self[2][0] * s4 - self[2][3] * s0;
395            adjugate[3][0] = self[1][1] * c1 - self[1][0] * c3 - self[1][2] * c0;
396            adjugate[3][1] = self[0][0] * c3 - self[0][1] * c1 + self[0][2] * c0;
397            adjugate[3][2] = self[3][1] * s1 - self[3][0] * s3 - self[3][2] * s0;
398            adjugate[3][3] = self[2][0] * s3 - self[2][1] * s1 + self[2][2] * s0;
399            adjugate / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0)
400        } else {
401            let (l_inverse, u_inverse, p) = self.lu_decomposition_inverse();
402            let mut q = [0; D];
403            p.into_iter().enumerate().for_each(|(i, p_i)| q[p_i] = i);
404            u_inverse
405                .into_iter()
406                .map(|u_inverse_i| {
407                    q.iter()
408                        .map(|&q_j| {
409                            u_inverse_i
410                                .iter()
411                                .zip(l_inverse.iter())
412                                .map(|(u_inverse_ik, l_inverse_k)| u_inverse_ik * l_inverse_k[q_j])
413                                .sum()
414                        })
415                        .collect()
416                })
417                .collect()
418        }
419    }
420    /// Returns the inverse and determinant of the rank-2 tensor.
421    pub fn inverse_and_determinant(&self) -> (TensorRank2<D, J, I>, TensorRank0) {
422        if D == 2 {
423            let mut adjugate = TensorRank2::<D, J, I>::zero();
424            adjugate[0][0] = self[1][1];
425            adjugate[0][1] = -self[0][1];
426            adjugate[1][0] = -self[1][0];
427            adjugate[1][1] = self[0][0];
428            let determinant = self.determinant();
429            (adjugate / determinant, determinant)
430        } else if D == 3 {
431            let mut adjugate = TensorRank2::<D, J, I>::zero();
432            let c_00 = self[1][1] * self[2][2] - self[1][2] * self[2][1];
433            let c_10 = self[1][2] * self[2][0] - self[1][0] * self[2][2];
434            let c_20 = self[1][0] * self[2][1] - self[1][1] * self[2][0];
435            let determinant = self[0][0] * c_00 + self[0][1] * c_10 + self[0][2] * c_20;
436            adjugate[0][0] = c_00;
437            adjugate[0][1] = self[0][2] * self[2][1] - self[0][1] * self[2][2];
438            adjugate[0][2] = self[0][1] * self[1][2] - self[0][2] * self[1][1];
439            adjugate[1][0] = c_10;
440            adjugate[1][1] = self[0][0] * self[2][2] - self[0][2] * self[2][0];
441            adjugate[1][2] = self[0][2] * self[1][0] - self[0][0] * self[1][2];
442            adjugate[2][0] = c_20;
443            adjugate[2][1] = self[0][1] * self[2][0] - self[0][0] * self[2][1];
444            adjugate[2][2] = self[0][0] * self[1][1] - self[0][1] * self[1][0];
445            (adjugate / determinant, determinant)
446        } else if D == 4 {
447            let mut adjugate = TensorRank2::<D, J, I>::zero();
448            let s0 = self[0][0] * self[1][1] - self[0][1] * self[1][0];
449            let s1 = self[0][0] * self[1][2] - self[0][2] * self[1][0];
450            let s2 = self[0][0] * self[1][3] - self[0][3] * self[1][0];
451            let s3 = self[0][1] * self[1][2] - self[0][2] * self[1][1];
452            let s4 = self[0][1] * self[1][3] - self[0][3] * self[1][1];
453            let s5 = self[0][2] * self[1][3] - self[0][3] * self[1][2];
454            let c5 = self[2][2] * self[3][3] - self[2][3] * self[3][2];
455            let c4 = self[2][1] * self[3][3] - self[2][3] * self[3][1];
456            let c3 = self[2][1] * self[3][2] - self[2][2] * self[3][1];
457            let c2 = self[2][0] * self[3][3] - self[2][3] * self[3][0];
458            let c1 = self[2][0] * self[3][2] - self[2][2] * self[3][0];
459            let c0 = self[2][0] * self[3][1] - self[2][1] * self[3][0];
460            let determinant = s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0;
461            adjugate[0][0] = self[1][1] * c5 - self[1][2] * c4 + self[1][3] * c3;
462            adjugate[0][1] = self[0][2] * c4 - self[0][1] * c5 - self[0][3] * c3;
463            adjugate[0][2] = self[3][1] * s5 - self[3][2] * s4 + self[3][3] * s3;
464            adjugate[0][3] = self[2][2] * s4 - self[2][1] * s5 - self[2][3] * s3;
465            adjugate[1][0] = self[1][2] * c2 - self[1][0] * c5 - self[1][3] * c1;
466            adjugate[1][1] = self[0][0] * c5 - self[0][2] * c2 + self[0][3] * c1;
467            adjugate[1][2] = self[3][2] * s2 - self[3][0] * s5 - self[3][3] * s1;
468            adjugate[1][3] = self[2][0] * s5 - self[2][2] * s2 + self[2][3] * s1;
469            adjugate[2][0] = self[1][0] * c4 - self[1][1] * c2 + self[1][3] * c0;
470            adjugate[2][1] = self[0][1] * c2 - self[0][0] * c4 - self[0][3] * c0;
471            adjugate[2][2] = self[3][0] * s4 - self[3][1] * s2 + self[3][3] * s0;
472            adjugate[2][3] = self[2][1] * s2 - self[2][0] * s4 - self[2][3] * s0;
473            adjugate[3][0] = self[1][1] * c1 - self[1][0] * c3 - self[1][2] * c0;
474            adjugate[3][1] = self[0][0] * c3 - self[0][1] * c1 + self[0][2] * c0;
475            adjugate[3][2] = self[3][1] * s1 - self[3][0] * s3 - self[3][2] * s0;
476            adjugate[3][3] = self[2][0] * s3 - self[2][1] * s1 + self[2][2] * s0;
477            (adjugate / determinant, determinant)
478        } else {
479            panic!()
480        }
481    }
482    /// Returns the inverse transpose of the rank-2 tensor.
483    pub fn inverse_transpose(&self) -> Self {
484        if D == 2 {
485            let mut adjugate_transpose = TensorRank2::<D, I, J>::zero();
486            adjugate_transpose[0][0] = self[1][1];
487            adjugate_transpose[0][1] = -self[1][0];
488            adjugate_transpose[1][0] = -self[0][1];
489            adjugate_transpose[1][1] = self[0][0];
490            adjugate_transpose / self.determinant()
491        } else if D == 3 {
492            let mut adjugate_transpose = TensorRank2::<D, I, J>::zero();
493            let c_00 = self[1][1] * self[2][2] - self[1][2] * self[2][1];
494            let c_10 = self[1][2] * self[2][0] - self[1][0] * self[2][2];
495            let c_20 = self[1][0] * self[2][1] - self[1][1] * self[2][0];
496            adjugate_transpose[0][0] = c_00;
497            adjugate_transpose[1][0] = self[0][2] * self[2][1] - self[0][1] * self[2][2];
498            adjugate_transpose[2][0] = self[0][1] * self[1][2] - self[0][2] * self[1][1];
499            adjugate_transpose[0][1] = c_10;
500            adjugate_transpose[1][1] = self[0][0] * self[2][2] - self[0][2] * self[2][0];
501            adjugate_transpose[2][1] = self[0][2] * self[1][0] - self[0][0] * self[1][2];
502            adjugate_transpose[0][2] = c_20;
503            adjugate_transpose[1][2] = self[0][1] * self[2][0] - self[0][0] * self[2][1];
504            adjugate_transpose[2][2] = self[0][0] * self[1][1] - self[0][1] * self[1][0];
505            adjugate_transpose / (self[0][0] * c_00 + self[0][1] * c_10 + self[0][2] * c_20)
506        } else if D == 4 {
507            let mut adjugate_transpose = TensorRank2::<D, I, J>::zero();
508            let s0 = self[0][0] * self[1][1] - self[0][1] * self[1][0];
509            let s1 = self[0][0] * self[1][2] - self[0][2] * self[1][0];
510            let s2 = self[0][0] * self[1][3] - self[0][3] * self[1][0];
511            let s3 = self[0][1] * self[1][2] - self[0][2] * self[1][1];
512            let s4 = self[0][1] * self[1][3] - self[0][3] * self[1][1];
513            let s5 = self[0][2] * self[1][3] - self[0][3] * self[1][2];
514            let c5 = self[2][2] * self[3][3] - self[2][3] * self[3][2];
515            let c4 = self[2][1] * self[3][3] - self[2][3] * self[3][1];
516            let c3 = self[2][1] * self[3][2] - self[2][2] * self[3][1];
517            let c2 = self[2][0] * self[3][3] - self[2][3] * self[3][0];
518            let c1 = self[2][0] * self[3][2] - self[2][2] * self[3][0];
519            let c0 = self[2][0] * self[3][1] - self[2][1] * self[3][0];
520            adjugate_transpose[0][0] = self[1][1] * c5 - self[1][2] * c4 + self[1][3] * c3;
521            adjugate_transpose[1][0] = self[0][2] * c4 - self[0][1] * c5 - self[0][3] * c3;
522            adjugate_transpose[2][0] = self[3][1] * s5 - self[3][2] * s4 + self[3][3] * s3;
523            adjugate_transpose[3][0] = self[2][2] * s4 - self[2][1] * s5 - self[2][3] * s3;
524            adjugate_transpose[0][1] = self[1][2] * c2 - self[1][0] * c5 - self[1][3] * c1;
525            adjugate_transpose[1][1] = self[0][0] * c5 - self[0][2] * c2 + self[0][3] * c1;
526            adjugate_transpose[2][1] = self[3][2] * s2 - self[3][0] * s5 - self[3][3] * s1;
527            adjugate_transpose[3][1] = self[2][0] * s5 - self[2][2] * s2 + self[2][3] * s1;
528            adjugate_transpose[0][2] = self[1][0] * c4 - self[1][1] * c2 + self[1][3] * c0;
529            adjugate_transpose[1][2] = self[0][1] * c2 - self[0][0] * c4 - self[0][3] * c0;
530            adjugate_transpose[2][2] = self[3][0] * s4 - self[3][1] * s2 + self[3][3] * s0;
531            adjugate_transpose[3][2] = self[2][1] * s2 - self[2][0] * s4 - self[2][3] * s0;
532            adjugate_transpose[0][3] = self[1][1] * c1 - self[1][0] * c3 - self[1][2] * c0;
533            adjugate_transpose[1][3] = self[0][0] * c3 - self[0][1] * c1 + self[0][2] * c0;
534            adjugate_transpose[2][3] = self[3][1] * s1 - self[3][0] * s3 - self[3][2] * s0;
535            adjugate_transpose[3][3] = self[2][0] * s3 - self[2][1] * s1 + self[2][2] * s0;
536            adjugate_transpose / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0)
537        } else {
538            self.inverse().transpose()
539        }
540    }
541    /// Returns the inverse transpose and determinant of the rank-2 tensor.
542    pub fn inverse_transpose_and_determinant(&self) -> (Self, TensorRank0) {
543        if D == 2 {
544            let mut adjugate_transpose = TensorRank2::<D, I, J>::zero();
545            adjugate_transpose[0][0] = self[1][1];
546            adjugate_transpose[0][1] = -self[1][0];
547            adjugate_transpose[1][0] = -self[0][1];
548            adjugate_transpose[1][1] = self[0][0];
549            let determinant = self.determinant();
550            (adjugate_transpose / determinant, determinant)
551        } else if D == 3 {
552            let mut adjugate_transpose = TensorRank2::<D, I, J>::zero();
553            let c_00 = self[1][1] * self[2][2] - self[1][2] * self[2][1];
554            let c_10 = self[1][2] * self[2][0] - self[1][0] * self[2][2];
555            let c_20 = self[1][0] * self[2][1] - self[1][1] * self[2][0];
556            let determinant = self[0][0] * c_00 + self[0][1] * c_10 + self[0][2] * c_20;
557            adjugate_transpose[0][0] = c_00;
558            adjugate_transpose[1][0] = self[0][2] * self[2][1] - self[0][1] * self[2][2];
559            adjugate_transpose[2][0] = self[0][1] * self[1][2] - self[0][2] * self[1][1];
560            adjugate_transpose[0][1] = c_10;
561            adjugate_transpose[1][1] = self[0][0] * self[2][2] - self[0][2] * self[2][0];
562            adjugate_transpose[2][1] = self[0][2] * self[1][0] - self[0][0] * self[1][2];
563            adjugate_transpose[0][2] = c_20;
564            adjugate_transpose[1][2] = self[0][1] * self[2][0] - self[0][0] * self[2][1];
565            adjugate_transpose[2][2] = self[0][0] * self[1][1] - self[0][1] * self[1][0];
566            (adjugate_transpose / determinant, determinant)
567        } else if D == 4 {
568            let mut adjugate_transpose = TensorRank2::<D, I, J>::zero();
569            let s0 = self[0][0] * self[1][1] - self[0][1] * self[1][0];
570            let s1 = self[0][0] * self[1][2] - self[0][2] * self[1][0];
571            let s2 = self[0][0] * self[1][3] - self[0][3] * self[1][0];
572            let s3 = self[0][1] * self[1][2] - self[0][2] * self[1][1];
573            let s4 = self[0][1] * self[1][3] - self[0][3] * self[1][1];
574            let s5 = self[0][2] * self[1][3] - self[0][3] * self[1][2];
575            let c5 = self[2][2] * self[3][3] - self[2][3] * self[3][2];
576            let c4 = self[2][1] * self[3][3] - self[2][3] * self[3][1];
577            let c3 = self[2][1] * self[3][2] - self[2][2] * self[3][1];
578            let c2 = self[2][0] * self[3][3] - self[2][3] * self[3][0];
579            let c1 = self[2][0] * self[3][2] - self[2][2] * self[3][0];
580            let c0 = self[2][0] * self[3][1] - self[2][1] * self[3][0];
581            let determinant = s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0;
582            adjugate_transpose[0][0] = self[1][1] * c5 - self[1][2] * c4 + self[1][3] * c3;
583            adjugate_transpose[1][0] = self[0][2] * c4 - self[0][1] * c5 - self[0][3] * c3;
584            adjugate_transpose[2][0] = self[3][1] * s5 - self[3][2] * s4 + self[3][3] * s3;
585            adjugate_transpose[3][0] = self[2][2] * s4 - self[2][1] * s5 - self[2][3] * s3;
586            adjugate_transpose[0][1] = self[1][2] * c2 - self[1][0] * c5 - self[1][3] * c1;
587            adjugate_transpose[1][1] = self[0][0] * c5 - self[0][2] * c2 + self[0][3] * c1;
588            adjugate_transpose[2][1] = self[3][2] * s2 - self[3][0] * s5 - self[3][3] * s1;
589            adjugate_transpose[3][1] = self[2][0] * s5 - self[2][2] * s2 + self[2][3] * s1;
590            adjugate_transpose[0][2] = self[1][0] * c4 - self[1][1] * c2 + self[1][3] * c0;
591            adjugate_transpose[1][2] = self[0][1] * c2 - self[0][0] * c4 - self[0][3] * c0;
592            adjugate_transpose[2][2] = self[3][0] * s4 - self[3][1] * s2 + self[3][3] * s0;
593            adjugate_transpose[3][2] = self[2][1] * s2 - self[2][0] * s4 - self[2][3] * s0;
594            adjugate_transpose[0][3] = self[1][1] * c1 - self[1][0] * c3 - self[1][2] * c0;
595            adjugate_transpose[1][3] = self[0][0] * c3 - self[0][1] * c1 + self[0][2] * c0;
596            adjugate_transpose[2][3] = self[3][1] * s1 - self[3][0] * s3 - self[3][2] * s0;
597            adjugate_transpose[3][3] = self[2][0] * s3 - self[2][1] * s1 + self[2][2] * s0;
598            (adjugate_transpose / determinant, determinant)
599        } else {
600            panic!()
601        }
602    }
603    /// Returns the LU decomposition of the rank-2 tensor.
604    pub fn lu_decomposition(&self) -> (TensorRank2<D, I, 88>, TensorRank2<D, 88, J>, Vec<usize>) {
605        let n = D;
606        let mut p: Vec<usize> = (0..n).collect();
607        let mut factor;
608        let mut lu = self.clone();
609        let mut max_row;
610        let mut max_val;
611        let mut pivot;
612        for i in 0..n {
613            max_row = i;
614            max_val = lu[max_row][i].abs();
615            for k in i + 1..n {
616                if lu[k][i].abs() > max_val {
617                    max_row = k;
618                    max_val = lu[max_row][i].abs();
619                }
620            }
621            if max_row != i {
622                lu.0.swap(i, max_row);
623                p.swap(i, max_row);
624            }
625            pivot = lu[i][i];
626            if pivot.abs() < ABS_TOL {
627                panic!("LU decomposition failed (zero pivot).")
628            }
629            for j in i + 1..n {
630                if lu[j][i] != 0.0 {
631                    lu[j][i] /= pivot;
632                    factor = lu[j][i];
633                    for k in i + 1..n {
634                        lu[j][k] -= factor * lu[i][k];
635                    }
636                }
637            }
638        }
639        let mut l = TensorRank2::identity();
640        for i in 0..D {
641            for j in 0..i {
642                l[i][j] = lu[i][j]
643            }
644        }
645        let mut u = TensorRank2::zero();
646        for i in 0..D {
647            for j in i..D {
648                u[i][j] = lu[i][j]
649            }
650        }
651        (l, u, p)
652    }
653    /// Returns the inverse of the LU decomposition of the rank-2 tensor.
654    pub fn lu_decomposition_inverse(
655        &self,
656    ) -> (TensorRank2<D, I, 88>, TensorRank2<D, 88, J>, Vec<usize>) {
657        let (mut tensor_l, mut tensor_u, p) = self.lu_decomposition();
658        let mut sum;
659        for i in 0..D {
660            tensor_l[i][i] = 1.0 / tensor_l[i][i];
661            for j in 0..i {
662                sum = 0.0;
663                for k in j..i {
664                    sum += tensor_l[i][k] * tensor_l[k][j];
665                }
666                tensor_l[i][j] = -sum * tensor_l[i][i];
667            }
668        }
669        for i in 0..D {
670            tensor_u[i][i] = 1.0 / tensor_u[i][i];
671            for j in 0..i {
672                sum = 0.0;
673                for k in j..i {
674                    sum += tensor_u[j][k] * tensor_u[k][i];
675                }
676                tensor_u[j][i] = -sum * tensor_u[i][i];
677            }
678        }
679        (tensor_l, tensor_u, p)
680    }
681}
682
683impl<const I: usize> TensorRank2<3, I, I> {
684    /// Returns the matrix logarithm of the 3x3 symmetric tensor.
685    pub fn logm(&self) -> Result<Self, TensorError> {
686        if self.is_diagonal() {
687            let mut logm = TensorRank2::zero();
688            logm.iter_mut()
689                .enumerate()
690                .zip(self.iter())
691                .for_each(|((i, logm_i), self_i)| logm_i[i] = self_i[i].ln());
692            Ok(logm)
693        } else {
694            let tensor = self - &TensorRank2::identity();
695            let norm = tensor.norm();
696            if norm < 1e-2 {
697                let num_terms = if norm < 1e-4 {
698                    2
699                } else if norm < 1e-3 {
700                    3
701                } else {
702                    5
703                };
704                let mut logm = tensor.clone();
705                let mut power = tensor.clone();
706                (2..=num_terms).for_each(|k| {
707                    power *= &tensor;
708                    logm += &power / (if k % 2 == 0 { -1.0 } else { 1.0 } / k as f64);
709                });
710                Ok(logm)
711            } else if self.is_symmetric() {
712                let mut eigenvalues = solve_cubic_symmetric(self.invariants())?;
713                if eigenvalues.iter().any(|eigenvalue| eigenvalue <= &0.0) {
714                    panic!("Symmetric matrix has a non-positive eigenvalue")
715                }
716                let eigenvectors = find_orthonormal_eigenvectors(&eigenvalues, self);
717                eigenvalues
718                    .iter_mut()
719                    .for_each(|eigenvalue| *eigenvalue = eigenvalue.ln());
720                Ok(reconstruct_symmetric(eigenvalues, eigenvectors))
721            } else {
722                panic!("Matrix logarithm only implemented for symmetric cases")
723            }
724        }
725    }
726    /// Returns the derivative of the matrix logarithm of the 3x3 symmetric tensor.
727    pub fn dlogm(&self) -> Result<TensorRank4<3, I, I, I, I>, TensorError> {
728        if self.is_diagonal() {
729            let mut dlogm = TensorRank4::zero();
730            dlogm.iter_mut().enumerate().for_each(|(i, dlogm_i)| {
731                dlogm_i.iter_mut().enumerate().for_each(|(j, dlogm_ij)| {
732                    dlogm_ij.iter_mut().enumerate().for_each(|(k, dlogm_ijk)| {
733                        dlogm_ijk
734                            .iter_mut()
735                            .enumerate()
736                            .filter(|(l, _)| i == k && &j == l)
737                            .for_each(|(_, dlogm_ijkl)| {
738                                *dlogm_ijkl = if assert_eq_within_tols(&self[i][i], &self[j][j])
739                                    .is_ok()
740                                {
741                                    1.0 / self[j][j]
742                                } else {
743                                    (self[i][i].ln() - self[j][j].ln()) / (self[i][i] - self[j][j])
744                                }
745                            })
746                    })
747                })
748            });
749            Ok(dlogm)
750        } else if self.is_symmetric() {
751            let eigenvalues = solve_cubic_symmetric(self.invariants())?;
752            if eigenvalues.iter().any(|eigenvalue| eigenvalue <= &0.0) {
753                panic!("Symmetric matrix has a non-positive eigenvalue")
754            }
755            let divided_difference: Self = eigenvalues
756                .iter()
757                .map(|eigenvalue_i| {
758                    eigenvalues
759                        .iter()
760                        .map(|eigenvalue_j| {
761                            if assert_eq_within_tols(eigenvalue_i, eigenvalue_j).is_ok() {
762                                1.0 / eigenvalue_j
763                            } else {
764                                (eigenvalue_i.ln() - eigenvalue_j.ln())
765                                    / (eigenvalue_i - eigenvalue_j)
766                            }
767                        })
768                        .collect()
769                })
770                .collect();
771            let eigenvectors = find_orthonormal_eigenvectors(&eigenvalues, self).transpose();
772            Ok(eigenvectors.iter().map(|eigenvector_i|
773                eigenvectors.iter().map(|eigenvector_j|
774                    eigenvectors.iter().map(|eigenvector_k|
775                        eigenvectors.iter().map(|eigenvector_l|
776                            eigenvector_i.iter().zip(eigenvector_k.iter().zip(divided_difference.iter())).map(|(eigenvector_ip, (eigenvector_kp, divided_difference_p))|
777                                eigenvector_j.iter().zip(eigenvector_l.iter().zip(divided_difference_p.iter())).map(|(eigenvector_jq, (eigenvector_lq, divided_difference_pq))|
778                                    eigenvector_ip * eigenvector_kp * divided_difference_pq * eigenvector_jq * eigenvector_lq
779                                ).sum::<TensorRank0>()
780                            ).sum()
781                        ).collect()
782                    ).collect()
783                ).collect()
784            ).collect())
785        } else {
786            panic!("Matrix logarithm only implemented for symmetric cases")
787        }
788    }
789    /// Returns the invariants of the 3x3 symmetric tensor.
790    pub fn invariants(&self) -> TensorRank0List<3> {
791        let trace = self.trace();
792        TensorRank0List::new([
793            trace,
794            0.5 * (trace.powi(2) - self.squared_trace()),
795            self.determinant(),
796        ])
797    }
798}
799
800fn solve_cubic_symmetric(
801    coefficients: TensorRank0List<3>,
802) -> Result<TensorRank0List<3>, TensorError> {
803    let c2 = coefficients[0];
804    let c1 = coefficients[1];
805    let c0 = coefficients[2];
806    let p = c1 - c2 * c2 / 3.0;
807    let q = -(2.0 * c2.powi(3) - 9.0 * c2 * c1 + 27.0 * c0) / 27.0;
808    if p.abs() < ABS_TOL {
809        let t = (-q).cbrt();
810        let lambda = t + c2 / 3.0;
811        return Ok(TensorRank0List::new([lambda; _]));
812    }
813    let discriminant = -4.0 * p * p * p - 27.0 * q * q;
814    if discriminant >= ABS_TOL {
815        let sqrt_term = (-p / 3.0).sqrt();
816        let cos_arg = 3.0 * q / (2.0 * p * (-p / 3.0).sqrt());
817        let cos_arg = cos_arg.clamp(-1.0, 1.0);
818        let theta = cos_arg.acos();
819        let mut lambdas = [
820            2.0 * sqrt_term * (theta / 3.0).cos() + c2 / 3.0,
821            2.0 * sqrt_term * ((theta + TAU) / 3.0).cos() + c2 / 3.0,
822            2.0 * sqrt_term * ((theta + 2.0 * TAU) / 3.0).cos() + c2 / 3.0,
823        ];
824        lambdas.sort_by(|a, b| b.partial_cmp(a).unwrap());
825        Ok(TensorRank0List::new(lambdas))
826    } else {
827        Err(TensorError::SymmetricMatrixComplexEigenvalues)
828    }
829}
830
831fn find_orthonormal_eigenvectors<const I: usize>(
832    eigenvalues: &TensorRank0List<3>,
833    tensor: &TensorRank2<3, I, I>,
834) -> TensorRank2<3, I, I> {
835    let mut eigenvectors = eigenvalues
836        .iter()
837        .map(|&eigenvalue| eigenvector_symmetric(eigenvalue, tensor))
838        .collect::<TensorRank2<3, I, I>>();
839    eigenvectors[0].normalize();
840    let proj1 = &eigenvectors[1] * &eigenvectors[0];
841    for i in 0..3 {
842        eigenvectors[1][i] -= proj1 * eigenvectors[0][i];
843    }
844    eigenvectors[1].normalize();
845    eigenvectors[2] = eigenvectors[0].cross(&eigenvectors[1]);
846    eigenvectors
847}
848
849fn eigenvector_symmetric<const I: usize>(
850    eigenvalue: TensorRank0,
851    tensor: &TensorRank2<3, I, I>,
852) -> TensorRank1<3, I> {
853    let m = tensor - TensorRank2::identity() * eigenvalue;
854    let mut pivot_row = 0;
855    m.iter().enumerate().for_each(|(i, m_i)| {
856        if m_i[i].abs() < m[pivot_row][pivot_row].abs() {
857            pivot_row = i;
858        }
859    });
860    if pivot_row == 0 {
861        m[1].cross(&m[2])
862    } else if pivot_row == 1 {
863        m[0].cross(&m[2])
864    } else {
865        m[0].cross(&m[1])
866    }
867    .normalized()
868}
869
870fn reconstruct_symmetric<const I: usize>(
871    eigenvalues: TensorRank0List<3>,
872    eigenvectors: TensorRank2<3, I, I>,
873) -> TensorRank2<3, I, I> {
874    let mut tensor = TensorRank2::zero();
875    eigenvalues
876        .iter()
877        .zip(eigenvectors.iter())
878        .for_each(|(eigenvalue, eigenvector)| {
879            tensor
880                .iter_mut()
881                .zip(eigenvector.iter())
882                .for_each(|(tensor_i, eigenvector_i)| {
883                    tensor_i.iter_mut().zip(eigenvector.iter()).for_each(
884                        |(tensor_ij, eigenvector_j)| {
885                            *tensor_ij += eigenvalue * eigenvector_i * eigenvector_j
886                        },
887                    )
888                })
889        });
890    tensor
891}
892
893impl<const D: usize, const I: usize, const J: usize> Hessian for TensorRank2<D, I, J> {
894    fn fill_into(self, square_matrix: &mut SquareMatrix) {
895        self.into_iter().enumerate().for_each(|(i, self_i)| {
896            self_i
897                .into_iter()
898                .enumerate()
899                .for_each(|(j, self_ij)| square_matrix[i][j] = self_ij)
900        })
901    }
902}
903
904impl<const D: usize, const I: usize, const J: usize> Rank2 for TensorRank2<D, I, J> {
905    type Transpose = TensorRank2<D, J, I>;
906    fn deviatoric(&self) -> Self {
907        Self::identity() * (self.trace() / -(D as TensorRank0)) + self
908    }
909    fn deviatoric_and_trace(&self) -> (Self, TensorRank0) {
910        let trace = self.trace();
911        (
912            Self::identity() * (trace / -(D as TensorRank0)) + self,
913            trace,
914        )
915    }
916    fn is_diagonal(&self) -> bool {
917        self.iter()
918            .enumerate()
919            .map(|(i, self_i)| {
920                self_i
921                    .iter()
922                    .enumerate()
923                    .map(|(j, self_ij)| (self_ij.abs() < ABS_TOL) as u8 * (i != j) as u8)
924                    .sum::<u8>()
925            })
926            .sum::<u8>()
927            == (D.pow(2) - D) as u8
928    }
929    fn is_identity(&self) -> bool {
930        self.iter().enumerate().all(|(i, self_i)| {
931            self_i
932                .iter()
933                .enumerate()
934                .all(|(j, self_ij)| self_ij == &((i == j) as u8 as TensorRank0))
935        })
936    }
937    fn is_symmetric(&self) -> bool {
938        self.iter().enumerate().all(|(i, self_i)| {
939            self_i
940                .iter()
941                .zip(self.iter())
942                .all(|(self_ij, self_j)| self_ij == &self_j[i])
943        })
944    }
945    fn squared_trace(&self) -> TensorRank0 {
946        self.iter()
947            .enumerate()
948            .map(|(i, self_i)| {
949                self_i
950                    .iter()
951                    .zip(self.iter())
952                    .map(|(self_ij, self_j)| self_ij * self_j[i])
953                    .sum::<TensorRank0>()
954            })
955            .sum()
956    }
957    fn trace(&self) -> TensorRank0 {
958        self.iter().enumerate().map(|(i, self_i)| self_i[i]).sum()
959    }
960    fn transpose(&self) -> Self::Transpose {
961        (0..D)
962            .map(|i| (0..D).map(|j| self[j][i]).collect())
963            // .map(|i| self.iter().map(|self_j| self_j[i]).collect())
964            .collect()
965    }
966}
967
968impl<const D: usize, const I: usize, const J: usize> Tensor for TensorRank2<D, I, J> {
969    type Item = TensorRank1<D, J>;
970    fn iter(&self) -> impl Iterator<Item = &Self::Item> {
971        self.0.iter()
972    }
973    fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item> {
974        self.0.iter_mut()
975    }
976    fn len(&self) -> usize {
977        D
978    }
979    fn size(&self) -> usize {
980        D * D
981    }
982}
983
984impl<const D: usize, const I: usize, const J: usize> IntoIterator for TensorRank2<D, I, J> {
985    type Item = TensorRank1<D, J>;
986    type IntoIter = IntoIter<Self::Item, D>;
987    fn into_iter(self) -> Self::IntoIter {
988        self.0.into_iter()
989    }
990}
991
992impl<const D: usize, const I: usize, const J: usize> TensorArray for TensorRank2<D, I, J> {
993    type Array = [[TensorRank0; D]; D];
994    type Item = TensorRank1<D, J>;
995    fn as_array(&self) -> Self::Array {
996        let mut array = [[0.0; D]; D];
997        array
998            .iter_mut()
999            .zip(self.iter())
1000            .for_each(|(entry, tensor_rank_1)| *entry = tensor_rank_1.as_array());
1001        array
1002    }
1003    fn identity() -> Self {
1004        (0..D)
1005            .map(|i| (0..D).map(|j| ((i == j) as u8) as TensorRank0).collect())
1006            .collect()
1007    }
1008    fn new(array: Self::Array) -> Self {
1009        array.into_iter().map(Self::Item::new).collect()
1010    }
1011    fn zero() -> Self {
1012        Self(from_fn(|_| Self::Item::zero()))
1013    }
1014}
1015
1016impl<const D: usize, const I: usize, const J: usize> Solution for TensorRank2<D, I, J> {
1017    fn decrement_from(&mut self, other: &Vector) {
1018        self.iter_mut()
1019            .flat_map(|x| x.iter_mut())
1020            .zip(other.iter())
1021            .for_each(|(self_i, vector_i)| *self_i -= vector_i)
1022    }
1023    fn decrement_from_chained(&mut self, other: &mut Vector, vector: Vector) {
1024        self.iter_mut()
1025            .flat_map(|x| x.iter_mut())
1026            .chain(other.iter_mut())
1027            .zip(vector)
1028            .for_each(|(entry_i, vector_i)| *entry_i -= vector_i)
1029    }
1030}
1031
1032impl<const D: usize, const I: usize, const J: usize> Jacobian for TensorRank2<D, I, J> {
1033    fn fill_into(self, vector: &mut Vector) {
1034        self.into_iter()
1035            .flatten()
1036            .zip(vector.iter_mut())
1037            .for_each(|(self_i, vector_i)| *vector_i = self_i)
1038    }
1039    fn fill_into_chained(self, other: Vector, vector: &mut Vector) {
1040        self.into_iter()
1041            .flatten()
1042            .chain(other)
1043            .zip(vector.iter_mut())
1044            .for_each(|(self_i, vector_i)| *vector_i = self_i)
1045    }
1046}
1047
1048impl<const D: usize, const I: usize, const J: usize> Sub<Vector> for TensorRank2<D, I, J> {
1049    type Output = Self;
1050    fn sub(mut self, vector: Vector) -> Self::Output {
1051        self.iter_mut().enumerate().for_each(|(i, self_i)| {
1052            self_i
1053                .iter_mut()
1054                .enumerate()
1055                .for_each(|(j, self_ij)| *self_ij -= vector[D * i + j])
1056        });
1057        self
1058    }
1059}
1060
1061impl<const D: usize, const I: usize, const J: usize> Sub<&Vector> for TensorRank2<D, I, J> {
1062    type Output = Self;
1063    fn sub(mut self, vector: &Vector) -> Self::Output {
1064        self.iter_mut().enumerate().for_each(|(i, self_i)| {
1065            self_i
1066                .iter_mut()
1067                .enumerate()
1068                .for_each(|(j, self_ij)| *self_ij -= vector[D * i + j])
1069        });
1070        self
1071    }
1072}
1073
1074impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
1075    From<TensorRank4<D, I, J, K, L>> for TensorRank2<9, 88, 99>
1076{
1077    fn from(tensor_rank_4: TensorRank4<D, I, J, K, L>) -> Self {
1078        assert_eq!(D, 3);
1079        tensor_rank_4
1080            .into_iter()
1081            .flatten()
1082            .map(|entry_ij| entry_ij.into_iter().flatten().collect())
1083            .collect()
1084    }
1085}
1086
1087impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
1088    From<&TensorRank4<D, I, J, K, L>> for TensorRank2<9, 88, 99>
1089{
1090    fn from(tensor_rank_4: &TensorRank4<D, I, J, K, L>) -> Self {
1091        assert_eq!(D, 3);
1092        tensor_rank_4
1093            .clone()
1094            .into_iter()
1095            .flatten()
1096            .map(|entry_ij| entry_ij.into_iter().flatten().collect())
1097            .collect()
1098    }
1099}
1100
1101impl From<TensorRank2<3, 0, 0>> for TensorRank2<3, 2, 2> {
1102    fn from(tensor_rank_2: TensorRank2<3, 0, 0>) -> Self {
1103        unsafe { transmute::<TensorRank2<3, 0, 0>, TensorRank2<3, 2, 2>>(tensor_rank_2) }
1104    }
1105}
1106
1107impl<const I: usize> From<TensorRank2<3, I, 0>> for TensorRank2<3, I, 2> {
1108    fn from(tensor_rank_2: TensorRank2<3, I, 0>) -> Self {
1109        unsafe { transmute::<TensorRank2<3, I, 0>, TensorRank2<3, I, 2>>(tensor_rank_2) }
1110    }
1111}
1112
1113impl<const I: usize> From<TensorRank2<3, I, 1>> for TensorRank2<3, I, 0> {
1114    fn from(tensor_rank_2: TensorRank2<3, I, 1>) -> Self {
1115        unsafe { transmute::<TensorRank2<3, I, 1>, TensorRank2<3, I, 0>>(tensor_rank_2) }
1116    }
1117}
1118
1119impl<const I: usize> From<TensorRank2<3, I, 2>> for TensorRank2<3, I, 0> {
1120    fn from(tensor_rank_2: TensorRank2<3, I, 2>) -> Self {
1121        unsafe { transmute::<TensorRank2<3, I, 2>, TensorRank2<3, I, 0>>(tensor_rank_2) }
1122    }
1123}
1124
1125impl<const J: usize> From<TensorRank2<3, 0, J>> for TensorRank2<3, 1, J> {
1126    fn from(tensor_rank_2: TensorRank2<3, 0, J>) -> Self {
1127        unsafe { transmute::<TensorRank2<3, 0, J>, TensorRank2<3, 1, J>>(tensor_rank_2) }
1128    }
1129}
1130
1131impl<const J: usize> From<TensorRank2<3, 1, J>> for TensorRank2<3, 0, J> {
1132    fn from(tensor_rank_2: TensorRank2<3, 1, J>) -> Self {
1133        unsafe { transmute::<TensorRank2<3, 1, J>, TensorRank2<3, 0, J>>(tensor_rank_2) }
1134    }
1135}
1136
1137impl<const J: usize> From<TensorRank2<3, 1, J>> for TensorRank2<3, 2, J> {
1138    fn from(tensor_rank_2: TensorRank2<3, 1, J>) -> Self {
1139        unsafe { transmute::<TensorRank2<3, 1, J>, TensorRank2<3, 2, J>>(tensor_rank_2) }
1140    }
1141}
1142
1143impl<const J: usize> From<TensorRank2<3, 2, J>> for TensorRank2<3, 1, J> {
1144    fn from(tensor_rank_2: TensorRank2<3, 2, J>) -> Self {
1145        unsafe { transmute::<TensorRank2<3, 2, J>, TensorRank2<3, 1, J>>(tensor_rank_2) }
1146    }
1147}
1148
1149impl<const J: usize> From<&TensorRank2<3, 2, J>> for &TensorRank2<3, 1, J> {
1150    fn from(tensor_rank_2: &TensorRank2<3, 2, J>) -> Self {
1151        unsafe { transmute::<&TensorRank2<3, 2, J>, &TensorRank2<3, 1, J>>(tensor_rank_2) }
1152    }
1153}
1154
1155impl From<TensorRank2<3, 0, 0>> for TensorRank2<3, 1, 1> {
1156    fn from(tensor_rank_2: TensorRank2<3, 0, 0>) -> Self {
1157        unsafe { transmute::<TensorRank2<3, 0, 0>, TensorRank2<3, 1, 1>>(tensor_rank_2) }
1158    }
1159}
1160
1161impl<const D: usize, const I: usize, const J: usize> From<Vector> for TensorRank2<D, I, J> {
1162    fn from(_vector: Vector) -> Self {
1163        unimplemented!()
1164    }
1165}
1166
1167impl<const D: usize, const I: usize, const J: usize> FromIterator<TensorRank1<D, J>>
1168    for TensorRank2<D, I, J>
1169{
1170    fn from_iter<Ii: IntoIterator<Item = TensorRank1<D, J>>>(into_iterator: Ii) -> Self {
1171        let mut tensor_rank_2 = Self::zero();
1172        tensor_rank_2
1173            .iter_mut()
1174            .zip(into_iterator)
1175            .for_each(|(tensor_rank_2_i, value_i)| *tensor_rank_2_i = value_i);
1176        tensor_rank_2
1177    }
1178}
1179
1180impl<const D: usize, const I: usize, const J: usize> Index<usize> for TensorRank2<D, I, J> {
1181    type Output = TensorRank1<D, J>;
1182    fn index(&self, index: usize) -> &Self::Output {
1183        &self.0[index]
1184    }
1185}
1186
1187impl<const D: usize, const I: usize, const J: usize> IndexMut<usize> for TensorRank2<D, I, J> {
1188    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
1189        &mut self.0[index]
1190    }
1191}
1192
1193impl<const D: usize, const I: usize, const J: usize> Sum for TensorRank2<D, I, J> {
1194    fn sum<Ii>(iter: Ii) -> Self
1195    where
1196        Ii: Iterator<Item = Self>,
1197    {
1198        iter.reduce(|mut acc, item| {
1199            acc += item;
1200            acc
1201        })
1202        .unwrap_or_else(Self::default)
1203    }
1204}
1205
1206impl<const D: usize, const I: usize, const J: usize> Div<TensorRank0> for TensorRank2<D, I, J> {
1207    type Output = Self;
1208    fn div(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
1209        self /= &tensor_rank_0;
1210        self
1211    }
1212}
1213
1214impl<const D: usize, const I: usize, const J: usize> Div<TensorRank0> for &TensorRank2<D, I, J> {
1215    type Output = TensorRank2<D, I, J>;
1216    fn div(self, tensor_rank_0: TensorRank0) -> Self::Output {
1217        self.iter().map(|self_i| self_i / tensor_rank_0).collect()
1218    }
1219}
1220
1221impl<const D: usize, const I: usize, const J: usize> Div<&TensorRank0> for TensorRank2<D, I, J> {
1222    type Output = Self;
1223    fn div(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
1224        self /= tensor_rank_0;
1225        self
1226    }
1227}
1228
1229impl<const D: usize, const I: usize, const J: usize> Div<&TensorRank0> for &TensorRank2<D, I, J> {
1230    type Output = TensorRank2<D, I, J>;
1231    fn div(self, tensor_rank_0: &TensorRank0) -> Self::Output {
1232        self.iter().map(|self_i| self_i / tensor_rank_0).collect()
1233    }
1234}
1235
1236impl<const D: usize, const I: usize, const J: usize> DivAssign<TensorRank0>
1237    for TensorRank2<D, I, J>
1238{
1239    fn div_assign(&mut self, tensor_rank_0: TensorRank0) {
1240        self.iter_mut().for_each(|self_i| *self_i /= &tensor_rank_0);
1241    }
1242}
1243
1244impl<const D: usize, const I: usize, const J: usize> DivAssign<&TensorRank0>
1245    for TensorRank2<D, I, J>
1246{
1247    fn div_assign(&mut self, tensor_rank_0: &TensorRank0) {
1248        self.iter_mut().for_each(|self_i| *self_i /= tensor_rank_0);
1249    }
1250}
1251
1252impl<const D: usize, const I: usize, const J: usize> Mul<TensorRank0> for TensorRank2<D, I, J> {
1253    type Output = Self;
1254    fn mul(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
1255        self *= &tensor_rank_0;
1256        self
1257    }
1258}
1259
1260impl<const D: usize, const I: usize, const J: usize> Mul<TensorRank0> for &TensorRank2<D, I, J> {
1261    type Output = TensorRank2<D, I, J>;
1262    fn mul(self, tensor_rank_0: TensorRank0) -> Self::Output {
1263        self.iter().map(|self_i| self_i * tensor_rank_0).collect()
1264    }
1265}
1266
1267impl<const D: usize, const I: usize, const J: usize> Mul<&TensorRank0> for TensorRank2<D, I, J> {
1268    type Output = Self;
1269    fn mul(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
1270        self *= tensor_rank_0;
1271        self
1272    }
1273}
1274
1275impl<const D: usize, const I: usize, const J: usize> Mul<&TensorRank0> for &TensorRank2<D, I, J> {
1276    type Output = TensorRank2<D, I, J>;
1277    fn mul(self, tensor_rank_0: &TensorRank0) -> Self::Output {
1278        self.iter().map(|self_i| self_i * tensor_rank_0).collect()
1279    }
1280}
1281
1282impl<const D: usize, const I: usize, const J: usize> MulAssign<TensorRank0>
1283    for TensorRank2<D, I, J>
1284{
1285    fn mul_assign(&mut self, tensor_rank_0: TensorRank0) {
1286        self.iter_mut().for_each(|self_i| *self_i *= &tensor_rank_0);
1287    }
1288}
1289
1290impl<const D: usize, const I: usize, const J: usize> MulAssign<&TensorRank0>
1291    for TensorRank2<D, I, J>
1292{
1293    fn mul_assign(&mut self, tensor_rank_0: &TensorRank0) {
1294        self.iter_mut().for_each(|self_i| *self_i *= tensor_rank_0);
1295    }
1296}
1297
1298impl<const D: usize, const I: usize, const J: usize> Mul<TensorRank1<D, J>>
1299    for TensorRank2<D, I, J>
1300{
1301    type Output = TensorRank1<D, I>;
1302    fn mul(self, tensor_rank_1: TensorRank1<D, J>) -> Self::Output {
1303        self.into_iter()
1304            .map(|self_i| self_i * &tensor_rank_1)
1305            .collect()
1306    }
1307}
1308
1309impl<const D: usize, const I: usize, const J: usize> Mul<&TensorRank1<D, J>>
1310    for TensorRank2<D, I, J>
1311{
1312    type Output = TensorRank1<D, I>;
1313    fn mul(self, tensor_rank_1: &TensorRank1<D, J>) -> Self::Output {
1314        self.into_iter()
1315            .map(|self_i| self_i * tensor_rank_1)
1316            .collect()
1317    }
1318}
1319
1320impl<const D: usize, const I: usize, const J: usize> Mul<TensorRank1<D, J>>
1321    for &TensorRank2<D, I, J>
1322{
1323    type Output = TensorRank1<D, I>;
1324    fn mul(self, tensor_rank_1: TensorRank1<D, J>) -> Self::Output {
1325        self.iter().map(|self_i| self_i * &tensor_rank_1).collect()
1326    }
1327}
1328
1329impl<const D: usize, const I: usize, const J: usize> Mul<&TensorRank1<D, J>>
1330    for &TensorRank2<D, I, J>
1331{
1332    type Output = TensorRank1<D, I>;
1333    fn mul(self, tensor_rank_1: &TensorRank1<D, J>) -> Self::Output {
1334        self.iter().map(|self_i| self_i * tensor_rank_1).collect()
1335    }
1336}
1337
1338impl<const D: usize, const I: usize, const J: usize> Add for TensorRank2<D, I, J> {
1339    type Output = Self;
1340    fn add(mut self, tensor_rank_2: Self) -> Self::Output {
1341        self += tensor_rank_2;
1342        self
1343    }
1344}
1345
1346impl<const D: usize, const I: usize, const J: usize> Add<&Self> for TensorRank2<D, I, J> {
1347    type Output = Self;
1348    fn add(mut self, tensor_rank_2: &Self) -> Self::Output {
1349        self += tensor_rank_2;
1350        self
1351    }
1352}
1353
1354impl<const D: usize, const I: usize, const J: usize> Add<TensorRank2<D, I, J>>
1355    for &TensorRank2<D, I, J>
1356{
1357    type Output = TensorRank2<D, I, J>;
1358    fn add(self, mut tensor_rank_2: TensorRank2<D, I, J>) -> Self::Output {
1359        tensor_rank_2 += self;
1360        tensor_rank_2
1361    }
1362}
1363
1364impl<const D: usize, const I: usize, const J: usize> AddAssign for TensorRank2<D, I, J> {
1365    fn add_assign(&mut self, tensor_rank_2: Self) {
1366        self.iter_mut()
1367            .zip(tensor_rank_2)
1368            .for_each(|(self_i, tensor_rank_2_i)| *self_i += tensor_rank_2_i);
1369    }
1370}
1371
1372impl<const D: usize, const I: usize, const J: usize> AddAssign<&Self> for TensorRank2<D, I, J> {
1373    fn add_assign(&mut self, tensor_rank_2: &Self) {
1374        self.iter_mut()
1375            .zip(tensor_rank_2.iter())
1376            .for_each(|(self_i, tensor_rank_2_i)| *self_i += tensor_rank_2_i);
1377    }
1378}
1379
1380impl<const D: usize, const I: usize, const J: usize, const K: usize> Mul<TensorRank2<D, J, K>>
1381    for TensorRank2<D, I, J>
1382{
1383    type Output = TensorRank2<D, I, K>;
1384    fn mul(self, tensor_rank_2: TensorRank2<D, J, K>) -> Self::Output {
1385        self.into_iter()
1386            .map(|self_i| {
1387                self_i
1388                    .into_iter()
1389                    .zip(tensor_rank_2.iter())
1390                    .map(|(self_ij, tensor_rank_2_j)| tensor_rank_2_j * self_ij)
1391                    .sum()
1392            })
1393            .collect()
1394    }
1395}
1396
1397impl<const D: usize, const I: usize, const J: usize, const K: usize> Mul<&TensorRank2<D, J, K>>
1398    for TensorRank2<D, I, J>
1399{
1400    type Output = TensorRank2<D, I, K>;
1401    fn mul(self, tensor_rank_2: &TensorRank2<D, J, K>) -> Self::Output {
1402        self.into_iter()
1403            .map(|self_i| {
1404                self_i
1405                    .into_iter()
1406                    .zip(tensor_rank_2.iter())
1407                    .map(|(self_ij, tensor_rank_2_j)| tensor_rank_2_j * self_ij)
1408                    .sum()
1409            })
1410            .collect()
1411    }
1412}
1413
1414impl<const D: usize, const I: usize, const J: usize, const K: usize> Mul<TensorRank2<D, J, K>>
1415    for &TensorRank2<D, I, J>
1416{
1417    type Output = TensorRank2<D, I, K>;
1418    fn mul(self, tensor_rank_2: TensorRank2<D, J, K>) -> Self::Output {
1419        self.iter()
1420            .map(|self_i| {
1421                self_i
1422                    .iter()
1423                    .zip(tensor_rank_2.iter())
1424                    .map(|(self_ij, tensor_rank_2_j)| tensor_rank_2_j * self_ij)
1425                    .sum()
1426            })
1427            .collect()
1428    }
1429}
1430
1431impl<const D: usize, const I: usize, const J: usize, const K: usize> Mul<&TensorRank2<D, J, K>>
1432    for &TensorRank2<D, I, J>
1433{
1434    type Output = TensorRank2<D, I, K>;
1435    fn mul(self, tensor_rank_2: &TensorRank2<D, J, K>) -> Self::Output {
1436        self.iter()
1437            .map(|self_i| {
1438                self_i
1439                    .iter()
1440                    .zip(tensor_rank_2.iter())
1441                    .map(|(self_ij, tensor_rank_2_j)| tensor_rank_2_j * self_ij)
1442                    .sum()
1443            })
1444            .collect()
1445    }
1446}
1447
1448impl<const D: usize, const I: usize, const J: usize> MulAssign<TensorRank2<D, J, J>>
1449    for TensorRank2<D, I, J>
1450{
1451    fn mul_assign(&mut self, tensor_rank_2: TensorRank2<D, J, J>) {
1452        *self = &*self * tensor_rank_2
1453    }
1454}
1455
1456impl<const D: usize, const I: usize, const J: usize> MulAssign<&TensorRank2<D, J, J>>
1457    for TensorRank2<D, I, J>
1458{
1459    fn mul_assign(&mut self, tensor_rank_2: &TensorRank2<D, J, J>) {
1460        *self = &*self * tensor_rank_2
1461    }
1462}
1463
1464impl<const D: usize, const I: usize, const J: usize> Sub for TensorRank2<D, I, J> {
1465    type Output = Self;
1466    fn sub(mut self, tensor_rank_2: Self) -> Self::Output {
1467        self -= tensor_rank_2;
1468        self
1469    }
1470}
1471
1472impl<const D: usize, const I: usize, const J: usize> Sub<&Self> for TensorRank2<D, I, J> {
1473    type Output = Self;
1474    fn sub(mut self, tensor_rank_2: &Self) -> Self::Output {
1475        self -= tensor_rank_2;
1476        self
1477    }
1478}
1479
1480impl<const D: usize, const I: usize, const J: usize> Sub<TensorRank2<D, I, J>>
1481    for &TensorRank2<D, I, J>
1482{
1483    type Output = TensorRank2<D, I, J>;
1484    fn sub(self, tensor_rank_2: TensorRank2<D, I, J>) -> Self::Output {
1485        let mut output = self.clone();
1486        output -= tensor_rank_2;
1487        output
1488    }
1489}
1490
1491impl<const D: usize, const I: usize, const J: usize> Sub for &TensorRank2<D, I, J> {
1492    type Output = TensorRank2<D, I, J>;
1493    fn sub(self, tensor_rank_2: Self) -> Self::Output {
1494        let mut output = self.clone();
1495        output -= tensor_rank_2;
1496        output
1497    }
1498}
1499
1500impl<const D: usize, const I: usize, const J: usize> SubAssign for TensorRank2<D, I, J> {
1501    fn sub_assign(&mut self, tensor_rank_2: Self) {
1502        self.iter_mut()
1503            .zip(tensor_rank_2)
1504            .for_each(|(self_i, tensor_rank_2_i)| *self_i -= tensor_rank_2_i);
1505    }
1506}
1507
1508impl<const D: usize, const I: usize, const J: usize> SubAssign<&Self> for TensorRank2<D, I, J> {
1509    fn sub_assign(&mut self, tensor_rank_2: &Self) {
1510        self.iter_mut()
1511            .zip(tensor_rank_2.iter())
1512            .for_each(|(self_i, tensor_rank_2_i)| *self_i -= tensor_rank_2_i);
1513    }
1514}
1515
1516impl<const D: usize, const I: usize, const J: usize, const W: usize> Mul<TensorRank1List<D, J, W>>
1517    for TensorRank2<D, I, J>
1518{
1519    type Output = TensorRank1List<D, I, W>;
1520    fn mul(self, tensor_rank_1_list: TensorRank1List<D, J, W>) -> Self::Output {
1521        tensor_rank_1_list
1522            .into_iter()
1523            .map(|tensor_rank_1| &self * tensor_rank_1)
1524            .collect()
1525    }
1526}
1527
1528impl<const D: usize, const I: usize, const J: usize, const W: usize> Mul<&TensorRank1List<D, J, W>>
1529    for TensorRank2<D, I, J>
1530{
1531    type Output = TensorRank1List<D, I, W>;
1532    fn mul(self, tensor_rank_1_list: &TensorRank1List<D, J, W>) -> Self::Output {
1533        tensor_rank_1_list
1534            .iter()
1535            .map(|tensor_rank_1| &self * tensor_rank_1)
1536            .collect()
1537    }
1538}
1539
1540impl<const D: usize, const I: usize, const J: usize, const W: usize> Mul<TensorRank1List<D, J, W>>
1541    for &TensorRank2<D, I, J>
1542{
1543    type Output = TensorRank1List<D, I, W>;
1544    fn mul(self, tensor_rank_1_list: TensorRank1List<D, J, W>) -> Self::Output {
1545        tensor_rank_1_list
1546            .into_iter()
1547            .map(|tensor_rank_1| self * tensor_rank_1)
1548            .collect()
1549    }
1550}
1551
1552impl<const D: usize, const I: usize, const J: usize, const W: usize> Mul<&TensorRank1List<D, J, W>>
1553    for &TensorRank2<D, I, J>
1554{
1555    type Output = TensorRank1List<D, I, W>;
1556    fn mul(self, tensor_rank_1_list: &TensorRank1List<D, J, W>) -> Self::Output {
1557        tensor_rank_1_list
1558            .iter()
1559            .map(|tensor_rank_1| self * tensor_rank_1)
1560            .collect()
1561    }
1562}
1563
1564impl<const D: usize, const I: usize, const J: usize> Mul<TensorRank1Vec<D, J>>
1565    for TensorRank2<D, I, J>
1566{
1567    type Output = TensorRank1Vec<D, I>;
1568    fn mul(self, tensor_rank_1_vec: TensorRank1Vec<D, J>) -> Self::Output {
1569        tensor_rank_1_vec
1570            .into_iter()
1571            .map(|tensor_rank_1| &self * tensor_rank_1)
1572            .collect()
1573    }
1574}
1575
1576impl<const D: usize, const I: usize, const J: usize> Mul<&TensorRank1Vec<D, J>>
1577    for TensorRank2<D, I, J>
1578{
1579    type Output = TensorRank1Vec<D, I>;
1580    fn mul(self, tensor_rank_1_vec: &TensorRank1Vec<D, J>) -> Self::Output {
1581        tensor_rank_1_vec
1582            .iter()
1583            .map(|tensor_rank_1| &self * tensor_rank_1)
1584            .collect()
1585    }
1586}
1587
1588impl<const D: usize, const I: usize, const J: usize> Mul<TensorRank1Vec<D, J>>
1589    for &TensorRank2<D, I, J>
1590{
1591    type Output = TensorRank1Vec<D, I>;
1592    fn mul(self, tensor_rank_1_vec: TensorRank1Vec<D, J>) -> Self::Output {
1593        tensor_rank_1_vec
1594            .into_iter()
1595            .map(|tensor_rank_1| self * tensor_rank_1)
1596            .collect()
1597    }
1598}
1599
1600impl<const D: usize, const I: usize, const J: usize> Mul<&TensorRank1Vec<D, J>>
1601    for &TensorRank2<D, I, J>
1602{
1603    type Output = TensorRank1Vec<D, I>;
1604    fn mul(self, tensor_rank_1_vec: &TensorRank1Vec<D, J>) -> Self::Output {
1605        tensor_rank_1_vec
1606            .iter()
1607            .map(|tensor_rank_1| self * tensor_rank_1)
1608            .collect()
1609    }
1610}
1611
1612impl<const D: usize, const I: usize, const J: usize, const K: usize, const W: usize, const X: usize>
1613    Mul<TensorRank2List2D<D, J, K, W, X>> for TensorRank2<D, I, J>
1614{
1615    type Output = TensorRank2List2D<D, I, K, W, X>;
1616    fn mul(self, tensor_rank_2_list_2d: TensorRank2List2D<D, J, K, W, X>) -> Self::Output {
1617        tensor_rank_2_list_2d
1618            .into_iter()
1619            .map(|tensor_rank_2_list_2d_entry| {
1620                tensor_rank_2_list_2d_entry
1621                    .into_iter()
1622                    .map(|tensor_rank_2| &self * tensor_rank_2)
1623                    .collect()
1624            })
1625            .collect()
1626    }
1627}
1628
1629impl<const D: usize, const I: usize, const J: usize, const K: usize, const W: usize, const X: usize>
1630    Mul<TensorRank2List2D<D, J, K, W, X>> for &TensorRank2<D, I, J>
1631{
1632    type Output = TensorRank2List2D<D, I, K, W, X>;
1633    fn mul(self, tensor_rank_2_list_2d: TensorRank2List2D<D, J, K, W, X>) -> Self::Output {
1634        tensor_rank_2_list_2d
1635            .into_iter()
1636            .map(|tensor_rank_2_list_2d_entry| {
1637                tensor_rank_2_list_2d_entry
1638                    .into_iter()
1639                    .map(|tensor_rank_2| self * tensor_rank_2)
1640                    .collect()
1641            })
1642            .collect()
1643    }
1644}
1645
1646impl<const D: usize, const I: usize, const J: usize, const K: usize> Mul<TensorRank2Vec2D<D, J, K>>
1647    for TensorRank2<D, I, J>
1648{
1649    type Output = TensorRank2Vec2D<D, I, K>;
1650    fn mul(self, tensor_rank_2_list_2d: TensorRank2Vec2D<D, J, K>) -> Self::Output {
1651        tensor_rank_2_list_2d
1652            .into_iter()
1653            .map(|tensor_rank_2_list_2d_entry| {
1654                tensor_rank_2_list_2d_entry
1655                    .into_iter()
1656                    .map(|tensor_rank_2| &self * tensor_rank_2)
1657                    .collect()
1658            })
1659            .collect()
1660    }
1661}
1662
1663impl<const D: usize, const I: usize, const J: usize, const K: usize> Mul<TensorRank2Vec2D<D, J, K>>
1664    for &TensorRank2<D, I, J>
1665{
1666    type Output = TensorRank2Vec2D<D, I, K>;
1667    fn mul(self, tensor_rank_2_list_2d: TensorRank2Vec2D<D, J, K>) -> Self::Output {
1668        tensor_rank_2_list_2d
1669            .into_iter()
1670            .map(|tensor_rank_2_list_2d_entry| {
1671                tensor_rank_2_list_2d_entry
1672                    .into_iter()
1673                    .map(|tensor_rank_2| self * tensor_rank_2)
1674                    .collect()
1675            })
1676            .collect()
1677    }
1678}
1679
1680#[allow(clippy::suspicious_arithmetic_impl)]
1681impl<const I: usize, const J: usize, const K: usize, const L: usize> Div<TensorRank4<3, I, J, K, L>>
1682    for &TensorRank2<3, I, J>
1683{
1684    type Output = TensorRank2<3, K, L>;
1685    fn div(self, tensor_rank_4: TensorRank4<3, I, J, K, L>) -> Self::Output {
1686        let tensor_rank_2: TensorRank2<9, 88, 99> = tensor_rank_4.into();
1687        let output_tensor_rank_1 = tensor_rank_2.inverse() * self.as_tensor_rank_1();
1688        let mut output = TensorRank2::zero();
1689        output.iter_mut().enumerate().for_each(|(i, output_i)| {
1690            output_i
1691                .iter_mut()
1692                .enumerate()
1693                .for_each(|(j, output_ij)| *output_ij = output_tensor_rank_1[3 * i + j])
1694        });
1695        output
1696    }
1697}