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