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    fn is_positive_definite(&self) -> bool {
278        let tensor_rank_2: TensorRank2<9, 88, 99> = self.into();
279        tensor_rank_2.cholesky_decomposition().is_ok()
280    }
281}
282
283impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Tensor
284    for TensorRank4<D, I, J, K, L>
285{
286    type Item = TensorRank3<D, J, K, L>;
287    fn iter(&self) -> impl Iterator<Item = &Self::Item> {
288        self.0.iter()
289    }
290    fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item> {
291        self.0.iter_mut()
292    }
293}
294
295impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> IntoIterator
296    for TensorRank4<D, I, J, K, L>
297{
298    type Item = TensorRank3<D, J, K, L>;
299    type IntoIter = std::array::IntoIter<Self::Item, D>;
300    fn into_iter(self) -> Self::IntoIter {
301        self.0.into_iter()
302    }
303}
304
305impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> TensorArray
306    for TensorRank4<D, I, J, K, L>
307{
308    type Array = [[[[TensorRank0; D]; D]; D]; D];
309    type Item = TensorRank3<D, J, K, L>;
310    fn as_array(&self) -> Self::Array {
311        let mut array = [[[[0.0; D]; D]; D]; D];
312        array
313            .iter_mut()
314            .zip(self.iter())
315            .for_each(|(entry_rank_3, tensor_rank_3)| *entry_rank_3 = tensor_rank_3.as_array());
316        array
317    }
318    fn identity() -> Self {
319        Self::dyad_ij_kl(&TensorRank2::identity(), &TensorRank2::identity())
320    }
321    fn new(array: Self::Array) -> Self {
322        array.into_iter().map(Self::Item::new).collect()
323    }
324    fn zero() -> Self {
325        Self(from_fn(|_| Self::Item::zero()))
326    }
327}
328
329impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
330    FromIterator<TensorRank3<D, J, K, L>> for TensorRank4<D, I, J, K, L>
331{
332    fn from_iter<Ii: IntoIterator<Item = TensorRank3<D, J, K, L>>>(into_iterator: Ii) -> Self {
333        let mut tensor_rank_4 = Self::zero();
334        tensor_rank_4
335            .iter_mut()
336            .zip(into_iterator)
337            .for_each(|(tensor_rank_4_i, value_i)| *tensor_rank_4_i = value_i);
338        tensor_rank_4
339    }
340}
341
342impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Index<usize>
343    for TensorRank4<D, I, J, K, L>
344{
345    type Output = TensorRank3<D, J, K, L>;
346    fn index(&self, index: usize) -> &Self::Output {
347        &self.0[index]
348    }
349}
350
351impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> IndexMut<usize>
352    for TensorRank4<D, I, J, K, L>
353{
354    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
355        &mut self.0[index]
356    }
357}
358
359impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> std::iter::Sum
360    for TensorRank4<D, I, J, K, L>
361{
362    fn sum<Ii>(iter: Ii) -> Self
363    where
364        Ii: Iterator<Item = Self>,
365    {
366        let mut output = TensorRank4::zero();
367        iter.for_each(|item| output += item);
368        output
369    }
370}
371
372pub trait ContractAllIndicesWithFirstIndicesOf<TIM, TJN, TKO, TLP> {
373    type Output;
374    fn contract_all_indices_with_first_indices_of(
375        &self,
376        tensor_rank_2_a: TIM,
377        tensor_rank_2_b: TJN,
378        tensor_rank_2_c: TKO,
379        tensor_rank_2_d: TLP,
380    ) -> Self::Output;
381}
382
383impl<
384    const D: usize,
385    const I: usize,
386    const J: usize,
387    const K: usize,
388    const L: usize,
389    const M: usize,
390    const N: usize,
391    const O: usize,
392    const P: usize,
393>
394    ContractAllIndicesWithFirstIndicesOf<
395        &TensorRank2<D, I, M>,
396        &TensorRank2<D, J, N>,
397        &TensorRank2<D, K, O>,
398        &TensorRank2<D, L, P>,
399    > for TensorRank4<D, I, J, K, L>
400{
401    type Output = TensorRank4<D, M, N, O, P>;
402    fn contract_all_indices_with_first_indices_of(
403        &self,
404        tensor_rank_2_a: &TensorRank2<D, I, M>,
405        tensor_rank_2_b: &TensorRank2<D, J, N>,
406        tensor_rank_2_c: &TensorRank2<D, K, O>,
407        tensor_rank_2_d: &TensorRank2<D, L, P>,
408    ) -> Self::Output {
409        let mut output = TensorRank4::zero();
410        self.iter().zip(tensor_rank_2_a.iter()).for_each(|(self_m, tensor_rank_2_a_m)|
411            self_m.iter().zip(tensor_rank_2_b.iter()).for_each(|(self_mn, tensor_rank_2_b_n)|
412                self_mn.iter().zip(tensor_rank_2_c.iter()).for_each(|(self_mno, tensor_rank_2_c_o)|
413                    self_mno.iter().zip(tensor_rank_2_d.iter()).for_each(|(self_mnop, tensor_rank_2_d_p)|
414                        output.iter_mut().zip(tensor_rank_2_a_m.iter()).for_each(|(output_i, tensor_rank_2_a_mi)|
415                            output_i.iter_mut().zip(tensor_rank_2_b_n.iter()).for_each(|(output_ij, tensor_rank_2_b_nj)|
416                                output_ij.iter_mut().zip(tensor_rank_2_c_o.iter()).for_each(|(output_ijk, tensor_rank_2_c_ok)|
417                                    output_ijk.iter_mut().zip(tensor_rank_2_d_p.iter()).for_each(|(output_ijkl, tensor_rank_2_dp)|
418                                        *output_ijkl += self_mnop*tensor_rank_2_a_mi*tensor_rank_2_b_nj*tensor_rank_2_c_ok*tensor_rank_2_dp
419                                    )
420                                )
421                            )
422                        )
423                    )
424                )
425            )
426        );
427        output
428    }
429}
430
431pub trait ContractFirstThirdFourthIndicesWithFirstIndicesOf<TIM, TKO, TLP> {
432    type Output;
433    fn contract_first_third_fourth_indices_with_first_indices_of(
434        &self,
435        tensor_rank_2_a: TIM,
436        tensor_rank_2_c: TKO,
437        tensor_rank_2_d: TLP,
438    ) -> Self::Output;
439}
440
441impl<
442    const D: usize,
443    const I: usize,
444    const J: usize,
445    const K: usize,
446    const L: usize,
447    const M: usize,
448    const O: usize,
449    const P: usize,
450>
451    ContractFirstThirdFourthIndicesWithFirstIndicesOf<
452        &TensorRank2<D, I, M>,
453        &TensorRank2<D, K, O>,
454        &TensorRank2<D, L, P>,
455    > for TensorRank4<D, I, J, K, L>
456{
457    type Output = TensorRank4<D, M, J, O, P>;
458    fn contract_first_third_fourth_indices_with_first_indices_of(
459        &self,
460        tensor_rank_2_a: &TensorRank2<D, I, M>,
461        tensor_rank_2_b: &TensorRank2<D, K, O>,
462        tensor_rank_2_c: &TensorRank2<D, L, P>,
463    ) -> Self::Output {
464        let mut output = TensorRank4::zero();
465        self.iter().zip(tensor_rank_2_a.iter()).for_each(|(self_q, tensor_rank_2_a_q)|
466            output.iter_mut().zip(tensor_rank_2_a_q.iter()).for_each(|(output_i, tensor_rank_2_a_qi)|
467                output_i.iter_mut().zip(self_q.iter()).for_each(|(output_ij, self_qj)|
468                    self_qj.iter().zip(tensor_rank_2_b.iter()).for_each(|(self_qjm, tensor_rank_2_b_m)|
469                        self_qjm.iter().zip(tensor_rank_2_c.iter()).for_each(|(self_qjmn, tensor_rank_2_c_n)|
470                            output_ij.iter_mut().zip(tensor_rank_2_b_m.iter()).for_each(|(output_ijk, tensor_rank_2_b_mk)|
471                                output_ijk.iter_mut().zip(tensor_rank_2_c_n.iter()).for_each(|(output_ijkl, tensor_rank_2_c_nl)|
472                                    *output_ijkl += self_qjmn*tensor_rank_2_a_qi*tensor_rank_2_b_mk*tensor_rank_2_c_nl
473                                )
474                            )
475                        )
476                    )
477                )
478            )
479        );
480        output
481    }
482}
483
484pub trait ContractSecondIndexWithFirstIndexOf<TJN> {
485    type Output;
486    fn contract_second_index_with_first_index_of(&self, tensor_rank_2: TJN) -> Self::Output;
487}
488
489impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize, const N: usize>
490    ContractSecondIndexWithFirstIndexOf<&TensorRank2<D, J, N>> for TensorRank4<D, I, J, K, L>
491{
492    type Output = TensorRank4<D, I, N, K, L>;
493    fn contract_second_index_with_first_index_of(
494        &self,
495        tensor_rank_2: &TensorRank2<D, J, N>,
496    ) -> Self::Output {
497        let mut output = TensorRank4::zero();
498        output
499            .iter_mut()
500            .zip(self.iter())
501            .for_each(|(output_i, self_i)| {
502                self_i
503                    .iter()
504                    .zip(tensor_rank_2.iter())
505                    .for_each(|(self_is, tensor_rank_2_s)| {
506                        output_i.iter_mut().zip(tensor_rank_2_s.iter()).for_each(
507                            |(output_ij, tensor_rank_2_sj)| {
508                                *output_ij += self_is * tensor_rank_2_sj
509                            },
510                        )
511                    })
512            });
513        output
514    }
515}
516
517pub trait ContractSecondFourthIndicesWithFirstIndicesOf<TJ, TL> {
518    type Output;
519    fn contract_second_fourth_indices_with_first_indices_of(
520        &self,
521        object_a: TJ,
522        object_b: TL,
523    ) -> Self::Output;
524}
525
526impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
527    ContractSecondFourthIndicesWithFirstIndicesOf<&TensorRank1<D, J>, &TensorRank1<D, L>>
528    for TensorRank4<D, I, J, K, L>
529{
530    type Output = TensorRank2<D, I, K>;
531    fn contract_second_fourth_indices_with_first_indices_of(
532        &self,
533        tensor_rank_1_a: &TensorRank1<D, J>,
534        tensor_rank_1_b: &TensorRank1<D, L>,
535    ) -> Self::Output {
536        self.iter()
537            .map(|self_i| {
538                self_i
539                    .iter()
540                    .zip(tensor_rank_1_a.iter())
541                    .map(|(self_ij, tensor_rank_1_a_j)| {
542                        self_ij
543                            .iter()
544                            .map(|self_ijk| self_ijk * (tensor_rank_1_b * tensor_rank_1_a_j))
545                            .collect()
546                    })
547                    .sum()
548            })
549            .collect()
550    }
551}
552
553pub trait ContractThirdFourthIndicesWithFirstSecondIndicesOf<TKL> {
554    type Output;
555    fn contract_third_fourth_indices_with_first_second_indices_of(
556        &self,
557        tensor_rank_2: TKL,
558    ) -> Self::Output;
559}
560
561impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
562    ContractThirdFourthIndicesWithFirstSecondIndicesOf<&TensorRank2<D, K, L>>
563    for TensorRank4<D, I, J, K, L>
564{
565    type Output = TensorRank2<D, I, J>;
566    fn contract_third_fourth_indices_with_first_second_indices_of(
567        &self,
568        tensor_rank_2: &TensorRank2<D, K, L>,
569    ) -> Self::Output {
570        self.iter()
571            .map(|self_i| {
572                self_i
573                    .iter()
574                    .map(|self_ij| self_ij.full_contraction(tensor_rank_2))
575                    .collect()
576            })
577            .collect()
578    }
579}
580
581pub trait ContractFirstSecondIndicesWithSecondIndicesOf<TI, TJ> {
582    type Output;
583    fn contract_first_second_indices_with_second_indices_of(
584        &self,
585        object_a: TI,
586        object_b: TJ,
587    ) -> Self::Output;
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> ContractFirstSecondIndicesWithSecondIndicesOf<&TensorRank2<D, I, M>, &TensorRank2<D, J, N>>
599    for TensorRank4<D, M, N, K, L>
600{
601    type Output = TensorRank4<D, I, J, K, L>;
602    fn contract_first_second_indices_with_second_indices_of(
603        &self,
604        tensor_rank_2_a: &TensorRank2<D, I, M>,
605        tensor_rank_2_b: &TensorRank2<D, J, N>,
606    ) -> Self::Output {
607        let mut output = TensorRank4::zero();
608        output
609            .iter_mut()
610            .zip(tensor_rank_2_a.iter())
611            .for_each(|(output_i, tensor_rank_2_a_i)| {
612                output_i.iter_mut().zip(tensor_rank_2_b.iter()).for_each(
613                    |(output_ij, tensor_rank_2_b_j)| {
614                        self.iter().zip(tensor_rank_2_a_i.iter()).for_each(
615                            |(self_m, tensor_rank_2_a_im)| {
616                                self_m.iter().zip(tensor_rank_2_b_j.iter()).for_each(
617                                    |(self_mn, tensor_rank_2_b_jn)| {
618                                        *output_ij +=
619                                            self_mn * tensor_rank_2_a_im * tensor_rank_2_b_jn
620                                    },
621                                )
622                            },
623                        )
624                    },
625                )
626            });
627        output
628    }
629}
630
631impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
632    Div<TensorRank0> for TensorRank4<D, I, J, K, L>
633{
634    type Output = Self;
635    fn div(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
636        self /= &tensor_rank_0;
637        self
638    }
639}
640
641impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
642    Div<TensorRank0> for &TensorRank4<D, I, J, K, L>
643{
644    type Output = TensorRank4<D, I, J, K, L>;
645    fn div(self, tensor_rank_0: TensorRank0) -> Self::Output {
646        self.iter().map(|self_i| self_i / tensor_rank_0).collect()
647    }
648}
649
650impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
651    Div<&TensorRank0> for TensorRank4<D, I, J, K, L>
652{
653    type Output = Self;
654    fn div(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
655        self /= tensor_rank_0;
656        self
657    }
658}
659
660impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
661    DivAssign<TensorRank0> for TensorRank4<D, I, J, K, L>
662{
663    fn div_assign(&mut self, tensor_rank_0: TensorRank0) {
664        self.iter_mut().for_each(|self_i| *self_i /= &tensor_rank_0);
665    }
666}
667
668impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
669    DivAssign<&TensorRank0> for TensorRank4<D, I, J, K, L>
670{
671    fn div_assign(&mut self, tensor_rank_0: &TensorRank0) {
672        self.iter_mut().for_each(|self_i| *self_i /= tensor_rank_0);
673    }
674}
675
676impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
677    Mul<TensorRank0> for TensorRank4<D, I, J, K, L>
678{
679    type Output = Self;
680    fn mul(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
681        self *= &tensor_rank_0;
682        self
683    }
684}
685
686impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
687    Mul<&TensorRank0> for TensorRank4<D, I, J, K, L>
688{
689    type Output = Self;
690    fn mul(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
691        self *= tensor_rank_0;
692        self
693    }
694}
695
696impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
697    MulAssign<TensorRank0> for TensorRank4<D, I, J, K, L>
698{
699    fn mul_assign(&mut self, tensor_rank_0: TensorRank0) {
700        self.iter_mut().for_each(|self_i| *self_i *= &tensor_rank_0);
701    }
702}
703
704impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
705    MulAssign<&TensorRank0> for TensorRank4<D, I, J, K, L>
706{
707    fn mul_assign(&mut self, tensor_rank_0: &TensorRank0) {
708        self.iter_mut().for_each(|self_i| *self_i *= tensor_rank_0);
709    }
710}
711
712impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize, const M: usize>
713    Mul<TensorRank2<D, L, M>> for TensorRank4<D, I, J, K, L>
714{
715    type Output = TensorRank4<D, I, J, K, M>;
716    fn mul(self, tensor_rank_2: TensorRank2<D, L, M>) -> Self::Output {
717        self.iter()
718            .map(|self_i| {
719                self_i
720                    .iter()
721                    .map(|self_ij| self_ij * &tensor_rank_2)
722                    .collect()
723            })
724            .collect()
725    }
726}
727
728impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize, const M: usize>
729    Mul<&TensorRank2<D, L, M>> for TensorRank4<D, I, J, K, L>
730{
731    type Output = TensorRank4<D, I, J, K, M>;
732    fn mul(self, tensor_rank_2: &TensorRank2<D, L, M>) -> Self::Output {
733        self.iter()
734            .map(|self_i| {
735                self_i
736                    .iter()
737                    .map(|self_ij| self_ij * tensor_rank_2)
738                    .collect()
739            })
740            .collect()
741    }
742}
743
744impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Add
745    for TensorRank4<D, I, J, K, L>
746{
747    type Output = Self;
748    fn add(mut self, tensor_rank_4: Self) -> Self::Output {
749        self += tensor_rank_4;
750        self
751    }
752}
753
754impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Add<&Self>
755    for TensorRank4<D, I, J, K, L>
756{
757    type Output = Self;
758    fn add(mut self, tensor_rank_4: &Self) -> Self::Output {
759        self += tensor_rank_4;
760        self
761    }
762}
763
764impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
765    Add<TensorRank4<D, I, J, K, L>> for &TensorRank4<D, I, J, K, L>
766{
767    type Output = TensorRank4<D, I, J, K, L>;
768    fn add(self, mut tensor_rank_4: TensorRank4<D, I, J, K, L>) -> Self::Output {
769        tensor_rank_4 += self;
770        tensor_rank_4
771    }
772}
773
774impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> AddAssign
775    for TensorRank4<D, I, J, K, L>
776{
777    fn add_assign(&mut self, tensor_rank_4: Self) {
778        self.iter_mut()
779            .zip(tensor_rank_4.iter())
780            .for_each(|(self_i, tensor_rank_4_i)| *self_i += tensor_rank_4_i);
781    }
782}
783
784impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize>
785    AddAssign<&Self> for TensorRank4<D, I, J, K, L>
786{
787    fn add_assign(&mut self, tensor_rank_4: &Self) {
788        self.iter_mut()
789            .zip(tensor_rank_4.iter())
790            .for_each(|(self_i, tensor_rank_4_i)| *self_i += tensor_rank_4_i);
791    }
792}
793
794impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Sub
795    for TensorRank4<D, I, J, K, L>
796{
797    type Output = Self;
798    fn sub(mut self, tensor_rank_4: Self) -> Self::Output {
799        self -= tensor_rank_4;
800        self
801    }
802}
803
804impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> Sub<&Self>
805    for TensorRank4<D, I, J, K, L>
806{
807    type Output = Self;
808    fn sub(mut self, tensor_rank_4: &Self) -> Self::Output {
809        self -= tensor_rank_4;
810        self
811    }
812}
813
814impl<const D: usize, const I: usize, const J: usize, const K: usize, const L: usize> SubAssign
815    for TensorRank4<D, I, J, K, L>
816{
817    fn sub_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>
825    SubAssign<&Self> for TensorRank4<D, I, J, K, L>
826{
827    fn sub_assign(&mut self, tensor_rank_4: &Self) {
828        self.iter_mut()
829            .zip(tensor_rank_4.iter())
830            .for_each(|(self_i, tensor_rank_4_i)| *self_i -= tensor_rank_4_i);
831    }
832}