conspire/math/tensor/rank_4/
mod.rs

1#[cfg(test)]
2mod test;
3
4#[cfg(test)]
5use super::test::ErrorTensor;
6
7use std::{
8    array::from_fn,
9    fmt::{self, Display, Formatter},
10    iter::Sum,
11    ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
12};
13
14use super::{
15    Hessian, Rank2, SquareMatrix, Tensor, TensorArray, Vector,
16    rank_0::TensorRank0,
17    rank_1::TensorRank1,
18    rank_2::TensorRank2,
19    rank_3::{TensorRank3, get_identity_1010_parts},
20};
21
22pub mod list;
23
24/// A *d*-dimensional tensor of rank 4.
25///
26/// `D` is the dimension, `I`, `J`, `K`, `L` are the configurations.
27#[repr(transparent)]
28#[derive(Clone, Debug, PartialEq)]
29pub struct TensorRank4<
30    const D: usize,
31    const I: usize,
32    const J: usize,
33    const K: usize,
34    const L: usize,
35>([TensorRank3<D, J, K, L>; D]);
36
37impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Default
38    for TensorRank4<D, I, J, K, L>
39{
40    fn default() -> Self {
41        Self::zero()
42    }
43}
44
45pub const IDENTITY_1010: TensorRank4<3, 1, 0, 1, 0> = TensorRank4(get_identity_1010_parts());
46
47impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
48    From<Vec<Vec<Vec<Vec<TensorRank0>>>>> for TensorRank4<D, I, J, K, L>
49{
50    fn from(vec_rank_4: Vec<Vec<Vec<Vec<TensorRank0>>>>) -> Self {
51        vec_rank_4
52            .into_iter()
53            .map(|vec_rank_3| {
54                vec_rank_3
55                    .into_iter()
56                    .map(|vec_rank_2| {
57                        vec_rank_2
58                            .into_iter()
59                            .map(|vec_rank_1| vec_rank_1.into_iter().collect())
60                            .collect()
61                    })
62                    .collect()
63            })
64            .collect()
65    }
66}
67
68impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
69    From<TensorRank4<D, I, J, K, L>> for Vec<Vec<Vec<Vec<TensorRank0>>>>
70{
71    fn from(tensor_rank_4: TensorRank4<D, I, J, K, L>) -> Self {
72        tensor_rank_4
73            .iter()
74            .map(|tensor_rank_3| {
75                tensor_rank_3
76                    .iter()
77                    .map(|tensor_rank_2| {
78                        tensor_rank_2
79                            .iter()
80                            .map(|tensor_rank_1| tensor_rank_1.iter().copied().collect())
81                            .collect()
82                    })
83                    .collect()
84            })
85            .collect()
86    }
87}
88
89impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
90    From<TensorRank4<D, I, J, K, L>> for Vec<TensorRank0>
91{
92    fn from(tensor_rank_4: TensorRank4<D, I, J, K, L>) -> Self {
93        tensor_rank_4
94            .iter()
95            .flat_map(|tensor_rank_3| {
96                tensor_rank_3.iter().flat_map(|tensor_rank_2| {
97                    tensor_rank_2
98                        .iter()
99                        .flat_map(|tensor_rank_1| tensor_rank_1.iter().copied())
100                })
101            })
102            .collect()
103    }
104}
105
106impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
107    From<TensorRank4<D, I, J, K, L>> for Vector
108{
109    fn from(tensor_rank_4: TensorRank4<D, I, J, K, L>) -> Self {
110        tensor_rank_4
111            .iter()
112            .flat_map(|tensor_rank_3| {
113                tensor_rank_3.iter().flat_map(|tensor_rank_2| {
114                    tensor_rank_2
115                        .iter()
116                        .flat_map(|tensor_rank_1| tensor_rank_1.iter().copied())
117                })
118            })
119            .collect()
120    }
121}
122
123impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Display
124    for TensorRank4<D, I, J, K, L>
125{
126    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
127        write!(f, "[")?;
128        self.iter()
129            .enumerate()
130            .try_for_each(|(i, entry)| write!(f, "{entry},\n\x1B[u\x1B[{}B\x1B[2D", i + 1))?;
131        write!(f, "\x1B[u\x1B[1A\x1B[{}C]", 16 * D + 2)
132    }
133}
134
135#[cfg(test)]
136impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> ErrorTensor
137    for TensorRank4<D, I, J, K, L>
138{
139    fn error_fd(&self, comparator: &Self, epsilon: &TensorRank0) -> Option<(bool, usize)> {
140        let error_count = self
141            .iter()
142            .zip(comparator.iter())
143            .map(|(self_i, comparator_i)| {
144                self_i
145                    .iter()
146                    .zip(comparator_i.iter())
147                    .map(|(self_ij, comparator_ij)| {
148                        self_ij
149                            .iter()
150                            .zip(comparator_ij.iter())
151                            .map(|(self_ijk, comparator_ijk)| {
152                                self_ijk
153                                    .iter()
154                                    .zip(comparator_ijk.iter())
155                                    .filter(|&(&self_ijkl, &comparator_ijkl)| {
156                                        &(self_ijkl / comparator_ijkl - 1.0).abs() >= epsilon
157                                            && (&self_ijkl.abs() >= epsilon
158                                                || &comparator_ijkl.abs() >= epsilon)
159                                    })
160                                    .count()
161                            })
162                            .sum::<usize>()
163                    })
164                    .sum::<usize>()
165            })
166            .sum();
167        if error_count > 0 {
168            let auxiliary = self
169                .iter()
170                .zip(comparator.iter())
171                .map(|(self_i, comparator_i)| {
172                    self_i
173                        .iter()
174                        .zip(comparator_i.iter())
175                        .map(|(self_ij, comparator_ij)| {
176                            self_ij
177                                .iter()
178                                .zip(comparator_ij.iter())
179                                .map(|(self_ijk, comparator_ijk)| {
180                                    self_ijk
181                                        .iter()
182                                        .zip(comparator_ijk.iter())
183                                        .filter(|&(&self_ijkl, &comparator_ijkl)| {
184                                            &(self_ijkl / comparator_ijkl - 1.0).abs() >= epsilon
185                                                && &(self_ijkl - comparator_ijkl).abs() >= epsilon
186                                                && (&self_ijkl.abs() >= epsilon
187                                                    || &comparator_ijkl.abs() >= epsilon)
188                                        })
189                                        .count()
190                                })
191                                .sum::<usize>()
192                        })
193                        .sum::<usize>()
194                })
195                .sum::<usize>()
196                > 0;
197            Some((auxiliary, error_count))
198        } else {
199            None
200        }
201    }
202}
203
204impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
205    TensorRank4<D, I, J, K, L>
206{
207    pub fn dyad_ij_kl(
208        tensor_rank_2_a: &TensorRank2<D, I, J>,
209        tensor_rank_2_b: &TensorRank2<D, K, L>,
210    ) -> Self {
211        tensor_rank_2_a
212            .iter()
213            .map(|tensor_rank_2_a_i| {
214                tensor_rank_2_a_i
215                    .iter()
216                    .map(|tensor_rank_2_a_ij| tensor_rank_2_b * tensor_rank_2_a_ij)
217                    .collect()
218            })
219            .collect()
220    }
221    pub fn dyad_ik_jl(
222        tensor_rank_2_a: &TensorRank2<D, I, K>,
223        tensor_rank_2_b: &TensorRank2<D, J, L>,
224    ) -> Self {
225        tensor_rank_2_a
226            .iter()
227            .map(|tensor_rank_2_a_i| {
228                tensor_rank_2_b
229                    .iter()
230                    .map(|tensor_rank_2_b_j| {
231                        tensor_rank_2_a_i
232                            .iter()
233                            .map(|tensor_rank_2_a_ik| tensor_rank_2_b_j * tensor_rank_2_a_ik)
234                            .collect()
235                    })
236                    .collect()
237            })
238            .collect()
239    }
240    pub fn dyad_il_jk(
241        tensor_rank_2_a: &TensorRank2<D, I, L>,
242        tensor_rank_2_b: &TensorRank2<D, J, K>,
243    ) -> Self {
244        tensor_rank_2_a
245            .iter()
246            .map(|tensor_rank_2_a_i| {
247                tensor_rank_2_b
248                    .iter()
249                    .map(|tensor_rank_2_b_j| {
250                        tensor_rank_2_b_j
251                            .iter()
252                            .map(|tensor_rank_2_b_jk| tensor_rank_2_a_i * tensor_rank_2_b_jk)
253                            .collect()
254                    })
255                    .collect()
256            })
257            .collect()
258    }
259    pub fn dyad_il_kj(
260        tensor_rank_2_a: &TensorRank2<D, I, L>,
261        tensor_rank_2_b: &TensorRank2<D, K, J>,
262    ) -> Self {
263        Self::dyad_il_jk(tensor_rank_2_a, &(tensor_rank_2_b.transpose()))
264    }
265}
266
267impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Hessian
268    for TensorRank4<D, I, J, K, L>
269{
270    fn fill_into(self, square_matrix: &mut SquareMatrix) {
271        self.into_iter().enumerate().for_each(|(i, self_i)| {
272            self_i.into_iter().enumerate().for_each(|(j, self_ij)| {
273                self_ij.into_iter().enumerate().for_each(|(k, self_ijk)| {
274                    self_ijk
275                        .into_iter()
276                        .enumerate()
277                        .for_each(|(l, self_ijkl)| square_matrix[D * i + j][D * k + l] = self_ijkl)
278                })
279            })
280        })
281    }
282}
283
284impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Tensor
285    for TensorRank4<D, I, J, K, L>
286{
287    type Item = TensorRank3<D, J, K, L>;
288    fn iter(&self) -> impl Iterator<Item = &Self::Item> {
289        self.0.iter()
290    }
291    fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item> {
292        self.0.iter_mut()
293    }
294    fn len(&self) -> usize {
295        D
296    }
297    fn size(&self) -> usize {
298        D * D * D * D
299    }
300}
301
302impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> IntoIterator
303    for TensorRank4<D, I, J, K, L>
304{
305    type Item = TensorRank3<D, J, K, L>;
306    type IntoIter = std::array::IntoIter<Self::Item, D>;
307    fn into_iter(self) -> Self::IntoIter {
308        self.0.into_iter()
309    }
310}
311
312impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> TensorArray
313    for TensorRank4<D, I, J, K, L>
314{
315    type Array = [[[[TensorRank0; D]; D]; D]; D];
316    type Item = TensorRank3<D, J, K, L>;
317    fn as_array(&self) -> Self::Array {
318        let mut array = [[[[0.0; D]; D]; D]; D];
319        array
320            .iter_mut()
321            .zip(self.iter())
322            .for_each(|(entry_rank_3, tensor_rank_3)| *entry_rank_3 = tensor_rank_3.as_array());
323        array
324    }
325    fn identity() -> Self {
326        Self::dyad_ij_kl(&TensorRank2::identity(), &TensorRank2::identity())
327    }
328    fn new(array: Self::Array) -> Self {
329        array.into_iter().map(Self::Item::new).collect()
330    }
331    fn zero() -> Self {
332        Self(from_fn(|_| Self::Item::zero()))
333    }
334}
335
336impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
337    FromIterator<TensorRank3<D, J, K, L>> for TensorRank4<D, I, J, K, L>
338{
339    fn from_iter<Ii: IntoIterator<Item = TensorRank3<D, J, K, L>>>(into_iterator: Ii) -> Self {
340        let mut tensor_rank_4 = Self::zero();
341        tensor_rank_4
342            .iter_mut()
343            .zip(into_iterator)
344            .for_each(|(tensor_rank_4_i, value_i)| *tensor_rank_4_i = value_i);
345        tensor_rank_4
346    }
347}
348
349impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Index<usize>
350    for TensorRank4<D, I, J, K, L>
351{
352    type Output = TensorRank3<D, J, K, L>;
353    fn index(&self, index: usize) -> &Self::Output {
354        &self.0[index]
355    }
356}
357
358impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> IndexMut<usize>
359    for TensorRank4<D, I, J, K, L>
360{
361    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
362        &mut self.0[index]
363    }
364}
365
366impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Sum
367    for TensorRank4<D, I, J, K, L>
368{
369    fn sum<Ii>(iter: Ii) -> Self
370    where
371        Ii: Iterator<Item = Self>,
372    {
373        iter.reduce(|mut acc, item| {
374            acc += item;
375            acc
376        })
377        .unwrap_or_else(Self::default)
378    }
379}
380
381pub trait ContractAllIndicesWithFirstIndicesOf<TIM, TJN, TKO, TLP> {
382    type Output;
383    fn contract_all_indices_with_first_indices_of(
384        &self,
385        tensor_rank_2_a: TIM,
386        tensor_rank_2_b: TJN,
387        tensor_rank_2_c: TKO,
388        tensor_rank_2_d: TLP,
389    ) -> Self::Output;
390}
391
392impl<
393    const D: usize,
394    const I: usize,
395    const J: usize,
396    const K: usize,
397    const L: usize,
398    const M: usize,
399    const N: usize,
400    const O: usize,
401    const P: usize,
402>
403    ContractAllIndicesWithFirstIndicesOf<
404        &TensorRank2<D, I, M>,
405        &TensorRank2<D, J, N>,
406        &TensorRank2<D, K, O>,
407        &TensorRank2<D, L, P>,
408    > for TensorRank4<D, I, J, K, L>
409{
410    type Output = TensorRank4<D, M, N, O, P>;
411    fn contract_all_indices_with_first_indices_of(
412        &self,
413        tensor_rank_2_a: &TensorRank2<D, I, M>,
414        tensor_rank_2_b: &TensorRank2<D, J, N>,
415        tensor_rank_2_c: &TensorRank2<D, K, O>,
416        tensor_rank_2_d: &TensorRank2<D, L, P>,
417    ) -> Self::Output {
418        let mut output = TensorRank4::zero();
419        self.iter().zip(tensor_rank_2_a.iter()).for_each(|(self_m, tensor_rank_2_a_m)|
420            self_m.iter().zip(tensor_rank_2_b.iter()).for_each(|(self_mn, tensor_rank_2_b_n)|
421                self_mn.iter().zip(tensor_rank_2_c.iter()).for_each(|(self_mno, tensor_rank_2_c_o)|
422                    self_mno.iter().zip(tensor_rank_2_d.iter()).for_each(|(self_mnop, tensor_rank_2_d_p)|
423                        output.iter_mut().zip(tensor_rank_2_a_m.iter()).for_each(|(output_i, tensor_rank_2_a_mi)|
424                            output_i.iter_mut().zip(tensor_rank_2_b_n.iter()).for_each(|(output_ij, tensor_rank_2_b_nj)|
425                                output_ij.iter_mut().zip(tensor_rank_2_c_o.iter()).for_each(|(output_ijk, tensor_rank_2_c_ok)|
426                                    output_ijk.iter_mut().zip(tensor_rank_2_d_p.iter()).for_each(|(output_ijkl, tensor_rank_2_dp)|
427                                        *output_ijkl += self_mnop*tensor_rank_2_a_mi*tensor_rank_2_b_nj*tensor_rank_2_c_ok*tensor_rank_2_dp
428                                    )
429                                )
430                            )
431                        )
432                    )
433                )
434            )
435        );
436        output
437    }
438}
439
440pub trait ContractFirstThirdFourthIndicesWithFirstIndicesOf<TIM, TKO, TLP> {
441    type Output;
442    fn contract_first_third_fourth_indices_with_first_indices_of(
443        &self,
444        tensor_rank_2_a: TIM,
445        tensor_rank_2_c: TKO,
446        tensor_rank_2_d: TLP,
447    ) -> Self::Output;
448}
449
450impl<
451    const D: usize,
452    const I: usize,
453    const J: usize,
454    const K: usize,
455    const L: usize,
456    const M: usize,
457    const O: usize,
458    const P: usize,
459>
460    ContractFirstThirdFourthIndicesWithFirstIndicesOf<
461        &TensorRank2<D, I, M>,
462        &TensorRank2<D, K, O>,
463        &TensorRank2<D, L, P>,
464    > for TensorRank4<D, I, J, K, L>
465{
466    type Output = TensorRank4<D, M, J, O, P>;
467    fn contract_first_third_fourth_indices_with_first_indices_of(
468        &self,
469        tensor_rank_2_a: &TensorRank2<D, I, M>,
470        tensor_rank_2_b: &TensorRank2<D, K, O>,
471        tensor_rank_2_c: &TensorRank2<D, L, P>,
472    ) -> Self::Output {
473        let mut output = TensorRank4::zero();
474        self.iter().zip(tensor_rank_2_a.iter()).for_each(|(self_q, tensor_rank_2_a_q)|
475            output.iter_mut().zip(tensor_rank_2_a_q.iter()).for_each(|(output_i, tensor_rank_2_a_qi)|
476                output_i.iter_mut().zip(self_q.iter()).for_each(|(output_ij, self_qj)|
477                    self_qj.iter().zip(tensor_rank_2_b.iter()).for_each(|(self_qjm, tensor_rank_2_b_m)|
478                        self_qjm.iter().zip(tensor_rank_2_c.iter()).for_each(|(self_qjmn, tensor_rank_2_c_n)|
479                            output_ij.iter_mut().zip(tensor_rank_2_b_m.iter()).for_each(|(output_ijk, tensor_rank_2_b_mk)|
480                                output_ijk.iter_mut().zip(tensor_rank_2_c_n.iter()).for_each(|(output_ijkl, tensor_rank_2_c_nl)|
481                                    *output_ijkl += self_qjmn*tensor_rank_2_a_qi*tensor_rank_2_b_mk*tensor_rank_2_c_nl
482                                )
483                            )
484                        )
485                    )
486                )
487            )
488        );
489        output
490    }
491}
492
493pub trait ContractSecondIndexWithFirstIndexOf<TJN> {
494    type Output;
495    fn contract_second_index_with_first_index_of(&self, tensor_rank_2: TJN) -> Self::Output;
496}
497
498impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize, const N: usize>
499    ContractSecondIndexWithFirstIndexOf<&TensorRank2<D, J, N>> for TensorRank4<D, I, J, K, L>
500{
501    type Output = TensorRank4<D, I, N, K, L>;
502    fn contract_second_index_with_first_index_of(
503        &self,
504        tensor_rank_2: &TensorRank2<D, J, N>,
505    ) -> Self::Output {
506        let mut output = TensorRank4::zero();
507        output
508            .iter_mut()
509            .zip(self.iter())
510            .for_each(|(output_i, self_i)| {
511                self_i
512                    .iter()
513                    .zip(tensor_rank_2.iter())
514                    .for_each(|(self_is, tensor_rank_2_s)| {
515                        output_i.iter_mut().zip(tensor_rank_2_s.iter()).for_each(
516                            |(output_ij, tensor_rank_2_sj)| {
517                                *output_ij += self_is * tensor_rank_2_sj
518                            },
519                        )
520                    })
521            });
522        output
523    }
524}
525
526pub trait ContractSecondFourthIndicesWithFirstIndicesOf<TJ, TL> {
527    type Output;
528    fn contract_second_fourth_indices_with_first_indices_of(
529        &self,
530        object_a: TJ,
531        object_b: TL,
532    ) -> Self::Output;
533}
534
535impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
536    ContractSecondFourthIndicesWithFirstIndicesOf<&TensorRank1<D, J>, &TensorRank1<D, L>>
537    for TensorRank4<D, I, J, K, L>
538{
539    type Output = TensorRank2<D, I, K>;
540    fn contract_second_fourth_indices_with_first_indices_of(
541        &self,
542        tensor_rank_1_a: &TensorRank1<D, J>,
543        tensor_rank_1_b: &TensorRank1<D, L>,
544    ) -> Self::Output {
545        self.iter()
546            .map(|self_i| {
547                self_i
548                    .iter()
549                    .zip(tensor_rank_1_a.iter())
550                    .map(|(self_ij, tensor_rank_1_a_j)| {
551                        self_ij
552                            .iter()
553                            .map(|self_ijk| self_ijk * (tensor_rank_1_b * tensor_rank_1_a_j))
554                            .collect()
555                    })
556                    .sum()
557            })
558            .collect()
559    }
560}
561
562pub trait ContractThirdFourthIndicesWithFirstSecondIndicesOf<TKL> {
563    type Output;
564    fn contract_third_fourth_indices_with_first_second_indices_of(
565        &self,
566        tensor: TKL,
567    ) -> Self::Output;
568}
569
570impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
571    ContractThirdFourthIndicesWithFirstSecondIndicesOf<&TensorRank2<D, K, L>>
572    for TensorRank4<D, I, J, K, L>
573{
574    type Output = TensorRank2<D, I, J>;
575    fn contract_third_fourth_indices_with_first_second_indices_of(
576        &self,
577        tensor_rank_2: &TensorRank2<D, K, L>,
578    ) -> Self::Output {
579        self.iter()
580            .map(|self_i| {
581                self_i
582                    .iter()
583                    .map(|self_ij| self_ij.full_contraction(tensor_rank_2))
584                    .collect()
585            })
586            .collect()
587    }
588}
589
590impl<
591    const D: usize,
592    const I: usize,
593    const J: usize,
594    const K: usize,
595    const L: usize,
596    const M: usize,
597    const N: usize,
598> ContractThirdFourthIndicesWithFirstSecondIndicesOf<&TensorRank4<D, K, L, M, N>>
599    for TensorRank4<D, I, J, K, L>
600{
601    type Output = TensorRank4<D, I, J, M, N>;
602    fn contract_third_fourth_indices_with_first_second_indices_of(
603        &self,
604        tensor: &TensorRank4<D, K, L, M, N>,
605    ) -> Self::Output {
606        self.iter()
607            .map(|self_i| {
608                self_i
609                    .iter()
610                    .map(|self_ij| {
611                        self_ij
612                            .iter()
613                            .zip(tensor.iter())
614                            .map(|(self_ijk, tensor_k)| {
615                                self_ijk
616                                    .iter()
617                                    .zip(tensor_k.iter())
618                                    .map(|(self_ijkl, tensor_kl)| tensor_kl * self_ijkl)
619                                    .sum()
620                            })
621                            .sum()
622                    })
623                    .collect()
624            })
625            .collect()
626    }
627}
628
629pub trait ContractFirstSecondIndicesWithSecondIndicesOf<TI, TJ> {
630    type Output;
631    fn contract_first_second_indices_with_second_indices_of(
632        &self,
633        object_a: TI,
634        object_b: TJ,
635    ) -> Self::Output;
636}
637
638impl<
639    const D: usize,
640    const I: usize,
641    const J: usize,
642    const K: usize,
643    const L: usize,
644    const M: usize,
645    const N: usize,
646> ContractFirstSecondIndicesWithSecondIndicesOf<&TensorRank2<D, I, M>, &TensorRank2<D, J, N>>
647    for TensorRank4<D, M, N, K, L>
648{
649    type Output = TensorRank4<D, I, J, K, L>;
650    fn contract_first_second_indices_with_second_indices_of(
651        &self,
652        tensor_rank_2_a: &TensorRank2<D, I, M>,
653        tensor_rank_2_b: &TensorRank2<D, J, N>,
654    ) -> Self::Output {
655        let mut output = TensorRank4::zero();
656        output
657            .iter_mut()
658            .zip(tensor_rank_2_a.iter())
659            .for_each(|(output_i, tensor_rank_2_a_i)| {
660                output_i.iter_mut().zip(tensor_rank_2_b.iter()).for_each(
661                    |(output_ij, tensor_rank_2_b_j)| {
662                        self.iter().zip(tensor_rank_2_a_i.iter()).for_each(
663                            |(self_m, tensor_rank_2_a_im)| {
664                                self_m.iter().zip(tensor_rank_2_b_j.iter()).for_each(
665                                    |(self_mn, tensor_rank_2_b_jn)| {
666                                        *output_ij +=
667                                            self_mn * tensor_rank_2_a_im * tensor_rank_2_b_jn
668                                    },
669                                )
670                            },
671                        )
672                    },
673                )
674            });
675        output
676    }
677}
678
679impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
680    Div<TensorRank0> for TensorRank4<D, I, J, K, L>
681{
682    type Output = Self;
683    fn div(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
684        self /= &tensor_rank_0;
685        self
686    }
687}
688
689impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
690    Div<TensorRank0> for &TensorRank4<D, I, J, K, L>
691{
692    type Output = TensorRank4<D, I, J, K, L>;
693    fn div(self, tensor_rank_0: TensorRank0) -> Self::Output {
694        self.iter().map(|self_i| self_i / tensor_rank_0).collect()
695    }
696}
697
698impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
699    Div<&TensorRank0> for TensorRank4<D, I, J, K, L>
700{
701    type Output = Self;
702    fn div(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
703        self /= tensor_rank_0;
704        self
705    }
706}
707
708impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
709    DivAssign<TensorRank0> for TensorRank4<D, I, J, K, L>
710{
711    fn div_assign(&mut self, tensor_rank_0: TensorRank0) {
712        self.iter_mut().for_each(|self_i| *self_i /= &tensor_rank_0);
713    }
714}
715
716impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
717    DivAssign<&TensorRank0> for TensorRank4<D, I, J, K, L>
718{
719    fn div_assign(&mut self, tensor_rank_0: &TensorRank0) {
720        self.iter_mut().for_each(|self_i| *self_i /= tensor_rank_0);
721    }
722}
723
724impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
725    Mul<TensorRank0> for TensorRank4<D, I, J, K, L>
726{
727    type Output = Self;
728    fn mul(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
729        self *= &tensor_rank_0;
730        self
731    }
732}
733
734impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
735    Mul<&TensorRank0> for TensorRank4<D, I, J, K, L>
736{
737    type Output = Self;
738    fn mul(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
739        self *= tensor_rank_0;
740        self
741    }
742}
743
744impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
745    MulAssign<TensorRank0> for TensorRank4<D, I, J, K, L>
746{
747    fn mul_assign(&mut self, tensor_rank_0: TensorRank0) {
748        self.iter_mut().for_each(|self_i| *self_i *= &tensor_rank_0);
749    }
750}
751
752impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
753    MulAssign<&TensorRank0> for TensorRank4<D, I, J, K, L>
754{
755    fn mul_assign(&mut self, tensor_rank_0: &TensorRank0) {
756        self.iter_mut().for_each(|self_i| *self_i *= tensor_rank_0);
757    }
758}
759
760impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize, const M: usize>
761    Mul<TensorRank2<D, L, M>> for TensorRank4<D, I, J, K, L>
762{
763    type Output = TensorRank4<D, I, J, K, M>;
764    fn mul(self, tensor_rank_2: TensorRank2<D, L, M>) -> Self::Output {
765        self.iter()
766            .map(|self_i| {
767                self_i
768                    .iter()
769                    .map(|self_ij| self_ij * &tensor_rank_2)
770                    .collect()
771            })
772            .collect()
773    }
774}
775
776impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize, const M: usize>
777    Mul<&TensorRank2<D, L, M>> for TensorRank4<D, I, J, K, L>
778{
779    type Output = TensorRank4<D, I, J, K, M>;
780    fn mul(self, tensor_rank_2: &TensorRank2<D, L, M>) -> Self::Output {
781        self.iter()
782            .map(|self_i| {
783                self_i
784                    .iter()
785                    .map(|self_ij| self_ij * tensor_rank_2)
786                    .collect()
787            })
788            .collect()
789    }
790}
791
792impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Add
793    for TensorRank4<D, I, J, K, L>
794{
795    type Output = Self;
796    fn add(mut self, tensor_rank_4: Self) -> Self::Output {
797        self += tensor_rank_4;
798        self
799    }
800}
801
802impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Add<&Self>
803    for TensorRank4<D, I, J, K, L>
804{
805    type Output = Self;
806    fn add(mut self, tensor_rank_4: &Self) -> Self::Output {
807        self += tensor_rank_4;
808        self
809    }
810}
811
812impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
813    Add<TensorRank4<D, I, J, K, L>> for &TensorRank4<D, I, J, K, L>
814{
815    type Output = TensorRank4<D, I, J, K, L>;
816    fn add(self, mut tensor_rank_4: TensorRank4<D, I, J, K, L>) -> Self::Output {
817        tensor_rank_4 += self;
818        tensor_rank_4
819    }
820}
821
822impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> AddAssign
823    for TensorRank4<D, I, J, K, L>
824{
825    fn add_assign(&mut self, tensor_rank_4: Self) {
826        self.iter_mut()
827            .zip(tensor_rank_4.iter())
828            .for_each(|(self_i, tensor_rank_4_i)| *self_i += tensor_rank_4_i);
829    }
830}
831
832impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
833    AddAssign<&Self> for TensorRank4<D, I, J, K, L>
834{
835    fn add_assign(&mut self, tensor_rank_4: &Self) {
836        self.iter_mut()
837            .zip(tensor_rank_4.iter())
838            .for_each(|(self_i, tensor_rank_4_i)| *self_i += tensor_rank_4_i);
839    }
840}
841
842impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Sub
843    for TensorRank4<D, I, J, K, L>
844{
845    type Output = Self;
846    fn sub(mut self, tensor_rank_4: Self) -> Self::Output {
847        self -= tensor_rank_4;
848        self
849    }
850}
851
852impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Sub<&Self>
853    for TensorRank4<D, I, J, K, L>
854{
855    type Output = Self;
856    fn sub(mut self, tensor_rank_4: &Self) -> Self::Output {
857        self -= tensor_rank_4;
858        self
859    }
860}
861
862impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Sub
863    for &TensorRank4<D, I, J, K, L>
864{
865    type Output = TensorRank4<D, I, J, K, L>;
866    fn sub(self, tensor_rank_4: Self) -> Self::Output {
867        tensor_rank_4
868            .iter()
869            .zip(self.iter())
870            .map(|(tensor_rank_4_i, self_i)| self_i - tensor_rank_4_i)
871            .collect()
872    }
873}
874
875impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> SubAssign
876    for TensorRank4<D, I, J, K, L>
877{
878    fn sub_assign(&mut self, tensor_rank_4: Self) {
879        self.iter_mut()
880            .zip(tensor_rank_4.iter())
881            .for_each(|(self_i, tensor_rank_4_i)| *self_i -= tensor_rank_4_i);
882    }
883}
884
885impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
886    SubAssign<&Self> for TensorRank4<D, I, J, K, L>
887{
888    fn sub_assign(&mut self, tensor_rank_4: &Self) {
889        self.iter_mut()
890            .zip(tensor_rank_4.iter())
891            .for_each(|(self_i, tensor_rank_4_i)| *self_i -= tensor_rank_4_i);
892    }
893}