1#[cfg(test)]
2mod test;
3use super::{ContractWith, Differentiate, Erase};
4use crate::math::{Current, Projection, Reference};
5
6pub(crate) mod cross;
7pub(crate) mod list;
8pub(crate) mod list_2d;
9pub(crate) mod vec;
10pub(crate) mod vec_2d;
11
12use std::{
13 array::from_fn,
14 fmt::{self, Debug, Display, Formatter},
15 iter::Sum,
16 marker::PhantomData,
17 ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign},
18};
19
20use crate::units::{UnitDiv, UnitMul};
21use crate::{
22 ABS_TOL,
23 math::{
24 matrix::vector::Vector,
25 tensor::{
26 Jacobian, Quantity, Solution, Tensor, TensorArray, rank_0::TensorRank0,
27 rank_1::list::TensorRank1List, rank_2::TensorRank2,
28 },
29 write_tensor_rank_0,
30 },
31 units::Dimensionless,
32};
33
34use crate::math::assert::FiniteDifference;
35
36#[repr(transparent)]
40pub struct TensorRank1<const D: usize, I, U = Dimensionless>(
41 pub(super) [Quantity<U>; D],
42 pub(super) PhantomData<I>,
43);
44
45impl<const D: usize, I, U> Clone for TensorRank1<D, I, U> {
46 fn clone(&self) -> Self {
47 Self(self.0, PhantomData)
48 }
49}
50
51impl<const D: usize, I, U> Debug for TensorRank1<D, I, U> {
52 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
53 self.0.fmt(f)
54 }
55}
56
57impl<const D: usize, I, U> PartialEq for TensorRank1<D, I, U> {
58 fn eq(&self, other: &Self) -> bool {
59 self.0 == other.0
60 }
61}
62
63impl<const D: usize, I, U> TensorRank1<D, I, U> {
64 pub(super) fn canonical(&self) -> &TensorRank1<D, Reference, Dimensionless> {
65 unsafe { &*(self as *const Self as *const TensorRank1<D, Reference, Dimensionless>) }
66 }
67 pub fn with_unit<V>(self) -> TensorRank1<D, I, V> {
69 relabel(self.into_canonical())
70 }
71 pub fn normalized(self) -> TensorRank1<D, I, Dimensionless> {
73 let norm = self.norm().value();
74 (self / norm).with_unit()
75 }
76 fn into_canonical(self) -> TensorRank1<D, Reference, Dimensionless> {
77 unsafe {
78 (&self as *const Self)
79 .cast::<TensorRank1<D, Reference, Dimensionless>>()
80 .read()
81 }
82 }
83}
84
85pub(super) fn relabel<const D: usize, I, U>(
86 tensor: TensorRank1<D, Reference, Dimensionless>,
87) -> TensorRank1<D, I, U> {
88 unsafe {
89 (&tensor as *const TensorRank1<D, Reference, Dimensionless>)
90 .cast::<TensorRank1<D, I, U>>()
91 .read()
92 }
93}
94
95impl<const D: usize, I, U> TensorRank1<D, I, U> {
96 pub const fn const_from(array: [TensorRank0; D]) -> Self {
98 let mut entries = [Quantity::new(0.0); D];
99 let mut i = 0;
100 while i < D {
101 entries[i] = Quantity::new(array[i]);
102 i += 1;
103 }
104 Self(entries, PhantomData)
105 }
106}
107
108impl<const D: usize, I, U> Default for TensorRank1<D, I, U> {
109 fn default() -> Self {
110 Self::zero()
111 }
112}
113
114impl<const D: usize, U> From<TensorRank1<D, Reference, U>> for TensorRank1<D, Current, U> {
115 fn from(tensor_rank_1: TensorRank1<D, Reference, U>) -> Self {
116 Self(tensor_rank_1.0, PhantomData)
117 }
118}
119
120impl<const D: usize, U> From<&TensorRank1<D, Reference, U>> for TensorRank1<D, Current, U> {
121 fn from(tensor_rank_1: &TensorRank1<D, Reference, U>) -> Self {
122 Self(tensor_rank_1.0, PhantomData)
123 }
124}
125
126impl<const D: usize, U> From<TensorRank1<D, Current, U>> for TensorRank1<D, Reference, U> {
127 fn from(tensor_rank_1: TensorRank1<D, Current, U>) -> Self {
128 Self(tensor_rank_1.0, PhantomData)
129 }
130}
131
132impl<const D: usize, U> From<&TensorRank1<D, Current, U>> for TensorRank1<D, Reference, U> {
133 fn from(tensor_rank_1: &TensorRank1<D, Current, U>) -> Self {
134 Self(tensor_rank_1.0, PhantomData)
135 }
136}
137
138impl<const D: usize, U> From<TensorRank1<D, Projection, U>> for TensorRank1<D, Reference, U> {
139 fn from(tensor_rank_1: TensorRank1<D, Projection, U>) -> Self {
140 Self(tensor_rank_1.0, PhantomData)
141 }
142}
143
144impl<const D: usize, U> From<&TensorRank1<D, Projection, U>> for TensorRank1<D, Reference, U> {
145 fn from(tensor_rank_1: &TensorRank1<D, Projection, U>) -> Self {
146 Self(tensor_rank_1.0, PhantomData)
147 }
148}
149
150impl<const D: usize, I, U> Display for TensorRank1<D, I, U> {
151 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
152 write!(f, "\x1B[s")?;
153 write!(f, "[")?;
154 self.iter()
155 .try_for_each(|entry| write_tensor_rank_0(f, &entry.value()))?;
156 write!(f, "\x1B[2D]")
157 }
158}
159
160impl<const D: usize, I, U> TensorRank1<D, I, U> {
161 pub const fn as_ptr(&self) -> *const TensorRank0 {
163 self.0.as_ptr().cast()
164 }
165 pub fn orthonormal_basis(&self) -> TensorRank1List<D, I, D, Dimensionless> {
167 let norm = self.norm().value();
168 assert!(
169 norm > ABS_TOL,
170 "Cannot build an orthonormal basis from the zero vector"
171 );
172 let mut basis = TensorRank1List::zero();
173 basis[0] = (self / norm).with_unit();
174 let mut filled = 1;
175 for i in 0..D {
176 if filled == D {
177 break;
178 }
179 let mut v: TensorRank1<D, I, Dimensionless> = zero();
180 v[i] = Quantity::new(1.0);
181 basis.iter().take(filled).for_each(|q| v -= q * (&v * q));
182 let v_norm = v.norm().value();
183 if v_norm > ABS_TOL {
184 basis[filled] = v / v_norm;
185 filled += 1;
186 }
187 }
188 assert!(filled == D, "Failed to construct full orthonormal basis");
189 basis
190 }
191}
192
193impl<const D: usize, I, U> FiniteDifference for TensorRank1<D, I, U> {
194 fn error_fd(&self, comparator: &Self, epsilon: TensorRank0) -> Option<(bool, usize)> {
195 let error_count = self
196 .iter()
197 .zip(comparator.iter())
198 .filter(|&(&self_i, &comparator_i)| self_i.differs(comparator_i, epsilon))
199 .count();
200 if error_count > 0 {
201 Some((true, error_count))
202 } else {
203 None
204 }
205 }
206}
207
208impl<const D: usize, I, U> Solution for TensorRank1<D, I, U> {
209 fn decrement_from(&mut self, _other: &Vector) {
210 unimplemented!()
211 }
212 fn decrement_from_chained(&mut self, _other: &mut Vector, _vector: &Vector) {
213 unimplemented!()
214 }
215}
216
217impl<const D: usize, I, U> Jacobian for TensorRank1<D, I, U> {
218 fn fill_into(&self, _vector: &mut Vector) {
219 unimplemented!()
220 }
221 fn fill_into_chained(self, _other: Vector, _vector: &mut Vector) {
222 unimplemented!()
223 }
224}
225
226impl<const D: usize, I, U> Sub<Vector> for TensorRank1<D, I, U> {
227 type Output = Self;
228 fn sub(self, _vector: Vector) -> Self::Output {
229 unimplemented!()
230 }
231}
232
233impl<const D: usize, I, U> Sub<&Vector> for TensorRank1<D, I, U> {
234 type Output = Self;
235 fn sub(self, _vector: &Vector) -> Self::Output {
236 unimplemented!()
237 }
238}
239
240impl<const D: usize, I, U> Erase for TensorRank1<D, I, U> {
241 type Erased = TensorRank1<D, Reference, Dimensionless>;
242 fn erase(&self) -> &Self::Erased {
243 self.canonical()
244 }
245}
246
247impl<const D: usize, I, U, V> Mul<Quantity<V>> for TensorRank1<D, I, U>
248where
249 U: UnitMul<V>,
250{
251 type Output = TensorRank1<D, I, <U as UnitMul<V>>::Output>;
252 fn mul(self, quantity: Quantity<V>) -> Self::Output {
253 relabel(self.into_canonical() * quantity.value())
254 }
255}
256
257impl<const D: usize, I, U, V> Mul<Quantity<V>> for &TensorRank1<D, I, U>
258where
259 U: UnitMul<V>,
260{
261 type Output = TensorRank1<D, I, <U as UnitMul<V>>::Output>;
262 fn mul(self, quantity: Quantity<V>) -> Self::Output {
263 relabel(self.canonical() * quantity.value())
264 }
265}
266
267impl<const D: usize, I, U, V> Mul<&Quantity<V>> for TensorRank1<D, I, U>
268where
269 U: UnitMul<V>,
270{
271 type Output = TensorRank1<D, I, <U as UnitMul<V>>::Output>;
272 fn mul(self, quantity: &Quantity<V>) -> Self::Output {
273 self * *quantity
274 }
275}
276
277impl<const D: usize, I, U, V> Mul<&Quantity<V>> for &TensorRank1<D, I, U>
278where
279 U: UnitMul<V>,
280{
281 type Output = TensorRank1<D, I, <U as UnitMul<V>>::Output>;
282 fn mul(self, quantity: &Quantity<V>) -> Self::Output {
283 self * *quantity
284 }
285}
286
287impl<const D: usize, I, U, V> Div<Quantity<V>> for TensorRank1<D, I, U>
288where
289 U: UnitDiv<V>,
290{
291 type Output = TensorRank1<D, I, <U as UnitDiv<V>>::Output>;
292 fn div(self, quantity: Quantity<V>) -> Self::Output {
293 relabel(self.into_canonical() / quantity.value())
294 }
295}
296
297impl<const D: usize, I, U, V> Div<Quantity<V>> for &TensorRank1<D, I, U>
298where
299 U: UnitDiv<V>,
300{
301 type Output = TensorRank1<D, I, <U as UnitDiv<V>>::Output>;
302 fn div(self, quantity: Quantity<V>) -> Self::Output {
303 relabel(self.canonical() / quantity.value())
304 }
305}
306
307impl<const D: usize, I, U> Tensor for TensorRank1<D, I, U> {
308 type Item = Quantity<U>;
309 type Unit = U;
310 fn full_contraction(&self, tensor_rank_1: &Self) -> TensorRank0 {
311 self.iter()
312 .zip(tensor_rank_1.iter())
313 .map(|(self_i, other_i)| self_i.value() * other_i.value())
314 .sum()
315 }
316 fn iter(&self) -> impl Iterator<Item = &Self::Item> {
317 self.0.iter()
318 }
319 fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item> {
320 self.0.iter_mut()
321 }
322 fn len(&self) -> usize {
323 D
324 }
325 fn size(&self) -> usize {
326 D
327 }
328}
329
330impl<const D: usize, I, U> IntoIterator for TensorRank1<D, I, U> {
331 type Item = Quantity<U>;
332 type IntoIter = std::array::IntoIter<Self::Item, D>;
333 fn into_iter(self) -> Self::IntoIter {
334 self.0.into_iter()
335 }
336}
337
338impl<const D: usize, I, U> TensorArray for TensorRank1<D, I, U> {
339 type Array = [Quantity<U>; D];
340 type Item = Quantity<U>;
341 fn as_array(&self) -> Self::Array {
342 self.0
343 }
344 fn identity() -> Self {
345 ones()
346 }
347 fn zero() -> Self {
348 zero()
349 }
350}
351
352pub(crate) const fn ones<const D: usize, I, U>() -> TensorRank1<D, I, U> {
354 TensorRank1([Quantity::new(1.0); D], PhantomData)
355}
356
357pub const fn zero<const D: usize, I, U>() -> TensorRank1<D, I, U> {
359 TensorRank1([Quantity::new(0.0); D], PhantomData)
360}
361
362impl<const D: usize, I, U> From<[Quantity<U>; D]> for TensorRank1<D, I, U> {
363 fn from(array: [Quantity<U>; D]) -> Self {
364 Self(array, PhantomData)
365 }
366}
367
368impl<const D: usize, I, U> From<[TensorRank0; D]> for TensorRank1<D, I, U> {
369 fn from(array: [TensorRank0; D]) -> Self {
370 Self(array.map(Quantity::new), PhantomData)
371 }
372}
373
374impl<const D: usize, I, U> From<TensorRank1<D, I, U>> for [TensorRank0; D] {
375 fn from(tensor_rank_1: TensorRank1<D, I, U>) -> Self {
376 tensor_rank_1.0.map(|entry| entry.value())
377 }
378}
379
380impl<const D: usize, I, U> From<Vec<TensorRank0>> for TensorRank1<D, I, U> {
381 fn from(vec: Vec<TensorRank0>) -> Self {
382 Self(
383 TryInto::<[TensorRank0; D]>::try_into(vec)
384 .unwrap()
385 .map(Quantity::new),
386 PhantomData,
387 )
388 }
389}
390
391impl<const D: usize, I, U> From<TensorRank1<D, I, U>> for Vec<TensorRank0> {
392 fn from(tensor_rank_1: TensorRank1<D, I, U>) -> Self {
393 tensor_rank_1.0.iter().map(|entry| entry.value()).collect()
394 }
395}
396
397impl<const D: usize, I, U> From<Vector> for TensorRank1<D, I, U> {
398 fn from(_vector: Vector) -> Self {
399 unimplemented!()
400 }
401}
402
403impl<const D: usize, I, U> FromIterator<TensorRank0> for TensorRank1<D, I, U> {
404 fn from_iter<Ii: IntoIterator<Item = TensorRank0>>(into_iterator: Ii) -> Self {
405 into_iterator.into_iter().map(Quantity::new).collect()
406 }
407}
408
409impl<const D: usize, I, U> FromIterator<Quantity<U>> for TensorRank1<D, I, U> {
410 fn from_iter<Ii: IntoIterator<Item = Quantity<U>>>(into_iterator: Ii) -> Self {
411 let mut tensor_rank_1 = zero();
412 tensor_rank_1
413 .iter_mut()
414 .zip(into_iterator)
415 .for_each(|(tensor_rank_1_i, value_i)| *tensor_rank_1_i = value_i);
416 tensor_rank_1
417 }
418}
419
420impl<const D: usize, I, U> Index<usize> for TensorRank1<D, I, U> {
421 type Output = Quantity<U>;
422 fn index(&self, index: usize) -> &Self::Output {
423 &self.0[index]
424 }
425}
426
427impl<const D: usize, I, U> IndexMut<usize> for TensorRank1<D, I, U> {
428 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
429 &mut self.0[index]
430 }
431}
432
433impl<const D: usize, I, U> Sum for TensorRank1<D, I, U> {
434 fn sum<Ii>(iter: Ii) -> Self
435 where
436 Ii: Iterator<Item = Self>,
437 {
438 iter.reduce(|mut acc, item| {
439 acc += item;
440 acc
441 })
442 .unwrap_or_else(Self::default)
443 }
444}
445
446impl<'a, const D: usize, I, U> Sum<&'a Self> for TensorRank1<D, I, U> {
447 fn sum<Ii>(iter: Ii) -> Self
448 where
449 Ii: Iterator<Item = &'a Self>,
450 {
451 iter.fold(Self::default(), |mut acc, item| {
452 acc += item;
453 acc
454 })
455 }
456}
457
458impl<const D: usize, I, U> Neg for TensorRank1<D, I, U> {
459 type Output = Self;
460 fn neg(self) -> Self::Output {
461 from_fn(|i| -self[i]).into()
462 }
463}
464
465impl<const D: usize, I, U> Neg for &TensorRank1<D, I, U> {
466 type Output = TensorRank1<D, I, U>;
467 fn neg(self) -> Self::Output {
468 from_fn(|i| -self[i]).into()
469 }
470}
471
472impl<const D: usize, I, U> Div<TensorRank0> for TensorRank1<D, I, U> {
473 type Output = Self;
474 fn div(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
475 self /= tensor_rank_0;
476 self
477 }
478}
479
480impl<const D: usize, I, U> Div<TensorRank0> for &TensorRank1<D, I, U> {
481 type Output = TensorRank1<D, I, U>;
482 fn div(self, tensor_rank_0: TensorRank0) -> Self::Output {
483 self.iter().map(|self_i| self_i / tensor_rank_0).collect()
484 }
485}
486
487impl<const D: usize, I, U> Div<&TensorRank0> for TensorRank1<D, I, U> {
488 type Output = Self;
489 fn div(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
490 self /= tensor_rank_0;
491 self
492 }
493}
494
495impl<const D: usize, I, U> Div<&TensorRank0> for &TensorRank1<D, I, U> {
496 type Output = TensorRank1<D, I, U>;
497 fn div(self, tensor_rank_0: &TensorRank0) -> Self::Output {
498 self.iter().map(|self_i| self_i / tensor_rank_0).collect()
499 }
500}
501
502impl<const D: usize, I, U> DivAssign<TensorRank0> for TensorRank1<D, I, U> {
503 fn div_assign(&mut self, tensor_rank_0: TensorRank0) {
504 self.iter_mut().for_each(|self_i| *self_i /= &tensor_rank_0);
505 }
506}
507
508impl<const D: usize, I, U> DivAssign<&TensorRank0> for TensorRank1<D, I, U> {
509 fn div_assign(&mut self, tensor_rank_0: &TensorRank0) {
510 self.iter_mut().for_each(|self_i| *self_i /= tensor_rank_0);
511 }
512}
513
514impl<const D: usize, I, U> Mul<TensorRank0> for TensorRank1<D, I, U> {
515 type Output = Self;
516 fn mul(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
517 self *= tensor_rank_0;
518 self
519 }
520}
521
522impl<const D: usize, I, U> Mul<TensorRank0> for &TensorRank1<D, I, U> {
523 type Output = TensorRank1<D, I, U>;
524 fn mul(self, tensor_rank_0: TensorRank0) -> Self::Output {
525 self.iter().map(|self_i| self_i * tensor_rank_0).collect()
526 }
527}
528
529impl<const D: usize, I, U> Mul<&TensorRank0> for TensorRank1<D, I, U> {
530 type Output = Self;
531 fn mul(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
532 self *= tensor_rank_0;
533 self
534 }
535}
536
537impl<const D: usize, I, U> Mul<&TensorRank0> for &TensorRank1<D, I, U> {
538 type Output = TensorRank1<D, I, U>;
539 fn mul(self, tensor_rank_0: &TensorRank0) -> Self::Output {
540 self.iter().map(|self_i| self_i * tensor_rank_0).collect()
541 }
542}
543
544impl<const D: usize, I, U> MulAssign<TensorRank0> for TensorRank1<D, I, U> {
545 fn mul_assign(&mut self, tensor_rank_0: TensorRank0) {
546 self.iter_mut().for_each(|self_i| *self_i *= &tensor_rank_0);
547 }
548}
549
550impl<const D: usize, I, U> MulAssign<&TensorRank0> for TensorRank1<D, I, U> {
551 fn mul_assign(&mut self, tensor_rank_0: &TensorRank0) {
552 self.iter_mut().for_each(|self_i| *self_i *= tensor_rank_0);
553 }
554}
555
556impl<const D: usize, I, U> Add for TensorRank1<D, I, U> {
557 type Output = Self;
558 fn add(mut self, tensor_rank_1: Self) -> Self::Output {
559 self += tensor_rank_1;
560 self
561 }
562}
563
564impl<const D: usize, I, U> Add<&Self> for TensorRank1<D, I, U> {
565 type Output = Self;
566 fn add(mut self, tensor_rank_1: &Self) -> Self::Output {
567 self += tensor_rank_1;
568 self
569 }
570}
571
572impl<const D: usize, I, U> Add<TensorRank1<D, I, U>> for &TensorRank1<D, I, U> {
573 type Output = TensorRank1<D, I, U>;
574 fn add(self, mut tensor_rank_1: TensorRank1<D, I, U>) -> Self::Output {
575 tensor_rank_1 += self;
576 tensor_rank_1
577 }
578}
579
580impl<const D: usize, I, U> Add<Self> for &TensorRank1<D, I, U> {
581 type Output = TensorRank1<D, I, U>;
582 fn add(self, tensor_rank_1: Self) -> Self::Output {
583 tensor_rank_1
584 .iter()
585 .zip(self.iter())
586 .map(|(tensor_rank_1_i, self_i)| self_i + *tensor_rank_1_i)
587 .collect()
588 }
589}
590
591impl<const D: usize, I, U> AddAssign for TensorRank1<D, I, U> {
592 fn add_assign(&mut self, tensor_rank_1: Self) {
593 self.iter_mut()
594 .zip(tensor_rank_1)
595 .for_each(|(self_i, tensor_rank_1_i)| *self_i += tensor_rank_1_i);
596 }
597}
598
599impl<const D: usize, I, U> AddAssign<&Self> for TensorRank1<D, I, U> {
600 fn add_assign(&mut self, tensor_rank_1: &Self) {
601 self.iter_mut()
602 .zip(tensor_rank_1.iter())
603 .for_each(|(self_i, tensor_rank_1_i)| *self_i += tensor_rank_1_i);
604 }
605}
606
607impl<const D: usize, I, U> Sub for TensorRank1<D, I, U> {
608 type Output = Self;
609 fn sub(mut self, tensor_rank_1: Self) -> Self::Output {
610 self -= tensor_rank_1;
611 self
612 }
613}
614
615impl<const D: usize, I, U> Sub<&Self> for TensorRank1<D, I, U> {
616 type Output = Self;
617 fn sub(mut self, tensor_rank_1: &Self) -> Self::Output {
618 self -= tensor_rank_1;
619 self
620 }
621}
622
623impl<const D: usize, I, U> Sub<TensorRank1<D, I, U>> for &TensorRank1<D, I, U> {
624 type Output = TensorRank1<D, I, U>;
625 fn sub(self, mut tensor_rank_1: TensorRank1<D, I, U>) -> Self::Output {
626 tensor_rank_1
627 .iter_mut()
628 .zip(self.iter())
629 .for_each(|(tensor_rank_1_i, self_i)| *tensor_rank_1_i = self_i - *tensor_rank_1_i);
630 tensor_rank_1
631 }
632}
633
634impl<const D: usize, I, U> Sub<Self> for &TensorRank1<D, I, U> {
635 type Output = TensorRank1<D, I, U>;
636 fn sub(self, tensor_rank_1: Self) -> Self::Output {
637 tensor_rank_1
638 .iter()
639 .zip(self.iter())
640 .map(|(tensor_rank_1_i, self_i)| self_i - *tensor_rank_1_i)
641 .collect()
642 }
643}
644
645impl<const D: usize, I, U> SubAssign for TensorRank1<D, I, U> {
646 fn sub_assign(&mut self, tensor_rank_1: Self) {
647 self.iter_mut()
648 .zip(tensor_rank_1)
649 .for_each(|(self_i, tensor_rank_1_i)| *self_i -= tensor_rank_1_i);
650 }
651}
652
653impl<const D: usize, I, U> SubAssign<&Self> for TensorRank1<D, I, U> {
654 fn sub_assign(&mut self, tensor_rank_1: &Self) {
655 self.iter_mut()
656 .zip(tensor_rank_1.iter())
657 .for_each(|(self_i, tensor_rank_1_i)| *self_i -= tensor_rank_1_i);
658 }
659}
660
661impl<const D: usize, I, U> Mul for TensorRank1<D, I, U> {
662 type Output = TensorRank0;
663 fn mul(self, tensor_rank_1: Self) -> Self::Output {
664 self.into_iter()
665 .zip(tensor_rank_1)
666 .map(|(self_i, tensor_rank_1_i)| self_i.value() * tensor_rank_1_i.value())
667 .sum()
668 }
669}
670
671impl<const D: usize, I, U, V> Mul<&TensorRank1<D, I, V>> for TensorRank1<D, I, U>
672where
673 U: UnitMul<V>,
674{
675 type Output = Quantity<<U as UnitMul<V>>::Output>;
676 fn mul(self, tensor_rank_1: &TensorRank1<D, I, V>) -> Self::Output {
677 Quantity::new(
678 self.into_iter()
679 .zip(tensor_rank_1.iter())
680 .map(|(self_i, tensor_rank_1_i)| self_i.value() * tensor_rank_1_i.value())
681 .sum(),
682 )
683 }
684}
685
686impl<const D: usize, I, U, V> Mul<TensorRank1<D, I, V>> for &TensorRank1<D, I, U>
687where
688 U: UnitMul<V>,
689{
690 type Output = Quantity<<U as UnitMul<V>>::Output>;
691 fn mul(self, tensor_rank_1: TensorRank1<D, I, V>) -> Self::Output {
692 Quantity::new(
693 self.iter()
694 .zip(tensor_rank_1)
695 .map(|(self_i, tensor_rank_1_i)| self_i.value() * tensor_rank_1_i.value())
696 .sum(),
697 )
698 }
699}
700
701impl<const D: usize, I, U, V> Mul<&TensorRank1<D, I, V>> for &TensorRank1<D, I, U>
702where
703 U: UnitMul<V>,
704{
705 type Output = Quantity<<U as UnitMul<V>>::Output>;
706 fn mul(self, tensor_rank_1: &TensorRank1<D, I, V>) -> Self::Output {
707 Quantity::new(
708 self.iter()
709 .zip(tensor_rank_1.iter())
710 .map(|(self_i, tensor_rank_1_i)| self_i.value() * tensor_rank_1_i.value())
711 .sum(),
712 )
713 }
714}
715
716#[allow(clippy::suspicious_arithmetic_impl)]
717impl<const D: usize, I, J, U, V> Div<TensorRank2<D, I, J, V>> for &TensorRank1<D, I, U>
718where
719 U: UnitDiv<V>,
720{
721 type Output = TensorRank1<D, J, <U as UnitDiv<V>>::Output>;
722 fn div(self, tensor_rank_2: TensorRank2<D, I, J, V>) -> Self::Output {
723 relabel(tensor_rank_2.canonical().clone().inverse() * self.canonical())
724 }
725}
726
727impl<const D: usize, I, U, V> ContractWith<TensorRank1<D, I, V>> for TensorRank1<D, I, U>
728where
729 U: UnitMul<V>,
730{
731 type Output = Quantity<<U as UnitMul<V>>::Output>;
732 fn contract_with(&self, tensor_rank_1: &TensorRank1<D, I, V>) -> Self::Output {
733 Quantity::new(self.canonical().full_contraction(tensor_rank_1.canonical()))
734 }
735}
736
737impl<const D: usize, I, U, T> Differentiate<T> for TensorRank1<D, I, U>
738where
739 U: UnitDiv<T>,
740{
741 type Derivative = TensorRank1<D, I, <U as UnitDiv<T>>::Output>;
742}