1#[cfg(test)]
2mod test;
3use super::{ContractWith, Differentiable, 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 HessianBlock, 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 self.iter_mut()
211 .zip(other.iter())
212 .for_each(|(self_i, vector_i)| *self_i -= Quantity::new(*vector_i))
213 }
214 fn decrement_from_chained(&mut self, other: &mut Vector, vector: &Vector) {
215 let mut values = vector.iter();
216 self.iter_mut()
217 .zip(values.by_ref())
218 .for_each(|(entry_i, vector_i)| *entry_i -= Quantity::new(*vector_i));
219 other
220 .iter_mut()
221 .zip(values)
222 .for_each(|(entry_i, vector_i)| *entry_i -= vector_i)
223 }
224}
225
226impl<const D: usize, I, U> Jacobian for TensorRank1<D, I, U> {
227 fn fill_into(&self, vector: &mut Vector) {
228 self.iter()
229 .zip(vector.iter_mut())
230 .for_each(|(self_i, vector_i)| *vector_i = self_i.value())
231 }
232 fn fill_into_chained(self, other: Vector, vector: &mut Vector) {
233 self.into_iter()
234 .map(|entry| entry.value())
235 .chain(other)
236 .zip(vector.iter_mut())
237 .for_each(|(self_i, vector_i)| *vector_i = self_i)
238 }
239}
240
241impl<const D: usize, I, U> HessianBlock for TensorRank1<D, I, U> {
242 fn entry(&self, row: usize, _column: usize) -> TensorRank0 {
243 self[row].value()
244 }
245 fn height(&self) -> usize {
246 D
247 }
248 fn width(&self) -> usize {
249 1
250 }
251 fn fill_into_block<M>(&self, matrix: &mut M, row: usize, column: usize)
252 where
253 M: IndexMut<usize, Output = Vector>,
254 {
255 self.iter()
256 .enumerate()
257 .for_each(|(i, self_i)| matrix[row + i][column] = self_i.value())
258 }
259}
260
261impl<const D: usize, I, U> Sub<Vector> for TensorRank1<D, I, U> {
262 type Output = Self;
263 fn sub(mut self, vector: Vector) -> Self::Output {
264 self.iter_mut()
265 .enumerate()
266 .for_each(|(i, self_i)| *self_i -= Quantity::new(vector[i]));
267 self
268 }
269}
270
271impl<const D: usize, I, U> Sub<&Vector> for TensorRank1<D, I, U> {
272 type Output = Self;
273 fn sub(mut self, vector: &Vector) -> Self::Output {
274 self.iter_mut()
275 .enumerate()
276 .for_each(|(i, self_i)| *self_i -= Quantity::new(vector[i]));
277 self
278 }
279}
280
281impl<const D: usize, I, U> Erase for TensorRank1<D, I, U> {
282 type Erased = TensorRank1<D, Reference, Dimensionless>;
283 fn erase(&self) -> &Self::Erased {
284 self.canonical()
285 }
286}
287
288impl<const D: usize, I, U, V> Mul<Quantity<V>> for TensorRank1<D, I, U>
289where
290 U: UnitMul<V>,
291{
292 type Output = TensorRank1<D, I, <U as UnitMul<V>>::Output>;
293 fn mul(self, quantity: Quantity<V>) -> Self::Output {
294 relabel(self.into_canonical() * quantity.value())
295 }
296}
297
298impl<const D: usize, I, U, V> Mul<Quantity<V>> for &TensorRank1<D, I, U>
299where
300 U: UnitMul<V>,
301{
302 type Output = TensorRank1<D, I, <U as UnitMul<V>>::Output>;
303 fn mul(self, quantity: Quantity<V>) -> Self::Output {
304 relabel(self.canonical() * quantity.value())
305 }
306}
307
308impl<const D: usize, I, U, V> Mul<&Quantity<V>> for TensorRank1<D, I, U>
309where
310 U: UnitMul<V>,
311{
312 type Output = TensorRank1<D, I, <U as UnitMul<V>>::Output>;
313 fn mul(self, quantity: &Quantity<V>) -> Self::Output {
314 self * *quantity
315 }
316}
317
318impl<const D: usize, I, U, V> Mul<&Quantity<V>> for &TensorRank1<D, I, U>
319where
320 U: UnitMul<V>,
321{
322 type Output = TensorRank1<D, I, <U as UnitMul<V>>::Output>;
323 fn mul(self, quantity: &Quantity<V>) -> Self::Output {
324 self * *quantity
325 }
326}
327
328impl<const D: usize, I, U, V> Div<Quantity<V>> for TensorRank1<D, I, U>
329where
330 U: UnitDiv<V>,
331{
332 type Output = TensorRank1<D, I, <U as UnitDiv<V>>::Output>;
333 fn div(self, quantity: Quantity<V>) -> Self::Output {
334 relabel(self.into_canonical() / quantity.value())
335 }
336}
337
338impl<const D: usize, I, U, V> Div<Quantity<V>> for &TensorRank1<D, I, U>
339where
340 U: UnitDiv<V>,
341{
342 type Output = TensorRank1<D, I, <U as UnitDiv<V>>::Output>;
343 fn div(self, quantity: Quantity<V>) -> Self::Output {
344 relabel(self.canonical() / quantity.value())
345 }
346}
347
348impl<const D: usize, I, U> Tensor for TensorRank1<D, I, U> {
349 type Item = Quantity<U>;
350 type Unit = U;
351 fn full_contraction(&self, tensor_rank_1: &Self) -> TensorRank0 {
352 self.iter()
353 .zip(tensor_rank_1.iter())
354 .map(|(self_i, other_i)| self_i.value().algebraic_mul(other_i.value()))
355 .fold(0.0, f64::algebraic_add)
356 }
357 fn iter(&self) -> impl Iterator<Item = &Self::Item> {
358 self.0.iter()
359 }
360 fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item> {
361 self.0.iter_mut()
362 }
363 fn len(&self) -> usize {
364 D
365 }
366 fn size(&self) -> usize {
367 D
368 }
369}
370
371impl<const D: usize, I, U> IntoIterator for TensorRank1<D, I, U> {
372 type Item = Quantity<U>;
373 type IntoIter = std::array::IntoIter<Self::Item, D>;
374 fn into_iter(self) -> Self::IntoIter {
375 self.0.into_iter()
376 }
377}
378
379impl<const D: usize, I, U> TensorArray for TensorRank1<D, I, U> {
380 type Array = [Quantity<U>; D];
381 type Item = Quantity<U>;
382 fn as_array(&self) -> Self::Array {
383 self.0
384 }
385 fn identity() -> Self {
386 ones()
387 }
388 fn zero() -> Self {
389 zero()
390 }
391}
392
393pub(crate) const fn ones<const D: usize, I, U>() -> TensorRank1<D, I, U> {
395 TensorRank1([Quantity::new(1.0); D], PhantomData)
396}
397
398pub const fn zero<const D: usize, I, U>() -> TensorRank1<D, I, U> {
400 TensorRank1([Quantity::new(0.0); D], PhantomData)
401}
402
403impl<const D: usize, I, U> From<[Quantity<U>; D]> for TensorRank1<D, I, U> {
404 fn from(array: [Quantity<U>; D]) -> Self {
405 Self(array, PhantomData)
406 }
407}
408
409impl<const D: usize, I, U> From<[TensorRank0; D]> for TensorRank1<D, I, U> {
410 fn from(array: [TensorRank0; D]) -> Self {
411 Self(array.map(Quantity::new), PhantomData)
412 }
413}
414
415impl<const D: usize, I, U> From<TensorRank1<D, I, U>> for [TensorRank0; D] {
416 fn from(tensor_rank_1: TensorRank1<D, I, U>) -> Self {
417 tensor_rank_1.0.map(|entry| entry.value())
418 }
419}
420
421impl<const D: usize, I, U> From<Vec<TensorRank0>> for TensorRank1<D, I, U> {
422 fn from(vec: Vec<TensorRank0>) -> Self {
423 Self(
424 TryInto::<[TensorRank0; D]>::try_into(vec)
425 .unwrap()
426 .map(Quantity::new),
427 PhantomData,
428 )
429 }
430}
431
432impl<const D: usize, I, U> From<TensorRank1<D, I, U>> for Vec<TensorRank0> {
433 fn from(tensor_rank_1: TensorRank1<D, I, U>) -> Self {
434 tensor_rank_1.0.iter().map(|entry| entry.value()).collect()
435 }
436}
437
438impl<const D: usize, I, U> From<Vector> for TensorRank1<D, I, U> {
439 fn from(vector: Vector) -> Self {
440 vector.into_iter().take(D).collect()
441 }
442}
443
444impl<const D: usize, I, U> FromIterator<TensorRank0> for TensorRank1<D, I, U> {
445 fn from_iter<Ii: IntoIterator<Item = TensorRank0>>(into_iterator: Ii) -> Self {
446 into_iterator.into_iter().map(Quantity::new).collect()
447 }
448}
449
450impl<const D: usize, I, U> FromIterator<Quantity<U>> for TensorRank1<D, I, U> {
451 fn from_iter<Ii: IntoIterator<Item = Quantity<U>>>(into_iterator: Ii) -> Self {
452 let mut tensor_rank_1 = zero();
453 tensor_rank_1
454 .iter_mut()
455 .zip(into_iterator)
456 .for_each(|(tensor_rank_1_i, value_i)| *tensor_rank_1_i = value_i);
457 tensor_rank_1
458 }
459}
460
461impl<const D: usize, I, U> Index<usize> for TensorRank1<D, I, U> {
462 type Output = Quantity<U>;
463 fn index(&self, index: usize) -> &Self::Output {
464 &self.0[index]
465 }
466}
467
468impl<const D: usize, I, U> IndexMut<usize> for TensorRank1<D, I, U> {
469 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
470 &mut self.0[index]
471 }
472}
473
474impl<const D: usize, I, U> Sum for TensorRank1<D, I, U> {
475 fn sum<Ii>(iter: Ii) -> Self
476 where
477 Ii: Iterator<Item = Self>,
478 {
479 iter.reduce(|mut acc, item| {
480 acc += item;
481 acc
482 })
483 .unwrap_or_else(Self::default)
484 }
485}
486
487impl<'a, const D: usize, I, U> Sum<&'a Self> for TensorRank1<D, I, U> {
488 fn sum<Ii>(iter: Ii) -> Self
489 where
490 Ii: Iterator<Item = &'a Self>,
491 {
492 iter.fold(Self::default(), |mut acc, item| {
493 acc += item;
494 acc
495 })
496 }
497}
498
499impl<const D: usize, I, U> Neg for TensorRank1<D, I, U> {
500 type Output = Self;
501 fn neg(self) -> Self::Output {
502 from_fn(|i| -self[i]).into()
503 }
504}
505
506impl<const D: usize, I, U> Neg for &TensorRank1<D, I, U> {
507 type Output = TensorRank1<D, I, U>;
508 fn neg(self) -> Self::Output {
509 from_fn(|i| -self[i]).into()
510 }
511}
512
513impl<const D: usize, I, U> Div<TensorRank0> for TensorRank1<D, I, U> {
514 type Output = Self;
515 fn div(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
516 self /= tensor_rank_0;
517 self
518 }
519}
520
521impl<const D: usize, I, U> Div<TensorRank0> for &TensorRank1<D, I, U> {
522 type Output = TensorRank1<D, I, U>;
523 fn div(self, tensor_rank_0: TensorRank0) -> Self::Output {
524 self.iter().map(|self_i| self_i / tensor_rank_0).collect()
525 }
526}
527
528impl<const D: usize, I, U> Div<&TensorRank0> for TensorRank1<D, I, U> {
529 type Output = Self;
530 fn div(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
531 self /= tensor_rank_0;
532 self
533 }
534}
535
536impl<const D: usize, I, U> Div<&TensorRank0> for &TensorRank1<D, I, U> {
537 type Output = TensorRank1<D, I, U>;
538 fn div(self, tensor_rank_0: &TensorRank0) -> Self::Output {
539 self.iter().map(|self_i| self_i / tensor_rank_0).collect()
540 }
541}
542
543impl<const D: usize, I, U> DivAssign<TensorRank0> for TensorRank1<D, I, U> {
544 fn div_assign(&mut self, tensor_rank_0: TensorRank0) {
545 self.iter_mut().for_each(|self_i| *self_i /= &tensor_rank_0);
546 }
547}
548
549impl<const D: usize, I, U> DivAssign<&TensorRank0> for TensorRank1<D, I, U> {
550 fn div_assign(&mut self, tensor_rank_0: &TensorRank0) {
551 self.iter_mut().for_each(|self_i| *self_i /= tensor_rank_0);
552 }
553}
554
555impl<const D: usize, I, U> Mul<TensorRank0> for TensorRank1<D, I, U> {
556 type Output = Self;
557 fn mul(mut self, tensor_rank_0: TensorRank0) -> Self::Output {
558 self *= tensor_rank_0;
559 self
560 }
561}
562
563impl<const D: usize, I, U> Mul<TensorRank0> for &TensorRank1<D, I, U> {
564 type Output = TensorRank1<D, I, U>;
565 fn mul(self, tensor_rank_0: TensorRank0) -> Self::Output {
566 self.iter().map(|self_i| self_i * tensor_rank_0).collect()
567 }
568}
569
570impl<const D: usize, I, U> Mul<&TensorRank0> for TensorRank1<D, I, U> {
571 type Output = Self;
572 fn mul(mut self, tensor_rank_0: &TensorRank0) -> Self::Output {
573 self *= tensor_rank_0;
574 self
575 }
576}
577
578impl<const D: usize, I, U> Mul<&TensorRank0> for &TensorRank1<D, I, U> {
579 type Output = TensorRank1<D, I, U>;
580 fn mul(self, tensor_rank_0: &TensorRank0) -> Self::Output {
581 self.iter().map(|self_i| self_i * tensor_rank_0).collect()
582 }
583}
584
585impl<const D: usize, I, U> MulAssign<TensorRank0> for TensorRank1<D, I, U> {
586 fn mul_assign(&mut self, tensor_rank_0: TensorRank0) {
587 self.iter_mut().for_each(|self_i| *self_i *= &tensor_rank_0);
588 }
589}
590
591impl<const D: usize, I, U> MulAssign<&TensorRank0> for TensorRank1<D, I, U> {
592 fn mul_assign(&mut self, tensor_rank_0: &TensorRank0) {
593 self.iter_mut().for_each(|self_i| *self_i *= tensor_rank_0);
594 }
595}
596
597impl<const D: usize, I, U> Add for TensorRank1<D, I, U> {
598 type Output = Self;
599 fn add(mut self, tensor_rank_1: Self) -> Self::Output {
600 self += tensor_rank_1;
601 self
602 }
603}
604
605impl<const D: usize, I, U> Add<&Self> for TensorRank1<D, I, U> {
606 type Output = Self;
607 fn add(mut self, tensor_rank_1: &Self) -> Self::Output {
608 self += tensor_rank_1;
609 self
610 }
611}
612
613impl<const D: usize, I, U> Add<TensorRank1<D, I, U>> for &TensorRank1<D, I, U> {
614 type Output = TensorRank1<D, I, U>;
615 fn add(self, mut tensor_rank_1: TensorRank1<D, I, U>) -> Self::Output {
616 tensor_rank_1 += self;
617 tensor_rank_1
618 }
619}
620
621impl<const D: usize, I, U> Add<Self> for &TensorRank1<D, I, U> {
622 type Output = TensorRank1<D, I, U>;
623 fn add(self, tensor_rank_1: Self) -> Self::Output {
624 tensor_rank_1
625 .iter()
626 .zip(self.iter())
627 .map(|(tensor_rank_1_i, self_i)| self_i + *tensor_rank_1_i)
628 .collect()
629 }
630}
631
632impl<const D: usize, I, U> AddAssign for TensorRank1<D, I, U> {
633 fn add_assign(&mut self, tensor_rank_1: Self) {
634 self.iter_mut()
635 .zip(tensor_rank_1)
636 .for_each(|(self_i, tensor_rank_1_i)| *self_i += tensor_rank_1_i);
637 }
638}
639
640impl<const D: usize, I, U> AddAssign<&Self> for TensorRank1<D, I, U> {
641 fn add_assign(&mut self, tensor_rank_1: &Self) {
642 self.iter_mut()
643 .zip(tensor_rank_1.iter())
644 .for_each(|(self_i, tensor_rank_1_i)| *self_i += tensor_rank_1_i);
645 }
646}
647
648impl<const D: usize, I, U> Sub for TensorRank1<D, I, U> {
649 type Output = Self;
650 fn sub(mut self, tensor_rank_1: Self) -> Self::Output {
651 self -= tensor_rank_1;
652 self
653 }
654}
655
656impl<const D: usize, I, U> Sub<&Self> for TensorRank1<D, I, U> {
657 type Output = Self;
658 fn sub(mut self, tensor_rank_1: &Self) -> Self::Output {
659 self -= tensor_rank_1;
660 self
661 }
662}
663
664impl<const D: usize, I, U> Sub<TensorRank1<D, I, U>> for &TensorRank1<D, I, U> {
665 type Output = TensorRank1<D, I, U>;
666 fn sub(self, mut tensor_rank_1: TensorRank1<D, I, U>) -> Self::Output {
667 tensor_rank_1
668 .iter_mut()
669 .zip(self.iter())
670 .for_each(|(tensor_rank_1_i, self_i)| *tensor_rank_1_i = self_i - *tensor_rank_1_i);
671 tensor_rank_1
672 }
673}
674
675impl<const D: usize, I, U> Sub<Self> for &TensorRank1<D, I, U> {
676 type Output = TensorRank1<D, I, U>;
677 fn sub(self, tensor_rank_1: Self) -> Self::Output {
678 tensor_rank_1
679 .iter()
680 .zip(self.iter())
681 .map(|(tensor_rank_1_i, self_i)| self_i - *tensor_rank_1_i)
682 .collect()
683 }
684}
685
686impl<const D: usize, I, U> SubAssign for TensorRank1<D, I, U> {
687 fn sub_assign(&mut self, tensor_rank_1: Self) {
688 self.iter_mut()
689 .zip(tensor_rank_1)
690 .for_each(|(self_i, tensor_rank_1_i)| *self_i -= tensor_rank_1_i);
691 }
692}
693
694impl<const D: usize, I, U> SubAssign<&Self> for TensorRank1<D, I, U> {
695 fn sub_assign(&mut self, tensor_rank_1: &Self) {
696 self.iter_mut()
697 .zip(tensor_rank_1.iter())
698 .for_each(|(self_i, tensor_rank_1_i)| *self_i -= tensor_rank_1_i);
699 }
700}
701
702impl<const D: usize, I, U> Mul for TensorRank1<D, I, U> {
703 type Output = TensorRank0;
704 fn mul(self, tensor_rank_1: Self) -> Self::Output {
705 self.into_iter()
706 .zip(tensor_rank_1)
707 .map(|(self_i, tensor_rank_1_i)| self_i.value() * tensor_rank_1_i.value())
708 .sum()
709 }
710}
711
712impl<const D: usize, I, U, V> Mul<&TensorRank1<D, I, V>> for TensorRank1<D, I, U>
713where
714 U: UnitMul<V>,
715{
716 type Output = Quantity<<U as UnitMul<V>>::Output>;
717 fn mul(self, tensor_rank_1: &TensorRank1<D, I, V>) -> Self::Output {
718 Quantity::new(
719 self.into_iter()
720 .zip(tensor_rank_1.iter())
721 .map(|(self_i, tensor_rank_1_i)| self_i.value() * tensor_rank_1_i.value())
722 .sum(),
723 )
724 }
725}
726
727impl<const D: usize, I, U, V> Mul<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 mul(self, tensor_rank_1: TensorRank1<D, I, V>) -> Self::Output {
733 Quantity::new(
734 self.iter()
735 .zip(tensor_rank_1)
736 .map(|(self_i, tensor_rank_1_i)| self_i.value() * tensor_rank_1_i.value())
737 .sum(),
738 )
739 }
740}
741
742impl<const D: usize, I, U, V> Mul<&TensorRank1<D, I, V>> for &TensorRank1<D, I, U>
743where
744 U: UnitMul<V>,
745{
746 type Output = Quantity<<U as UnitMul<V>>::Output>;
747 fn mul(self, tensor_rank_1: &TensorRank1<D, I, V>) -> Self::Output {
748 Quantity::new(
749 self.iter()
750 .zip(tensor_rank_1.iter())
751 .map(|(self_i, tensor_rank_1_i)| self_i.value() * tensor_rank_1_i.value())
752 .sum(),
753 )
754 }
755}
756
757#[expect(clippy::suspicious_arithmetic_impl)]
758impl<const D: usize, I, J, U, V> Div<TensorRank2<D, I, J, V>> for &TensorRank1<D, I, U>
759where
760 U: UnitDiv<V>,
761{
762 type Output = TensorRank1<D, J, <U as UnitDiv<V>>::Output>;
763 fn div(self, tensor_rank_2: TensorRank2<D, I, J, V>) -> Self::Output {
764 relabel(tensor_rank_2.canonical().clone().inverse() * self.canonical())
765 }
766}
767
768impl<const D: usize, I, U, V> ContractWith<TensorRank1<D, I, V>> for TensorRank1<D, I, U>
769where
770 U: UnitMul<V>,
771{
772 type Output = Quantity<<U as UnitMul<V>>::Output>;
773 fn contract_with(&self, tensor_rank_1: &TensorRank1<D, I, V>) -> Self::Output {
774 Quantity::new(self.canonical().full_contraction(tensor_rank_1.canonical()))
775 }
776}
777
778impl<const D: usize, I, U, T> Differentiable<T> for TensorRank1<D, I, U>
779where
780 U: UnitDiv<T>,
781{
782 type Derivative = TensorRank1<D, I, <U as UnitDiv<T>>::Output>;
783}