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