1#[cfg(test)]
2mod test;
3use super::rank_2::relabel as relabel_rank_2;
4use super::rank_3::relabel as relabel_rank_3;
5use crate::math::Quantity;
6use crate::math::{Current, Intermediate, Reference};
7use crate::units::{Dimensionless, UnitDiv, UnitMul};
8
9use crate::math::assert::FiniteDifference;
10
11use std::{
12 array::from_fn,
13 fmt::{self, Debug, Display, Formatter},
14 iter::Sum,
15 marker::PhantomData,
16 mem::transmute,
17 ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
18};
19
20use super::{
21 Differentiable, Erase, Hessian, HessianBlock, Rank2, SquareMatrix, Tensor, TensorArray, Vector,
22 rank_0::TensorRank0,
23 rank_1::TensorRank1,
24 rank_2::TensorRank2,
25 rank_3::{TensorRank3, get_identity_1010_parts},
26};
27
28pub(crate) mod list;
29pub(crate) mod vec;
30
31impl<const D: usize, I, J, K, L, U> HessianBlock for TensorRank4<D, I, J, K, L, U> {
32 fn entry(&self, row: usize, column: usize) -> TensorRank0 {
33 self[row / D][row % D][column / D][column % D].value()
34 }
35 fn height(&self) -> usize {
36 D * D
37 }
38 fn width(&self) -> usize {
39 D * D
40 }
41 fn fill_into_block<M>(&self, matrix: &mut M, row: usize, column: usize)
42 where
43 M: IndexMut<usize, Output = Vector>,
44 {
45 self.iter().enumerate().for_each(|(i, self_i)| {
46 self_i.iter().enumerate().for_each(|(j, self_ij)| {
47 let matrix_row = &mut matrix[row + D * i + j];
48 self_ij.iter().enumerate().for_each(|(k, self_ijk)| {
49 self_ijk.iter().enumerate().for_each(|(l, self_ijkl)| {
50 matrix_row[column + D * k + l] = self_ijkl.value()
51 })
52 })
53 })
54 })
55 }
56}
57
58#[repr(transparent)]
62pub struct TensorRank4<const D: usize, I, J, K, L, U = Dimensionless>(
63 [TensorRank3<D, J, K, L, U>; D],
64 pub(super) PhantomData<I>,
65);
66
67impl<const D: usize, I, J, K, L, U> Clone for TensorRank4<D, I, J, K, L, U> {
68 fn clone(&self) -> Self {
69 Self(self.0.clone(), PhantomData)
70 }
71}
72
73impl<const D: usize, I, J, K, L, U> Debug for TensorRank4<D, I, J, K, L, U> {
74 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
75 self.0.fmt(f)
76 }
77}
78
79impl<const D: usize, I, J, K, L, U> PartialEq for TensorRank4<D, I, J, K, L, U> {
80 fn eq(&self, other: &Self) -> bool {
81 self.0 == other.0
82 }
83}
84
85impl<const D: usize, I, J, K, L, U> TensorRank4<D, I, J, K, L, U> {
86 pub fn with_unit<V>(self) -> TensorRank4<D, I, J, K, L, V> {
87 relabel(self.into_canonical())
88 }
89 fn canonical(
90 &self,
91 ) -> &TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless> {
92 unsafe {
93 &*(self as *const Self
94 as *const TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>)
95 }
96 }
97 fn canonical_mut(
98 &mut self,
99 ) -> &mut TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless> {
100 unsafe {
101 &mut *(self as *mut Self
102 as *mut TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>)
103 }
104 }
105 fn into_canonical(
106 self,
107 ) -> TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless> {
108 unsafe {
109 (&self as *const Self)
110 .cast::<TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>>()
111 .read()
112 }
113 }
114}
115
116fn relabel<const D: usize, I, J, K, L, U>(
117 tensor: TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>,
118) -> TensorRank4<D, I, J, K, L, U> {
119 unsafe {
120 (&tensor
121 as *const TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>)
122 .cast::<TensorRank4<D, I, J, K, L, U>>()
123 .read()
124 }
125}
126
127impl<I, J, K, L, U> TensorRank4<3, I, J, K, L, U> {
128 pub const fn flatten(&self) -> [TensorRank0; 81] {
130 let mut array = [0.0; 81];
131 let mut i = 0;
132 while i < 3 {
133 let mut j = 0;
134 while j < 3 {
135 let mut k = 0;
136 while k < 3 {
137 let mut l = 0;
138 while l < 3 {
139 array[27 * i + 9 * j + 3 * k + l] = self.0[i].0[j].0[k].0[l].value();
140 l += 1;
141 }
142 k += 1;
143 }
144 j += 1;
145 }
146 i += 1;
147 }
148 array
149 }
150 pub const fn unflatten(array: [TensorRank0; 81]) -> Self {
152 const fn nine(array: &[TensorRank0; 81], base: usize) -> [TensorRank0; 9] {
153 [
154 array[base],
155 array[base + 1],
156 array[base + 2],
157 array[base + 3],
158 array[base + 4],
159 array[base + 5],
160 array[base + 6],
161 array[base + 7],
162 array[base + 8],
163 ]
164 }
165 Self(
166 [
167 TensorRank3(
168 [
169 TensorRank2::unflatten(nine(&array, 0)),
170 TensorRank2::unflatten(nine(&array, 9)),
171 TensorRank2::unflatten(nine(&array, 18)),
172 ],
173 PhantomData,
174 ),
175 TensorRank3(
176 [
177 TensorRank2::unflatten(nine(&array, 27)),
178 TensorRank2::unflatten(nine(&array, 36)),
179 TensorRank2::unflatten(nine(&array, 45)),
180 ],
181 PhantomData,
182 ),
183 TensorRank3(
184 [
185 TensorRank2::unflatten(nine(&array, 54)),
186 TensorRank2::unflatten(nine(&array, 63)),
187 TensorRank2::unflatten(nine(&array, 72)),
188 ],
189 PhantomData,
190 ),
191 ],
192 PhantomData,
193 )
194 }
195}
196
197impl<const D: usize> TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless> {
198 fn as_array_core(&self) -> [[[[TensorRank0; D]; D]; D]; D] {
199 let mut array = [[[[0.0; D]; D]; D]; D];
200 array
201 .iter_mut()
202 .zip(self.iter())
203 .for_each(|(entry_rank_3, tensor_rank_3)| *entry_rank_3 = tensor_rank_3.as_array());
204 array
205 }
206 fn zero_core() -> Self {
207 Self(from_fn(|_| TensorRank3::zero()), PhantomData)
208 }
209 fn add_assign_core(&mut self, tensor: Self) {
210 self.iter_mut()
211 .zip(tensor)
212 .for_each(|(self_i, tensor_i)| *self_i += tensor_i);
213 }
214 fn add_assign_ref_core(&mut self, tensor: &Self) {
215 self.iter_mut()
216 .zip(tensor.iter())
217 .for_each(|(self_i, tensor_i)| *self_i += tensor_i);
218 }
219 fn sub_assign_core(&mut self, tensor: Self) {
220 self.iter_mut()
221 .zip(tensor)
222 .for_each(|(self_i, tensor_i)| *self_i -= tensor_i);
223 }
224 fn sub_assign_ref_core(&mut self, tensor: &Self) {
225 self.iter_mut()
226 .zip(tensor.iter())
227 .for_each(|(self_i, tensor_i)| *self_i -= tensor_i);
228 }
229}
230
231impl<const D: usize, I, J, K, L, U> Default for TensorRank4<D, I, J, K, L, U> {
232 fn default() -> Self {
233 Self::zero()
234 }
235}
236
237impl<const D: usize, I, J, K, L, U> From<[[[[TensorRank0; D]; D]; D]; D]>
238 for TensorRank4<D, I, J, K, L, U>
239{
240 fn from(array: [[[[TensorRank0; D]; D]; D]; D]) -> Self {
241 array.into_iter().map(|entry| entry.into()).collect()
242 }
243}
244
245pub const IDENTITY_1010: TensorRank4<3, Current, Reference, Current, Reference, Dimensionless> =
247 TensorRank4(get_identity_1010_parts(), PhantomData);
248
249impl<I, J, K, U> From<TensorRank4<3, I, J, K, Reference, U>>
250 for TensorRank4<3, I, J, K, Intermediate, U>
251{
252 fn from(tensor_rank_4: TensorRank4<3, I, J, K, Reference, U>) -> Self {
253 unsafe {
254 transmute::<
255 TensorRank4<3, I, J, K, Reference, U>,
256 TensorRank4<3, I, J, K, Intermediate, U>,
257 >(tensor_rank_4)
258 }
259 }
260}
261
262impl<J, L, U> From<TensorRank4<3, Current, J, Current, L, U>>
263 for TensorRank4<3, Intermediate, J, Intermediate, L, U>
264{
265 fn from(tensor_rank_4: TensorRank4<3, Current, J, Current, L, U>) -> Self {
266 unsafe {
267 transmute::<
268 TensorRank4<3, Current, J, Current, L, U>,
269 TensorRank4<3, Intermediate, J, Intermediate, L, U>,
270 >(tensor_rank_4)
271 }
272 }
273}
274
275impl<I, K, U> From<TensorRank4<3, I, Reference, K, Reference, U>>
276 for TensorRank4<3, I, Intermediate, K, Intermediate, U>
277{
278 fn from(tensor_rank_4: TensorRank4<3, I, Reference, K, Reference, U>) -> Self {
279 unsafe {
280 transmute::<
281 TensorRank4<3, I, Reference, K, Reference, U>,
282 TensorRank4<3, I, Intermediate, K, Intermediate, U>,
283 >(tensor_rank_4)
284 }
285 }
286}
287
288impl<K, U> From<TensorRank4<3, Reference, Reference, K, Reference, U>>
289 for TensorRank4<3, Intermediate, Intermediate, K, Intermediate, U>
290{
291 fn from(tensor_rank_4: TensorRank4<3, Reference, Reference, K, Reference, U>) -> Self {
292 unsafe {
293 transmute::<
294 TensorRank4<3, Reference, Reference, K, Reference, U>,
295 TensorRank4<3, Intermediate, Intermediate, K, Intermediate, U>,
296 >(tensor_rank_4)
297 }
298 }
299}
300
301impl<const D: usize, I, J, K, L, U> From<Vec<Vec<Vec<Vec<TensorRank0>>>>>
302 for TensorRank4<D, I, J, K, L, U>
303{
304 fn from(vec_rank_4: Vec<Vec<Vec<Vec<TensorRank0>>>>) -> Self {
305 vec_rank_4
306 .into_iter()
307 .map(|vec_rank_3| {
308 vec_rank_3
309 .into_iter()
310 .map(|vec_rank_2| {
311 vec_rank_2
312 .into_iter()
313 .map(|vec_rank_1| vec_rank_1.into_iter().collect())
314 .collect()
315 })
316 .collect()
317 })
318 .collect()
319 }
320}
321
322impl<const D: usize, I, J, K, L, U> From<TensorRank4<D, I, J, K, L, U>>
323 for Vec<Vec<Vec<Vec<TensorRank0>>>>
324{
325 fn from(tensor_rank_4: TensorRank4<D, I, J, K, L, U>) -> Self {
326 tensor_rank_4
327 .iter()
328 .map(|tensor_rank_3| {
329 tensor_rank_3
330 .iter()
331 .map(|tensor_rank_2| {
332 tensor_rank_2
333 .iter()
334 .map(|tensor_rank_1| {
335 tensor_rank_1.iter().map(|entry| entry.value()).collect()
336 })
337 .collect()
338 })
339 .collect()
340 })
341 .collect()
342 }
343}
344
345impl<const D: usize, I, J, K, L, U> From<TensorRank4<D, I, J, K, L, U>> for Vec<TensorRank0> {
346 fn from(tensor_rank_4: TensorRank4<D, I, J, K, L, U>) -> Self {
347 tensor_rank_4
348 .iter()
349 .flat_map(|tensor_rank_3| {
350 tensor_rank_3.iter().flat_map(|tensor_rank_2| {
351 tensor_rank_2
352 .iter()
353 .flat_map(|tensor_rank_1| tensor_rank_1.iter().map(|entry| entry.value()))
354 })
355 })
356 .collect()
357 }
358}
359
360impl<const D: usize, I, J, K, L, U> From<TensorRank4<D, I, J, K, L, U>> for Vector {
361 fn from(tensor_rank_4: TensorRank4<D, I, J, K, L, U>) -> Self {
362 tensor_rank_4
363 .iter()
364 .flat_map(|tensor_rank_3| {
365 tensor_rank_3.iter().flat_map(|tensor_rank_2| {
366 tensor_rank_2
367 .iter()
368 .flat_map(|tensor_rank_1| tensor_rank_1.iter().map(|entry| entry.value()))
369 })
370 })
371 .collect()
372 }
373}
374
375impl<const D: usize, I, J, K, L, U> Display for TensorRank4<D, I, J, K, L, U> {
376 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
377 write!(f, "[")?;
378 self.iter()
379 .enumerate()
380 .try_for_each(|(i, entry)| write!(f, "{entry},\n\x1B[u\x1B[{}B\x1B[2D", i + 1))?;
381 write!(f, "\x1B[u\x1B[1A\x1B[{}C]", 16 * D + 2)
382 }
383}
384
385impl<const D: usize, I, J, K, L, U> FiniteDifference for TensorRank4<D, I, J, K, L, U> {
386 fn error_fd(&self, comparator: &Self, epsilon: TensorRank0) -> Option<(bool, usize)> {
387 let error_count = self
388 .iter()
389 .zip(comparator.iter())
390 .map(|(self_i, comparator_i)| {
391 self_i
392 .iter()
393 .zip(comparator_i.iter())
394 .map(|(self_ij, comparator_ij)| {
395 self_ij
396 .iter()
397 .zip(comparator_ij.iter())
398 .map(|(self_ijk, comparator_ijk)| {
399 self_ijk
400 .iter()
401 .zip(comparator_ijk.iter())
402 .filter(|&(&self_ijkl, &comparator_ijkl)| {
403 self_ijkl.differs(comparator_ijkl, epsilon)
404 })
405 .count()
406 })
407 .sum::<usize>()
408 })
409 .sum::<usize>()
410 })
411 .sum();
412 if error_count > 0 {
413 let auxiliary = self
414 .iter()
415 .zip(comparator.iter())
416 .map(|(self_i, comparator_i)| {
417 self_i
418 .iter()
419 .zip(comparator_i.iter())
420 .map(|(self_ij, comparator_ij)| {
421 self_ij
422 .iter()
423 .zip(comparator_ij.iter())
424 .map(|(self_ijk, comparator_ijk)| {
425 self_ijk
426 .iter()
427 .zip(comparator_ijk.iter())
428 .filter(|&(&self_ijkl, &comparator_ijkl)| {
429 self_ijkl.differs_severely(comparator_ijkl, epsilon)
430 })
431 .count()
432 })
433 .sum::<usize>()
434 })
435 .sum::<usize>()
436 })
437 .sum::<usize>()
438 > 0;
439 Some((auxiliary, error_count))
440 } else {
441 None
442 }
443 }
444}
445
446impl<const D: usize, I, J, K, L, U> TensorRank4<D, I, J, K, L, U> {
447 pub fn dyad_ij_kl<U1, U2>(
448 tensor_rank_2_a: &TensorRank2<D, I, J, U1>,
449 tensor_rank_2_b: &TensorRank2<D, K, L, U2>,
450 ) -> Self
451 where
452 U1: UnitMul<U2, Output = U>,
453 {
454 relabel(canonical_dyad_ij_kl(
455 tensor_rank_2_a.canonical(),
456 tensor_rank_2_b.canonical(),
457 ))
458 }
459 pub fn dyad_ik_jl<U1, U2>(
460 tensor_rank_2_a: &TensorRank2<D, I, K, U1>,
461 tensor_rank_2_b: &TensorRank2<D, J, L, U2>,
462 ) -> Self
463 where
464 U1: UnitMul<U2, Output = U>,
465 {
466 relabel(canonical_dyad_ik_jl(
467 tensor_rank_2_a.canonical(),
468 tensor_rank_2_b.canonical(),
469 ))
470 }
471 pub fn dyad_il_jk<U1, U2>(
472 tensor_rank_2_a: &TensorRank2<D, I, L, U1>,
473 tensor_rank_2_b: &TensorRank2<D, J, K, U2>,
474 ) -> Self
475 where
476 U1: UnitMul<U2, Output = U>,
477 {
478 relabel(canonical_dyad_il_jk(
479 tensor_rank_2_a.canonical(),
480 tensor_rank_2_b.canonical(),
481 ))
482 }
483 pub fn dyad_il_kj<U1, U2>(
484 tensor_rank_2_a: &TensorRank2<D, I, L, U1>,
485 tensor_rank_2_b: &TensorRank2<D, K, J, U2>,
486 ) -> Self
487 where
488 U1: UnitMul<U2, Output = U>,
489 {
490 Self::dyad_il_jk(tensor_rank_2_a, &(tensor_rank_2_b.transpose()))
491 }
492}
493
494impl<const D: usize, I, J, K, L, U> Hessian for TensorRank4<D, I, J, K, L, U> {
495 fn entry(&self, row: usize, column: usize) -> TensorRank0 {
496 self[row / D][row % D][column / D][column % D].value()
497 }
498 fn quadratic_form(&self, vector: &Vector) -> TensorRank0 {
499 self.iter()
500 .enumerate()
501 .map(|(i, self_i)| {
502 self_i
503 .iter()
504 .enumerate()
505 .map(|(j, self_ij)| {
506 vector[D * i + j]
507 * self_ij
508 .iter()
509 .enumerate()
510 .map(|(k, self_ijk)| {
511 self_ijk
512 .iter()
513 .enumerate()
514 .map(|(l, self_ijkl)| self_ijkl.value() * vector[D * k + l])
515 .sum::<TensorRank0>()
516 })
517 .sum::<TensorRank0>()
518 })
519 .sum::<TensorRank0>()
520 })
521 .sum()
522 }
523 fn fill_into(self, square_matrix: &mut SquareMatrix) {
524 self.into_iter().enumerate().for_each(|(i, self_i)| {
525 self_i.into_iter().enumerate().for_each(|(j, self_ij)| {
526 self_ij.into_iter().enumerate().for_each(|(k, self_ijk)| {
527 self_ijk.into_iter().enumerate().for_each(|(l, self_ijkl)| {
528 square_matrix[D * i + j][D * k + l] = self_ijkl.value()
529 })
530 })
531 })
532 })
533 }
534 fn retain_from(self, retained: &[bool]) -> SquareMatrix {
535 (0..D * D)
536 .filter(|&row| retained[row])
537 .map(|row| {
538 (0..D * D)
539 .filter(|&column| retained[column])
540 .map(|column| self[row / D][row % D][column / D][column % D].value())
541 .collect()
542 })
543 .collect()
544 }
545}
546
547impl<const D: usize, I, J, K, L, U> Erase for TensorRank4<D, I, J, K, L, U> {
548 type Erased = TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>;
549 fn erase(&self) -> &Self::Erased {
550 self.canonical()
551 }
552}
553
554impl<const D: usize, I, J, K, L, U> Tensor for TensorRank4<D, I, J, K, L, U> {
555 type Item = TensorRank3<D, J, K, L, U>;
556 type Unit = U;
557 fn iter(&self) -> impl Iterator<Item = &Self::Item> {
558 self.0.iter()
559 }
560 fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item> {
561 self.0.iter_mut()
562 }
563 fn len(&self) -> usize {
564 D
565 }
566 fn size(&self) -> usize {
567 D * D * D * D
568 }
569}
570
571impl<const D: usize, I, J, K, L, U> IntoIterator for TensorRank4<D, I, J, K, L, U> {
572 type Item = TensorRank3<D, J, K, L, U>;
573 type IntoIter = std::array::IntoIter<Self::Item, D>;
574 fn into_iter(self) -> Self::IntoIter {
575 self.0.into_iter()
576 }
577}
578
579impl<const D: usize, I, J, K, L, U> TensorArray for TensorRank4<D, I, J, K, L, U> {
580 type Array = [[[[TensorRank0; D]; D]; D]; D];
581 type Item = TensorRank3<D, J, K, L, U>;
582 fn as_array(&self) -> Self::Array {
583 self.canonical().as_array_core()
584 }
585 fn identity() -> Self {
586 relabel(canonical_dyad_ij_kl(
587 &TensorRank2::identity(),
588 &TensorRank2::identity(),
589 ))
590 }
591 fn zero() -> Self {
592 relabel(TensorRank4::<
593 D,
594 Reference,
595 Reference,
596 Reference,
597 Reference,
598 Dimensionless,
599 >::zero_core())
600 }
601}
602
603impl<const D: usize, I, J, K, L, U> FromIterator<TensorRank3<D, J, K, L, U>>
604 for TensorRank4<D, I, J, K, L, U>
605{
606 fn from_iter<Ii: IntoIterator<Item = TensorRank3<D, J, K, L, U>>>(into_iterator: Ii) -> Self {
607 let mut tensor_rank_4 = Self::zero();
608 tensor_rank_4
609 .iter_mut()
610 .zip(into_iterator)
611 .for_each(|(tensor_rank_4_i, value_i)| *tensor_rank_4_i = value_i);
612 tensor_rank_4
613 }
614}
615
616impl<const D: usize, I, J, K, L, U> Index<usize> for TensorRank4<D, I, J, K, L, U> {
617 type Output = TensorRank3<D, J, K, L, U>;
618 fn index(&self, index: usize) -> &Self::Output {
619 &self.0[index]
620 }
621}
622
623impl<const D: usize, I, J, K, L, U> IndexMut<usize> for TensorRank4<D, I, J, K, L, U> {
624 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
625 &mut self.0[index]
626 }
627}
628
629impl<const D: usize, I, J, K, L, U> Sum for TensorRank4<D, I, J, K, L, U> {
630 fn sum<Ii>(iter: Ii) -> Self
631 where
632 Ii: Iterator<Item = Self>,
633 {
634 iter.reduce(|mut acc, item| {
635 acc += item;
636 acc
637 })
638 .unwrap_or_else(Self::default)
639 }
640}
641
642impl<'a, const D: usize, I, J, K, L, U> Sum<&'a Self> for TensorRank4<D, I, J, K, L, U> {
643 fn sum<Ii>(iter: Ii) -> Self
644 where
645 Ii: Iterator<Item = &'a Self>,
646 {
647 iter.fold(Self::default(), |mut acc, item| {
648 acc += item;
649 acc
650 })
651 }
652}
653
654pub trait ContractAllWithFirst<TIM, TJN, TKO, TLP> {
658 type Output;
659 fn contract_all_with_first(
660 self,
661 object_a: TIM,
662 object_b: TJN,
663 object_c: TKO,
664 object_d: TLP,
665 ) -> Self::Output;
666}
667
668impl<const D: usize, I, J, K, L, M, N, O, P, U>
669 ContractAllWithFirst<
670 &TensorRank2<D, I, M, Dimensionless>,
671 &TensorRank2<D, J, N, Dimensionless>,
672 &TensorRank2<D, K, O, Dimensionless>,
673 &TensorRank2<D, L, P, Dimensionless>,
674 > for TensorRank4<D, I, J, K, L, U>
675{
676 type Output = TensorRank4<D, M, N, O, P, U>;
677 fn contract_all_with_first(
678 self,
679 tensor_rank_2_a: &TensorRank2<D, I, M, Dimensionless>,
680 tensor_rank_2_b: &TensorRank2<D, J, N, Dimensionless>,
681 tensor_rank_2_c: &TensorRank2<D, K, O, Dimensionless>,
682 tensor_rank_2_d: &TensorRank2<D, L, P, Dimensionless>,
683 ) -> Self::Output {
684 let first = canonical_transform_first(self.canonical(), tensor_rank_2_a.canonical());
685 let second = canonical_contract_second_with_first(&first, tensor_rank_2_b.canonical());
686 let third = canonical_contract_third_with_first(&second, tensor_rank_2_c.canonical());
687 relabel(canonical_transform_fourth(
688 &third,
689 tensor_rank_2_d.canonical(),
690 ))
691 }
692}
693
694pub trait ContractFirstThirdFourthWithFirst<TIM, TKO, TLP> {
695 type Output;
696 fn contract_first_third_fourth_with_first(
697 self,
698 object_a: TIM,
699 object_b: TKO,
700 object_c: TLP,
701 ) -> Self::Output;
702}
703
704impl<const D: usize, I, J, K, L, M, O, P, U>
705 ContractFirstThirdFourthWithFirst<
706 &TensorRank2<D, I, M, Dimensionless>,
707 &TensorRank2<D, K, O, Dimensionless>,
708 &TensorRank2<D, L, P, Dimensionless>,
709 > for TensorRank4<D, I, J, K, L, U>
710{
711 type Output = TensorRank4<D, M, J, O, P, U>;
712 fn contract_first_third_fourth_with_first(
713 self,
714 tensor_rank_2_a: &TensorRank2<D, I, M, Dimensionless>,
715 tensor_rank_2_b: &TensorRank2<D, K, O, Dimensionless>,
716 tensor_rank_2_c: &TensorRank2<D, L, P, Dimensionless>,
717 ) -> Self::Output {
718 let first = canonical_transform_first(self.canonical(), tensor_rank_2_a.canonical());
719 let third = canonical_contract_third_with_first(&first, tensor_rank_2_b.canonical());
720 relabel(canonical_transform_fourth(
721 &third,
722 tensor_rank_2_c.canonical(),
723 ))
724 }
725}
726
727pub trait ContractSecondWithFirst<TJN> {
728 type Output;
729 fn contract_second_with_first(self, tensor_rank_2: TJN) -> Self::Output;
730}
731
732impl<const D: usize, I, J, K, L, N, U> ContractSecondWithFirst<&TensorRank2<D, J, N, Dimensionless>>
733 for TensorRank4<D, I, J, K, L, U>
734{
735 type Output = TensorRank4<D, I, N, K, L, U>;
736 fn contract_second_with_first(
737 self,
738 tensor_rank_2: &TensorRank2<D, J, N, Dimensionless>,
739 ) -> Self::Output {
740 relabel(canonical_contract_second_with_first(
741 self.canonical(),
742 tensor_rank_2.canonical(),
743 ))
744 }
745}
746
747pub trait ContractSecondFourthWithFirst<TJ, TL> {
748 type Output;
749 fn contract_second_fourth_with_first(&self, object_a: TJ, object_b: TL) -> Self::Output;
750}
751
752impl<const D: usize, I, J, K, L, U, V, W>
753 ContractSecondFourthWithFirst<&TensorRank1<D, J, V>, &TensorRank1<D, L, W>>
754 for TensorRank4<D, I, J, K, L, U>
755where
756 U: UnitMul<V>,
757 <U as UnitMul<V>>::Output: UnitMul<W>,
758{
759 type Output = TensorRank2<D, I, K, <<U as UnitMul<V>>::Output as UnitMul<W>>::Output>;
760 fn contract_second_fourth_with_first(
761 &self,
762 tensor_rank_1_a: &TensorRank1<D, J, V>,
763 tensor_rank_1_b: &TensorRank1<D, L, W>,
764 ) -> Self::Output {
765 relabel_rank_2(canonical_contract_second_fourth_with_first(
766 self.canonical(),
767 tensor_rank_1_a.canonical(),
768 tensor_rank_1_b.canonical(),
769 ))
770 }
771}
772
773fn canonical_contract_second_fourth_with_first<const D: usize>(
774 tensor_rank_4: &TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>,
775 tensor_rank_1_a: &TensorRank1<D, Reference, Dimensionless>,
776 tensor_rank_1_b: &TensorRank1<D, Reference, Dimensionless>,
777) -> TensorRank2<D, Reference, Reference, Dimensionless> {
778 let mut output = TensorRank2::zero();
779 tensor_rank_4
780 .iter()
781 .zip(output.iter_mut())
782 .for_each(|(tensor_rank_4_i, output_i)| {
783 tensor_rank_4_i.iter().zip(tensor_rank_1_a.iter()).for_each(
784 |(tensor_rank_4_ij, tensor_rank_1_a_j)| {
785 tensor_rank_4_ij.iter().zip(output_i.iter_mut()).for_each(
786 |(tensor_rank_4_ijk, output_ik)| {
787 *output_ik += (tensor_rank_4_ijk * tensor_rank_1_b) * tensor_rank_1_a_j
788 },
789 )
790 },
791 )
792 });
793 output
794}
795
796pub trait ContractThirdWithFirst<TKL> {
797 type Output;
798 fn contract_third_with_first(&self, tensor: TKL) -> Self::Output;
799}
800
801impl<const D: usize, I, J, K, L, M, U> ContractThirdWithFirst<&TensorRank2<D, M, K, Dimensionless>>
802 for TensorRank4<D, I, J, M, L, U>
803{
804 type Output = TensorRank4<D, I, J, K, L, U>;
805 fn contract_third_with_first(
806 &self,
807 tensor_rank_2: &TensorRank2<D, M, K, Dimensionless>,
808 ) -> Self::Output {
809 relabel(canonical_contract_third_with_first(
810 self.canonical(),
811 tensor_rank_2.canonical(),
812 ))
813 }
814}
815
816pub trait ContractThirdFourthWithFirstSecond<TKL> {
817 type Output;
818 fn contract_third_fourth_with_first_second(self, tensor: TKL) -> Self::Output;
819}
820
821impl<const D: usize, I, J, K, L, U, V> ContractThirdFourthWithFirstSecond<&TensorRank2<D, K, L, V>>
822 for TensorRank4<D, I, J, K, L, U>
823where
824 U: UnitMul<V>,
825{
826 type Output = TensorRank2<D, I, J, <U as UnitMul<V>>::Output>;
827 fn contract_third_fourth_with_first_second(
828 self,
829 tensor_rank_2: &TensorRank2<D, K, L, V>,
830 ) -> Self::Output {
831 (&self).contract_third_fourth_with_first_second(tensor_rank_2)
832 }
833}
834
835impl<const D: usize, I, J, K, L, U, V> ContractThirdFourthWithFirstSecond<&TensorRank2<D, K, L, V>>
836 for &TensorRank4<D, I, J, K, L, U>
837where
838 U: UnitMul<V>,
839{
840 type Output = TensorRank2<D, I, J, <U as UnitMul<V>>::Output>;
841 fn contract_third_fourth_with_first_second(
842 self,
843 tensor_rank_2: &TensorRank2<D, K, L, V>,
844 ) -> Self::Output {
845 relabel_rank_2(canonical_contract_34_12_rank_2(
846 self.canonical(),
847 tensor_rank_2.canonical(),
848 ))
849 }
850}
851
852fn canonical_contract_34_12_rank_2<const D: usize>(
853 tensor_rank_4: &TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>,
854 tensor_rank_2: &TensorRank2<D, Reference, Reference, Dimensionless>,
855) -> TensorRank2<D, Reference, Reference, Dimensionless> {
856 let mut contraction = TensorRank2::zero();
857 for i in 0..D {
858 for j in 0..D {
859 let mut sum: TensorRank0 = 0.0;
860 for k in 0..D {
861 for l in 0..D {
862 sum = sum.algebraic_add(
863 tensor_rank_4[i][j][k][l]
864 .value()
865 .algebraic_mul(tensor_rank_2[k][l].value()),
866 );
867 }
868 }
869 contraction[i][j] = Quantity::new(sum);
870 }
871 }
872 contraction
873}
874
875impl<const D: usize, I, J, K, L, M, N, U, V>
876 ContractThirdFourthWithFirstSecond<&TensorRank4<D, K, L, M, N, V>>
877 for TensorRank4<D, I, J, K, L, U>
878where
879 U: UnitMul<V>,
880{
881 type Output = TensorRank4<D, I, J, M, N, <U as UnitMul<V>>::Output>;
882 fn contract_third_fourth_with_first_second(
883 self,
884 tensor: &TensorRank4<D, K, L, M, N, V>,
885 ) -> Self::Output {
886 relabel(canonical_contract_34_12_rank_4(
887 self.into_canonical(),
888 tensor.canonical(),
889 ))
890 }
891}
892
893fn canonical_contract_34_12_rank_4<const D: usize>(
894 tensor_rank_4: TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>,
895 tensor: &TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>,
896) -> TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless> {
897 tensor_rank_4
898 .into_iter()
899 .map(|self_i| {
900 self_i
901 .into_iter()
902 .map(|self_ij| {
903 self_ij
904 .into_iter()
905 .zip(tensor.iter())
906 .map(|(self_ijk, tensor_k)| {
907 self_ijk
908 .into_iter()
909 .zip(tensor_k.iter())
910 .map(|(self_ijkl, tensor_kl)| tensor_kl * self_ijkl)
911 .sum::<TensorRank2<D, Reference, Reference, Dimensionless>>()
912 })
913 .sum()
914 })
915 .collect()
916 })
917 .collect()
918}
919
920pub trait ContractFirstSecondWithSecond<TI, TJ> {
921 type Output;
922 fn contract_first_second_with_second(self, object_a: TI, object_b: TJ) -> Self::Output;
923}
924
925impl<const D: usize, I, J, K, L, M, N, U>
926 ContractFirstSecondWithSecond<
927 &TensorRank2<D, I, M, Dimensionless>,
928 &TensorRank2<D, J, N, Dimensionless>,
929 > for TensorRank4<D, M, N, K, L, U>
930{
931 type Output = TensorRank4<D, I, J, K, L, U>;
932 fn contract_first_second_with_second(
933 self,
934 tensor_rank_2_a: &TensorRank2<D, I, M, Dimensionless>,
935 tensor_rank_2_b: &TensorRank2<D, J, N, Dimensionless>,
936 ) -> Self::Output {
937 let first =
938 canonical_transform_first(self.canonical(), &tensor_rank_2_a.canonical().transpose());
939 relabel(canonical_contract_second_with_first(
940 &first,
941 &tensor_rank_2_b.canonical().transpose(),
942 ))
943 }
944}
945
946impl<const D: usize, I, J, K, L, U> Div<TensorRank0> for TensorRank4<D, I, J, K, L, U> {
947 type Output = Self;
948 fn div(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
949 self /= &tensor_rank_0;
950 self
951 }
952}
953
954impl<const D: usize, I, J, K, L, U> Div<TensorRank0> for &TensorRank4<D, I, J, K, L, U> {
955 type Output = TensorRank4<D, I, J, K, L, U>;
956 fn div(self, tensor_rank_0: TensorRank0) -> Self::Output {
957 self.iter().map(|self_i| self_i / tensor_rank_0).collect()
958 }
959}
960
961impl<const D: usize, I, J, K, L, U> Div<&TensorRank0> for TensorRank4<D, I, J, K, L, U> {
962 type Output = Self;
963 fn div(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
964 self /= tensor_rank_0;
965 self
966 }
967}
968
969impl<const D: usize, I, J, K, L, U> DivAssign<TensorRank0> for TensorRank4<D, I, J, K, L, U> {
970 fn div_assign(&mut self, tensor_rank_0: TensorRank0) {
971 self.iter_mut().for_each(|self_i| *self_i /= &tensor_rank_0);
972 }
973}
974
975impl<const D: usize, I, J, K, L, U> DivAssign<&TensorRank0> for TensorRank4<D, I, J, K, L, U> {
976 fn div_assign(&mut self, tensor_rank_0: &TensorRank0) {
977 self.iter_mut().for_each(|self_i| *self_i /= tensor_rank_0);
978 }
979}
980
981impl<const D: usize, I, J, K, L, U> Mul<TensorRank0> for TensorRank4<D, I, J, K, L, U> {
982 type Output = Self;
983 fn mul(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
984 self *= &tensor_rank_0;
985 self
986 }
987}
988
989impl<const D: usize, I, J, K, L, U> Mul<&TensorRank0> for TensorRank4<D, I, J, K, L, U> {
990 type Output = Self;
991 fn mul(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
992 self *= tensor_rank_0;
993 self
994 }
995}
996
997impl<const D: usize, I, J, K, L, U> MulAssign<TensorRank0> for TensorRank4<D, I, J, K, L, U> {
998 fn mul_assign(&mut self, tensor_rank_0: TensorRank0) {
999 self.iter_mut().for_each(|self_i| *self_i *= &tensor_rank_0);
1000 }
1001}
1002
1003impl<const D: usize, I, J, K, L, U> MulAssign<&TensorRank0> for TensorRank4<D, I, J, K, L, U> {
1004 fn mul_assign(&mut self, tensor_rank_0: &TensorRank0) {
1005 self.iter_mut().for_each(|self_i| *self_i *= tensor_rank_0);
1006 }
1007}
1008
1009impl<const D: usize, I, J, K, L, M, U, V> Mul<TensorRank2<D, L, M, V>>
1010 for TensorRank4<D, I, J, K, L, U>
1011where
1012 U: UnitMul<V>,
1013{
1014 type Output = TensorRank4<D, I, J, K, M, <U as UnitMul<V>>::Output>;
1015 fn mul(self, tensor_rank_2: TensorRank2<D, L, M, V>) -> Self::Output {
1016 self.into_iter()
1017 .map(|self_i| {
1018 self_i
1019 .into_iter()
1020 .map(|self_ij| self_ij * &tensor_rank_2)
1021 .collect()
1022 })
1023 .collect()
1024 }
1025}
1026
1027impl<const D: usize, I, J, K, L, M, U, V> Mul<&TensorRank2<D, L, M, V>>
1028 for TensorRank4<D, I, J, K, L, U>
1029where
1030 U: UnitMul<V>,
1031{
1032 type Output = TensorRank4<D, I, J, K, M, <U as UnitMul<V>>::Output>;
1033 fn mul(self, tensor_rank_2: &TensorRank2<D, L, M, V>) -> Self::Output {
1034 self.into_iter()
1035 .map(|self_i| {
1036 self_i
1037 .into_iter()
1038 .map(|self_ij| self_ij * tensor_rank_2)
1039 .collect()
1040 })
1041 .collect()
1042 }
1043}
1044
1045impl<const D: usize, J, K, L, M, U, V> Mul<TensorRank4<D, M, J, K, L, V>> for TensorRank1<D, M, U>
1046where
1047 U: UnitMul<V>,
1048{
1049 type Output = TensorRank3<D, J, K, L, <U as UnitMul<V>>::Output>;
1050 fn mul(self, tensor_rank_4: TensorRank4<D, M, J, K, L, V>) -> Self::Output {
1051 relabel_rank_3(canonical_rank_1_times_rank_4(
1052 self.canonical(),
1053 tensor_rank_4.canonical(),
1054 ))
1055 }
1056}
1057
1058impl<const D: usize, J, K, L, M, U, V> Mul<&TensorRank4<D, M, J, K, L, V>> for TensorRank1<D, M, U>
1059where
1060 U: UnitMul<V>,
1061{
1062 type Output = TensorRank3<D, J, K, L, <U as UnitMul<V>>::Output>;
1063 fn mul(self, tensor_rank_4: &TensorRank4<D, M, J, K, L, V>) -> Self::Output {
1064 relabel_rank_3(canonical_rank_1_times_rank_4(
1065 self.canonical(),
1066 tensor_rank_4.canonical(),
1067 ))
1068 }
1069}
1070
1071impl<const D: usize, J, K, L, M, U, V> Mul<TensorRank4<D, M, J, K, L, V>> for &TensorRank1<D, M, U>
1072where
1073 U: UnitMul<V>,
1074{
1075 type Output = TensorRank3<D, J, K, L, <U as UnitMul<V>>::Output>;
1076 fn mul(self, tensor_rank_4: TensorRank4<D, M, J, K, L, V>) -> Self::Output {
1077 relabel_rank_3(canonical_rank_1_times_rank_4(
1078 self.canonical(),
1079 tensor_rank_4.canonical(),
1080 ))
1081 }
1082}
1083
1084impl<const D: usize, J, K, L, M, U, V> Mul<&TensorRank4<D, M, J, K, L, V>> for &TensorRank1<D, M, U>
1085where
1086 U: UnitMul<V>,
1087{
1088 type Output = TensorRank3<D, J, K, L, <U as UnitMul<V>>::Output>;
1089 fn mul(self, tensor_rank_4: &TensorRank4<D, M, J, K, L, V>) -> Self::Output {
1090 relabel_rank_3(canonical_rank_1_times_rank_4(
1091 self.canonical(),
1092 tensor_rank_4.canonical(),
1093 ))
1094 }
1095}
1096
1097impl<const D: usize, I, J, K, L, M, U, V> Mul<TensorRank4<D, M, J, K, L, V>>
1098 for TensorRank2<D, I, M, U>
1099where
1100 U: UnitMul<V>,
1101{
1102 type Output = TensorRank4<D, I, J, K, L, <U as UnitMul<V>>::Output>;
1103 fn mul(self, tensor_rank_4: TensorRank4<D, M, J, K, L, V>) -> Self::Output {
1104 relabel(canonical_rank_2_times_rank_4(
1105 self.canonical(),
1106 tensor_rank_4.canonical(),
1107 ))
1108 }
1109}
1110
1111impl<const D: usize, I, J, K, L, M, U, V> Mul<&TensorRank4<D, M, J, K, L, V>>
1112 for TensorRank2<D, I, M, U>
1113where
1114 U: UnitMul<V>,
1115{
1116 type Output = TensorRank4<D, I, J, K, L, <U as UnitMul<V>>::Output>;
1117 fn mul(self, tensor_rank_4: &TensorRank4<D, M, J, K, L, V>) -> Self::Output {
1118 relabel(canonical_rank_2_times_rank_4(
1119 self.canonical(),
1120 tensor_rank_4.canonical(),
1121 ))
1122 }
1123}
1124
1125impl<const D: usize, I, J, K, L, M, U, V> Mul<TensorRank4<D, M, J, K, L, V>>
1126 for &TensorRank2<D, I, M, U>
1127where
1128 U: UnitMul<V>,
1129{
1130 type Output = TensorRank4<D, I, J, K, L, <U as UnitMul<V>>::Output>;
1131 fn mul(self, tensor_rank_4: TensorRank4<D, M, J, K, L, V>) -> Self::Output {
1132 relabel(canonical_rank_2_times_rank_4(
1133 self.canonical(),
1134 tensor_rank_4.canonical(),
1135 ))
1136 }
1137}
1138
1139impl<const D: usize, I, J, K, L, M, U, V> Mul<&TensorRank4<D, M, J, K, L, V>>
1140 for &TensorRank2<D, I, M, U>
1141where
1142 U: UnitMul<V>,
1143{
1144 type Output = TensorRank4<D, I, J, K, L, <U as UnitMul<V>>::Output>;
1145 fn mul(self, tensor_rank_4: &TensorRank4<D, M, J, K, L, V>) -> Self::Output {
1146 relabel(canonical_rank_2_times_rank_4(
1147 self.canonical(),
1148 tensor_rank_4.canonical(),
1149 ))
1150 }
1151}
1152
1153impl<const D: usize, I, J, K, L, U> Add for TensorRank4<D, I, J, K, L, U> {
1154 type Output = Self;
1155 fn add(mut self, tensor_rank_4: Self) -> Self::Output {
1156 self += tensor_rank_4;
1157 self
1158 }
1159}
1160
1161impl<const D: usize, I, J, K, L, U> Add<&Self> for TensorRank4<D, I, J, K, L, U> {
1162 type Output = Self;
1163 fn add(mut self, tensor_rank_4: &Self) -> Self::Output {
1164 self += tensor_rank_4;
1165 self
1166 }
1167}
1168
1169impl<const D: usize, I, J, K, L, U> Add<TensorRank4<D, I, J, K, L, U>>
1170 for &TensorRank4<D, I, J, K, L, U>
1171{
1172 type Output = TensorRank4<D, I, J, K, L, U>;
1173 fn add(self, mut tensor_rank_4: TensorRank4<D, I, J, K, L, U>) -> Self::Output {
1174 tensor_rank_4 += self;
1175 tensor_rank_4
1176 }
1177}
1178
1179impl<const D: usize, I, J, K, L, U> AddAssign for TensorRank4<D, I, J, K, L, U> {
1180 fn add_assign(&mut self, tensor_rank_4: Self) {
1181 self.canonical_mut()
1182 .add_assign_core(tensor_rank_4.into_canonical());
1183 }
1184}
1185
1186impl<const D: usize, I, J, K, L, U> AddAssign<&Self> for TensorRank4<D, I, J, K, L, U> {
1187 fn add_assign(&mut self, tensor_rank_4: &Self) {
1188 self.canonical_mut()
1189 .add_assign_ref_core(tensor_rank_4.canonical());
1190 }
1191}
1192
1193impl<const D: usize, I, J, K, L, U> Sub for TensorRank4<D, I, J, K, L, U> {
1194 type Output = Self;
1195 fn sub(mut self, tensor_rank_4: Self) -> Self::Output {
1196 self -= tensor_rank_4;
1197 self
1198 }
1199}
1200
1201impl<const D: usize, I, J, K, L, U> Sub<&Self> for TensorRank4<D, I, J, K, L, U> {
1202 type Output = Self;
1203 fn sub(mut self, tensor_rank_4: &Self) -> Self::Output {
1204 self -= tensor_rank_4;
1205 self
1206 }
1207}
1208
1209impl<const D: usize, I, J, K, L, U> Sub for &TensorRank4<D, I, J, K, L, U> {
1210 type Output = TensorRank4<D, I, J, K, L, U>;
1211 fn sub(self, tensor_rank_4: Self) -> Self::Output {
1212 tensor_rank_4
1213 .iter()
1214 .zip(self.iter())
1215 .map(|(tensor_rank_4_i, self_i)| self_i - tensor_rank_4_i)
1216 .collect()
1217 }
1218}
1219
1220impl<const D: usize, I, J, K, L, U> SubAssign for TensorRank4<D, I, J, K, L, U> {
1221 fn sub_assign(&mut self, tensor_rank_4: Self) {
1222 self.canonical_mut()
1223 .sub_assign_core(tensor_rank_4.into_canonical());
1224 }
1225}
1226
1227impl<const D: usize, I, J, K, L, U> SubAssign<&Self> for TensorRank4<D, I, J, K, L, U> {
1228 fn sub_assign(&mut self, tensor_rank_4: &Self) {
1229 self.canonical_mut()
1230 .sub_assign_ref_core(tensor_rank_4.canonical());
1231 }
1232}
1233
1234impl<const D: usize, I, J, K, L, U, V> Mul<Quantity<V>> for TensorRank4<D, I, J, K, L, U>
1235where
1236 U: UnitMul<V>,
1237{
1238 type Output = TensorRank4<D, I, J, K, L, <U as UnitMul<V>>::Output>;
1239 fn mul(self, quantity: Quantity<V>) -> Self::Output {
1240 relabel(self.into_canonical() * quantity.value())
1241 }
1242}
1243
1244impl<const D: usize, I, J, K, L, U, V> Mul<&Quantity<V>> for TensorRank4<D, I, J, K, L, U>
1245where
1246 U: UnitMul<V>,
1247{
1248 type Output = TensorRank4<D, I, J, K, L, <U as UnitMul<V>>::Output>;
1249 fn mul(self, quantity: &Quantity<V>) -> Self::Output {
1250 self * *quantity
1251 }
1252}
1253
1254impl<const D: usize, I, J, K, L, U, V> Mul<Quantity<V>> for &TensorRank4<D, I, J, K, L, U>
1255where
1256 U: UnitMul<V>,
1257{
1258 type Output = TensorRank4<D, I, J, K, L, <U as UnitMul<V>>::Output>;
1259 fn mul(self, quantity: Quantity<V>) -> Self::Output {
1260 relabel(self.canonical().clone() * quantity.value())
1261 }
1262}
1263
1264impl<const D: usize, I, J, K, L, U, V> Mul<&Quantity<V>> for &TensorRank4<D, I, J, K, L, U>
1265where
1266 U: UnitMul<V>,
1267{
1268 type Output = TensorRank4<D, I, J, K, L, <U as UnitMul<V>>::Output>;
1269 fn mul(self, quantity: &Quantity<V>) -> Self::Output {
1270 self * *quantity
1271 }
1272}
1273
1274impl<const D: usize, I, J, K, L, U, V> Div<Quantity<V>> for TensorRank4<D, I, J, K, L, U>
1275where
1276 U: UnitDiv<V>,
1277{
1278 type Output = TensorRank4<D, I, J, K, L, <U as UnitDiv<V>>::Output>;
1279 fn div(self, quantity: Quantity<V>) -> Self::Output {
1280 relabel(self.into_canonical() / quantity.value())
1281 }
1282}
1283
1284fn canonical_dyad_ij_kl<const D: usize>(
1285 tensor_rank_2_a: &TensorRank2<D, Reference, Reference, Dimensionless>,
1286 tensor_rank_2_b: &TensorRank2<D, Reference, Reference, Dimensionless>,
1287) -> TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless> {
1288 tensor_rank_2_a
1289 .iter()
1290 .map(|tensor_rank_2_a_i| {
1291 tensor_rank_2_a_i
1292 .iter()
1293 .map(|tensor_rank_2_a_ij| tensor_rank_2_b * tensor_rank_2_a_ij)
1294 .collect()
1295 })
1296 .collect()
1297}
1298
1299fn canonical_dyad_ik_jl<const D: usize>(
1300 tensor_rank_2_a: &TensorRank2<D, Reference, Reference, Dimensionless>,
1301 tensor_rank_2_b: &TensorRank2<D, Reference, Reference, Dimensionless>,
1302) -> TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless> {
1303 tensor_rank_2_a
1304 .iter()
1305 .map(|tensor_rank_2_a_i| {
1306 tensor_rank_2_b
1307 .iter()
1308 .map(|tensor_rank_2_b_j| {
1309 tensor_rank_2_a_i
1310 .iter()
1311 .map(|tensor_rank_2_a_ik| tensor_rank_2_b_j * tensor_rank_2_a_ik)
1312 .collect()
1313 })
1314 .collect()
1315 })
1316 .collect()
1317}
1318
1319fn canonical_dyad_il_jk<const D: usize>(
1320 tensor_rank_2_a: &TensorRank2<D, Reference, Reference, Dimensionless>,
1321 tensor_rank_2_b: &TensorRank2<D, Reference, Reference, Dimensionless>,
1322) -> TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless> {
1323 tensor_rank_2_a
1324 .iter()
1325 .map(|tensor_rank_2_a_i| {
1326 tensor_rank_2_b
1327 .iter()
1328 .map(|tensor_rank_2_b_j| {
1329 tensor_rank_2_b_j
1330 .iter()
1331 .map(|tensor_rank_2_b_jk| tensor_rank_2_a_i * tensor_rank_2_b_jk)
1332 .collect()
1333 })
1334 .collect()
1335 })
1336 .collect()
1337}
1338
1339fn canonical_rank_1_times_rank_4<const D: usize>(
1340 tensor_rank_1: &TensorRank1<D, Reference, Dimensionless>,
1341 tensor_rank_4: &TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>,
1342) -> TensorRank3<D, Reference, Reference, Reference, Dimensionless> {
1343 tensor_rank_1
1344 .iter()
1345 .zip(tensor_rank_4.iter())
1346 .map(|(&tensor_rank_1_m, tensor_rank_4_m)| tensor_rank_4_m * tensor_rank_1_m.value())
1347 .sum()
1348}
1349
1350fn canonical_rank_2_times_rank_4<const D: usize>(
1351 tensor_rank_2: &TensorRank2<D, Reference, Reference, Dimensionless>,
1352 tensor_rank_4: &TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>,
1353) -> TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless> {
1354 tensor_rank_2
1355 .iter()
1356 .map(|tensor_rank_2_i| tensor_rank_2_i * tensor_rank_4)
1357 .collect()
1358}
1359
1360fn canonical_contract_second_with_first<const D: usize>(
1361 tensor_rank_4: &TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>,
1362 tensor_rank_2: &TensorRank2<D, Reference, Reference, Dimensionless>,
1363) -> TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless> {
1364 let mut output = TensorRank4::zero();
1365 tensor_rank_4
1366 .iter()
1367 .zip(output.iter_mut())
1368 .for_each(|(tensor_rank_4_i, output_i)| {
1369 tensor_rank_4_i.iter().zip(tensor_rank_2.iter()).for_each(
1370 |(tensor_rank_4_is, tensor_rank_2_s)| {
1371 tensor_rank_2_s.iter().zip(output_i.iter_mut()).for_each(
1372 |(tensor_rank_2_sj, output_ij)| {
1373 output_ij.iter_mut().zip(tensor_rank_4_is.iter()).for_each(
1374 |(output_ijk, tensor_rank_4_isk)| {
1375 output_ijk
1376 .iter_mut()
1377 .zip(tensor_rank_4_isk.iter())
1378 .for_each(|(output_ijkl, tensor_rank_4_iskl)| {
1379 *output_ijkl += tensor_rank_4_iskl * tensor_rank_2_sj
1380 })
1381 },
1382 )
1383 },
1384 )
1385 },
1386 )
1387 });
1388 output
1389}
1390
1391fn canonical_contract_third_with_first<const D: usize>(
1392 tensor_rank_4: &TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>,
1393 tensor_rank_2: &TensorRank2<D, Reference, Reference, Dimensionless>,
1394) -> TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless> {
1395 let mut output = TensorRank4::zero();
1396 tensor_rank_4
1397 .iter()
1398 .zip(output.iter_mut())
1399 .for_each(|(tensor_rank_4_i, output_i)| {
1400 tensor_rank_4_i.iter().zip(output_i.iter_mut()).for_each(
1401 |(tensor_rank_4_ij, output_ij)| {
1402 tensor_rank_4_ij.iter().zip(tensor_rank_2.iter()).for_each(
1403 |(tensor_rank_4_ijm, tensor_rank_2_m)| {
1404 tensor_rank_2_m.iter().zip(output_ij.iter_mut()).for_each(
1405 |(tensor_rank_2_mk, output_ijk)| {
1406 output_ijk
1407 .iter_mut()
1408 .zip(tensor_rank_4_ijm.iter())
1409 .for_each(|(output_ijkl, tensor_rank_4_ijml)| {
1410 *output_ijkl += tensor_rank_2_mk * tensor_rank_4_ijml
1411 })
1412 },
1413 )
1414 },
1415 )
1416 },
1417 )
1418 });
1419 output
1420}
1421
1422fn canonical_transform_first<const D: usize>(
1423 tensor_rank_4: &TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>,
1424 tensor_rank_2: &TensorRank2<D, Reference, Reference, Dimensionless>,
1425) -> TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless> {
1426 let mut output = TensorRank4::zero();
1427 tensor_rank_4.iter().zip(tensor_rank_2.iter()).for_each(
1428 |(tensor_rank_4_m, tensor_rank_2_m)| {
1429 tensor_rank_2_m.iter().zip(output.iter_mut()).for_each(
1430 |(tensor_rank_2_mi, output_i)| {
1431 output_i.iter_mut().zip(tensor_rank_4_m.iter()).for_each(
1432 |(output_ij, tensor_rank_4_mj)| {
1433 output_ij.iter_mut().zip(tensor_rank_4_mj.iter()).for_each(
1434 |(output_ijk, tensor_rank_4_mjk)| {
1435 output_ijk
1436 .iter_mut()
1437 .zip(tensor_rank_4_mjk.iter())
1438 .for_each(|(output_ijkl, tensor_rank_4_mjkl)| {
1439 *output_ijkl += tensor_rank_4_mjkl * tensor_rank_2_mi
1440 })
1441 },
1442 )
1443 },
1444 )
1445 },
1446 )
1447 },
1448 );
1449 output
1450}
1451
1452fn canonical_transform_fourth<const D: usize>(
1453 tensor_rank_4: &TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless>,
1454 tensor_rank_2: &TensorRank2<D, Reference, Reference, Dimensionless>,
1455) -> TensorRank4<D, Reference, Reference, Reference, Reference, Dimensionless> {
1456 let mut output = TensorRank4::zero();
1457 tensor_rank_4
1458 .iter()
1459 .zip(output.iter_mut())
1460 .for_each(|(tensor_rank_4_i, output_i)| {
1461 tensor_rank_4_i.iter().zip(output_i.iter_mut()).for_each(
1462 |(tensor_rank_4_ij, output_ij)| {
1463 tensor_rank_4_ij.iter().zip(output_ij.iter_mut()).for_each(
1464 |(tensor_rank_4_ijk, output_ijk)| {
1465 tensor_rank_4_ijk.iter().zip(tensor_rank_2.iter()).for_each(
1466 |(tensor_rank_4_ijkm, tensor_rank_2_m)| {
1467 output_ijk.iter_mut().zip(tensor_rank_2_m.iter()).for_each(
1468 |(output_ijkl, tensor_rank_2_ml)| {
1469 *output_ijkl += tensor_rank_4_ijkm * tensor_rank_2_ml
1470 },
1471 )
1472 },
1473 )
1474 },
1475 )
1476 },
1477 )
1478 });
1479 output
1480}
1481
1482impl<const D: usize, I, J, K, L, U, T> Differentiable<T> for TensorRank4<D, I, J, K, L, U>
1483where
1484 U: UnitDiv<T>,
1485{
1486 type Derivative = TensorRank4<D, I, J, K, L, <U as UnitDiv<T>>::Output>;
1487}