Skip to main content

conspire/math/tensor/rank_2/
mod.rs

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