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