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