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