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#[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}