1#[cfg(test)]
2mod test;
3
4pub(crate) mod sparse_vec;
5pub(crate) mod sparse_vec_2d;
6pub(crate) mod vec;
7
8use super::{
9 Differentiate, Erase, Hessian, Jacobian, Solution, SquareMatrix, Tensor, TensorArray, Vector,
10 rank_0::TensorRank0,
11};
12use crate::math::{TensorList, assert::FiniteDifference};
13use crate::units::{Dimensionless, UnitDiv, UnitHalves, UnitInv, UnitMul};
14use std::{
15 cmp::Ordering,
16 fmt::{self, Display, Formatter},
17 marker::PhantomData,
18 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
19};
20
21pub trait Is<T> {}
24
25impl<T> Is<T> for T {}
26
27#[repr(transparent)]
29pub struct Quantity<U = Dimensionless>(TensorRank0, PhantomData<U>);
30
31impl<U> Quantity<U> {
32 pub(crate) const fn new(value: TensorRank0) -> Self {
34 Self(value, PhantomData)
35 }
36 pub const fn value(&self) -> TensorRank0 {
38 self.0
39 }
40 pub const fn value_as<V>(&self) -> TensorRank0
42 where
43 U: Is<V>,
44 {
45 self.0
46 }
47}
48
49impl<U> Quantity<U> {
50 pub fn abs(self) -> Self {
52 Self::new(self.0.abs())
53 }
54 pub fn is_nan(&self) -> bool {
56 self.0.is_nan()
57 }
58 pub fn differs(self, quantity: Self, epsilon: TensorRank0) -> bool {
62 ((self.0 / quantity.0 - 1.0).abs() >= epsilon
63 && (self.0.abs() >= epsilon || quantity.0.abs() >= epsilon))
64 || self.is_nan()
65 || quantity.is_nan()
66 }
67 pub fn differs_severely(self, quantity: Self, epsilon: TensorRank0) -> bool {
70 ((self.0 / quantity.0 - 1.0).abs() >= epsilon
71 && (self.0 - quantity.0).abs() >= epsilon
72 && (self.0.abs() >= epsilon || quantity.0.abs() >= epsilon))
73 || self.is_nan()
74 || quantity.is_nan()
75 }
76 pub fn total_cmp(&self, quantity: &Self) -> Ordering {
78 self.0.total_cmp(&quantity.0)
79 }
80 pub fn min(self, quantity: Self) -> Self {
82 Self::new(self.0.min(quantity.0))
83 }
84 pub fn max(self, quantity: Self) -> Self {
86 Self::new(self.0.max(quantity.0))
87 }
88}
89
90impl<U> Quantity<U>
91where
92 U: UnitHalves,
93{
94 pub const fn halves(
97 self,
98 ) -> (
99 Quantity<<U as UnitHalves>::First>,
100 Quantity<<U as UnitHalves>::Second>,
101 ) {
102 (Quantity::new(self.0), Quantity::new(self.0))
103 }
104}
105
106impl Quantity<Dimensionless> {
107 pub fn ceil(self) -> Self {
109 Self::new(self.0.ceil())
110 }
111 pub fn floor(self) -> Self {
113 Self::new(self.0.floor())
114 }
115 pub fn powi(self, n: i32) -> Self {
117 Self::new(self.0.powi(n))
118 }
119 pub fn powf(self, n: TensorRank0) -> Self {
121 Self::new(self.0.powf(n))
122 }
123 pub fn sqrt(self) -> Self {
125 Self::new(self.0.sqrt())
126 }
127 pub fn ln(self) -> Self {
129 Self::new(self.0.ln())
130 }
131 pub fn log2(self) -> Self {
133 Self::new(self.0.log2())
134 }
135 pub fn exp(self) -> Self {
137 Self::new(self.0.exp())
138 }
139 pub fn sin(self) -> Self {
141 Self::new(self.0.sin())
142 }
143 pub fn cos(self) -> Self {
145 Self::new(self.0.cos())
146 }
147}
148
149impl<U> Clone for Quantity<U> {
150 fn clone(&self) -> Self {
151 *self
152 }
153}
154
155impl<U> Copy for Quantity<U> {}
156
157impl<U> fmt::Debug for Quantity<U> {
158 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
159 fmt::Debug::fmt(&self.0, f)
160 }
161}
162
163impl<U> Display for Quantity<U> {
164 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
165 Display::fmt(&self.0, f)
166 }
167}
168
169impl<U> PartialEq for Quantity<U> {
170 fn eq(&self, other: &Self) -> bool {
171 self.0 == other.0
172 }
173}
174
175impl<U> PartialOrd for Quantity<U> {
176 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
177 self.0.partial_cmp(&other.0)
178 }
179}
180
181impl<U> Neg for Quantity<U> {
182 type Output = Self;
183 fn neg(self) -> Self::Output {
184 Self::new(-self.0)
185 }
186}
187
188impl<U> Default for Quantity<U> {
189 fn default() -> Self {
190 Self::new(0.0)
191 }
192}
193
194impl<U> Add for Quantity<U> {
195 type Output = Self;
196 fn add(self, quantity: Self) -> Self::Output {
197 Self::new(self.0 + quantity.0)
198 }
199}
200
201impl<U> Add<&Self> for Quantity<U> {
202 type Output = Self;
203 fn add(self, quantity: &Self) -> Self::Output {
204 Self::new(self.0 + quantity.0)
205 }
206}
207
208impl<U> AddAssign<&Self> for Quantity<U> {
209 fn add_assign(&mut self, quantity: &Self) {
210 self.0 += quantity.0
211 }
212}
213
214impl<U> Sub<&Self> for Quantity<U> {
215 type Output = Self;
216 fn sub(self, quantity: &Self) -> Self::Output {
217 Self::new(self.0 - quantity.0)
218 }
219}
220
221impl<U> SubAssign<&Self> for Quantity<U> {
222 fn sub_assign(&mut self, quantity: &Self) {
223 self.0 -= quantity.0
224 }
225}
226
227impl<U> Add for &Quantity<U> {
228 type Output = Quantity<U>;
229 fn add(self, quantity: Self) -> Self::Output {
230 Quantity::new(self.0 + quantity.0)
231 }
232}
233
234impl<U> Add<Quantity<U>> for &Quantity<U> {
235 type Output = Quantity<U>;
236 fn add(self, quantity: Quantity<U>) -> Self::Output {
237 Quantity::new(self.0 + quantity.0)
238 }
239}
240
241impl<U> Sub<Quantity<U>> for &Quantity<U> {
242 type Output = Quantity<U>;
243 fn sub(self, quantity: Quantity<U>) -> Self::Output {
244 Quantity::new(self.0 - quantity.0)
245 }
246}
247
248impl<U> Div<TensorRank0> for &Quantity<U> {
249 type Output = Quantity<U>;
250 fn div(self, tensor_rank_0: TensorRank0) -> Self::Output {
251 Quantity::new(self.0 / tensor_rank_0)
252 }
253}
254
255impl<U> Div<&TensorRank0> for &Quantity<U> {
256 type Output = Quantity<U>;
257 fn div(self, tensor_rank_0: &TensorRank0) -> Self::Output {
258 Quantity::new(self.0 / tensor_rank_0)
259 }
260}
261
262impl<U> Neg for &Quantity<U> {
263 type Output = Quantity<U>;
264 fn neg(self) -> Self::Output {
265 Quantity::new(-self.0)
266 }
267}
268
269impl<U> Sub for &Quantity<U> {
270 type Output = Quantity<U>;
271 fn sub(self, quantity: Self) -> Self::Output {
272 Quantity::new(self.0 - quantity.0)
273 }
274}
275
276impl<U> Mul<TensorRank0> for &Quantity<U> {
277 type Output = Quantity<U>;
278 fn mul(self, tensor_rank_0: TensorRank0) -> Self::Output {
279 Quantity::new(self.0 * tensor_rank_0)
280 }
281}
282
283impl<U> Mul<&TensorRank0> for &Quantity<U> {
284 type Output = Quantity<U>;
285 fn mul(self, tensor_rank_0: &TensorRank0) -> Self::Output {
286 Quantity::new(self.0 * tensor_rank_0)
287 }
288}
289
290impl<U> MulAssign<&TensorRank0> for Quantity<U> {
291 fn mul_assign(&mut self, tensor_rank_0: &TensorRank0) {
292 self.0 *= tensor_rank_0
293 }
294}
295
296impl<U> DivAssign<&TensorRank0> for Quantity<U> {
297 fn div_assign(&mut self, tensor_rank_0: &TensorRank0) {
298 self.0 /= tensor_rank_0
299 }
300}
301
302impl<U> AddAssign for Quantity<U> {
303 fn add_assign(&mut self, quantity: Self) {
304 self.0 += quantity.0
305 }
306}
307
308impl<U> Sub for Quantity<U> {
309 type Output = Self;
310 fn sub(self, quantity: Self) -> Self::Output {
311 Self::new(self.0 - quantity.0)
312 }
313}
314
315impl<U> SubAssign for Quantity<U> {
316 fn sub_assign(&mut self, quantity: Self) {
317 self.0 -= quantity.0
318 }
319}
320
321impl<U> Mul<TensorRank0> for Quantity<U> {
322 type Output = Self;
323 fn mul(self, tensor_rank_0: TensorRank0) -> Self::Output {
324 Self::new(self.0 * tensor_rank_0)
325 }
326}
327
328impl<U> Mul<&TensorRank0> for Quantity<U> {
329 type Output = Self;
330 fn mul(self, tensor_rank_0: &TensorRank0) -> Self::Output {
331 Self::new(self.0 * tensor_rank_0)
332 }
333}
334
335impl<U> MulAssign<TensorRank0> for Quantity<U> {
336 fn mul_assign(&mut self, tensor_rank_0: TensorRank0) {
337 self.0 *= tensor_rank_0
338 }
339}
340
341impl<U> Div<TensorRank0> for Quantity<U> {
342 type Output = Self;
343 fn div(self, tensor_rank_0: TensorRank0) -> Self::Output {
344 Self::new(self.0 / tensor_rank_0)
345 }
346}
347
348impl<U> DivAssign<TensorRank0> for Quantity<U> {
349 fn div_assign(&mut self, tensor_rank_0: TensorRank0) {
350 self.0 /= tensor_rank_0
351 }
352}
353
354impl<U> Mul<Quantity<U>> for TensorRank0 {
355 type Output = Quantity<U>;
356 fn mul(self, quantity: Quantity<U>) -> Self::Output {
357 Quantity::new(self * quantity.0)
358 }
359}
360
361impl Mul<Quantity<Dimensionless>> for &TensorRank0 {
363 type Output = TensorRank0;
364 fn mul(self, quantity: Quantity<Dimensionless>) -> Self::Output {
365 self * quantity.0
366 }
367}
368
369impl<U, V> Mul<Quantity<V>> for Quantity<U>
370where
371 U: UnitMul<V>,
372{
373 type Output = Quantity<<U as UnitMul<V>>::Output>;
374 fn mul(self, quantity: Quantity<V>) -> Self::Output {
375 Quantity::new(self.0 * quantity.0)
376 }
377}
378
379impl<U, V> Mul<Quantity<V>> for &Quantity<U>
380where
381 U: UnitMul<V>,
382{
383 type Output = Quantity<<U as UnitMul<V>>::Output>;
384 fn mul(self, quantity: Quantity<V>) -> Self::Output {
385 Quantity::new(self.0 * quantity.0)
386 }
387}
388
389impl<U, V> Div<Quantity<V>> for &Quantity<U>
390where
391 U: UnitDiv<V>,
392{
393 type Output = Quantity<<U as UnitDiv<V>>::Output>;
394 fn div(self, quantity: Quantity<V>) -> Self::Output {
395 Quantity::new(self.0 / quantity.value())
396 }
397}
398
399impl<U, V> Div<Quantity<V>> for Quantity<U>
400where
401 U: UnitDiv<V>,
402{
403 type Output = Quantity<<U as UnitDiv<V>>::Output>;
404 fn div(self, quantity: Quantity<V>) -> Self::Output {
405 Quantity::new(self.0 / quantity.0)
406 }
407}
408
409impl<U, V> Mul<&Quantity<V>> for Quantity<U>
410where
411 U: UnitMul<V>,
412{
413 type Output = Quantity<<U as UnitMul<V>>::Output>;
414 fn mul(self, quantity: &Quantity<V>) -> Self::Output {
415 self * *quantity
416 }
417}
418
419impl<U, V> Mul<&Quantity<V>> for &Quantity<U>
420where
421 U: UnitMul<V>,
422{
423 type Output = Quantity<<U as UnitMul<V>>::Output>;
424 fn mul(self, quantity: &Quantity<V>) -> Self::Output {
425 *self * *quantity
426 }
427}
428
429impl<V> Mul<&Quantity<V>> for TensorRank0 {
430 type Output = Quantity<V>;
431 fn mul(self, quantity: &Quantity<V>) -> Self::Output {
432 Quantity::new(self * quantity.0)
433 }
434}
435
436impl<V> Mul<&Quantity<V>> for &TensorRank0 {
437 type Output = Quantity<V>;
438 fn mul(self, quantity: &Quantity<V>) -> Self::Output {
439 Quantity::new(self * quantity.0)
440 }
441}
442
443impl Add<TensorRank0> for Quantity<Dimensionless> {
444 type Output = Self;
445 fn add(self, tensor_rank_0: TensorRank0) -> Self::Output {
446 Self::new(self.0 + tensor_rank_0)
447 }
448}
449
450impl Add<Quantity<Dimensionless>> for TensorRank0 {
451 type Output = Quantity<Dimensionless>;
452 fn add(self, quantity: Quantity<Dimensionless>) -> Self::Output {
453 Quantity::new(self + quantity.0)
454 }
455}
456
457impl Sub<TensorRank0> for Quantity<Dimensionless> {
458 type Output = Self;
459 fn sub(self, tensor_rank_0: TensorRank0) -> Self::Output {
460 Self::new(self.0 - tensor_rank_0)
461 }
462}
463
464impl Sub<Quantity<Dimensionless>> for TensorRank0 {
465 type Output = Quantity<Dimensionless>;
466 fn sub(self, quantity: Quantity<Dimensionless>) -> Self::Output {
467 Quantity::new(self - quantity.0)
468 }
469}
470
471impl PartialEq<TensorRank0> for Quantity<Dimensionless> {
472 fn eq(&self, tensor_rank_0: &TensorRank0) -> bool {
473 &self.0 == tensor_rank_0
474 }
475}
476
477impl PartialEq<Quantity<Dimensionless>> for TensorRank0 {
478 fn eq(&self, quantity: &Quantity<Dimensionless>) -> bool {
479 self == &quantity.0
480 }
481}
482
483impl PartialOrd<TensorRank0> for Quantity<Dimensionless> {
484 fn partial_cmp(&self, tensor_rank_0: &TensorRank0) -> Option<std::cmp::Ordering> {
485 self.0.partial_cmp(tensor_rank_0)
486 }
487}
488
489impl PartialOrd<Quantity<Dimensionless>> for TensorRank0 {
490 fn partial_cmp(&self, quantity: &Quantity<Dimensionless>) -> Option<std::cmp::Ordering> {
491 self.partial_cmp(&quantity.0)
492 }
493}
494
495impl<U> Div<Quantity<U>> for TensorRank0
496where
497 U: UnitInv,
498{
499 type Output = Quantity<<U as UnitInv>::Output>;
500 fn div(self, quantity: Quantity<U>) -> Self::Output {
501 Quantity::new(self / quantity.0)
502 }
503}
504
505impl<U> std::iter::Sum for Quantity<U> {
506 fn sum<I>(iter: I) -> Self
507 where
508 I: Iterator<Item = Self>,
509 {
510 Self::new(iter.map(|quantity| quantity.0).sum())
511 }
512}
513
514impl<'a, U> std::iter::Sum<&'a Quantity<U>> for Quantity<U> {
515 fn sum<I>(iter: I) -> Self
516 where
517 I: Iterator<Item = &'a Quantity<U>>,
518 {
519 Self::new(iter.map(|quantity| quantity.0).sum())
520 }
521}
522
523impl<U> Erase for Quantity<U> {
524 type Erased = TensorRank0;
525 fn erase(&self) -> &Self::Erased {
526 &self.0
527 }
528}
529
530impl<U> Tensor for Quantity<U> {
531 type Item = Self;
532 type Unit = U;
533 fn error_count_zero(&self, tol_abs: TensorRank0, tol_rel: TensorRank0) -> Option<usize> {
534 self.0.error_count_zero(tol_abs, tol_rel)
535 }
536 fn error_count(
537 &self,
538 other: &Self,
539 tol_abs: TensorRank0,
540 tol_rel: TensorRank0,
541 ) -> Option<usize> {
542 self.0.error_count(&other.0, tol_abs, tol_rel)
543 }
544 fn full_contraction(&self, quantity: &Self) -> TensorRank0 {
545 self.0 * quantity.0
546 }
547 fn is_zero(&self) -> bool {
548 self.0 == 0.0
549 }
550 fn iter(&self) -> impl Iterator<Item = &Self::Item> {
551 std::slice::from_ref(self).iter()
552 }
553 fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item> {
554 std::slice::from_mut(self).iter_mut()
555 }
556 fn len(&self) -> usize {
557 1
558 }
559 fn norm_inf(&self) -> Quantity<U> {
560 Self::new(self.0.abs())
561 }
562 fn norm_l1(&self) -> Quantity<U> {
563 Self::new(self.0.abs())
564 }
565 fn norm_p_sum(&self, p: TensorRank0) -> TensorRank0 {
566 self.0.abs().powf(p)
567 }
568 fn size(&self) -> usize {
569 1
570 }
571 fn sub_abs(&self, other: &Self) -> Self {
572 Self::new((self.0 - other.0).abs())
573 }
574 fn sub_rel(&self, other: &Self) -> Self {
575 Self::new(self.0.sub_rel(&other.0))
576 }
577}
578
579impl<U> TensorArray for Quantity<U> {
580 type Array = TensorRank0;
581 type Item = Self;
582 fn as_array(&self) -> Self::Array {
583 self.0
584 }
585 fn identity() -> Self {
586 Self::new(1.0)
587 }
588 fn zero() -> Self {
589 Self::new(0.0)
590 }
591}
592
593impl<U> FiniteDifference for Quantity<U> {
594 fn error_fd(&self, comparator: &Self, epsilon: TensorRank0) -> Option<(bool, usize)> {
595 self.0.error_fd(&comparator.0, epsilon)
596 }
597}
598
599impl<U, const N: usize> FiniteDifference for TensorList<Quantity<U>, N> {
600 fn error_fd(&self, comparator: &Self, epsilon: TensorRank0) -> Option<(bool, usize)> {
601 error_fd_over(self.iter().zip(comparator.iter()), epsilon)
602 }
603}
604
605impl<U, const M: usize, const N: usize> FiniteDifference
606 for TensorList<TensorList<Quantity<U>, N>, M>
607{
608 fn error_fd(&self, comparator: &Self, epsilon: TensorRank0) -> Option<(bool, usize)> {
609 error_fd_over(
610 self.iter()
611 .zip(comparator.iter())
612 .flat_map(|(entry, comparator_entry)| entry.iter().zip(comparator_entry.iter())),
613 epsilon,
614 )
615 }
616}
617
618fn error_fd_over<'a, U: 'a>(
619 entries: impl Iterator<Item = (&'a Quantity<U>, &'a Quantity<U>)>,
620 epsilon: TensorRank0,
621) -> Option<(bool, usize)> {
622 let error_count = entries
623 .filter_map(|(entry, comparator_entry)| entry.error_fd(comparator_entry, epsilon))
624 .map(|(_, count)| count)
625 .sum();
626 if error_count > 0 {
627 Some((true, error_count))
628 } else {
629 None
630 }
631}
632
633impl<U> Solution for Quantity<U> {
634 fn decrement_from(&mut self, _other: &Vector) {
635 unimplemented!()
636 }
637 fn decrement_from_chained(&mut self, _other: &mut Vector, _vector: &Vector) {
638 unimplemented!()
639 }
640}
641
642impl<U> Hessian for Quantity<U> {
643 fn quadratic_form(&self, vector: &Vector) -> TensorRank0 {
644 self.0 * vector[0] * vector[0]
645 }
646 fn entry(&self, _row: usize, _column: usize) -> TensorRank0 {
647 unimplemented!()
648 }
649 fn fill_into(self, _square_matrix: &mut SquareMatrix) {
650 unimplemented!()
651 }
652}
653
654impl<U> Jacobian for Quantity<U> {
655 fn fill_into(&self, _vector: &mut Vector) {
656 unimplemented!()
657 }
658 fn fill_into_chained(self, _other: Vector, _vector: &mut Vector) {
659 unimplemented!()
660 }
661}
662
663impl<U> Sub<Vector> for Quantity<U> {
664 type Output = Self;
665 fn sub(self, _vector: Vector) -> Self::Output {
666 unimplemented!()
667 }
668}
669
670impl<U> Sub<&Vector> for Quantity<U> {
671 type Output = Self;
672 fn sub(self, _vector: &Vector) -> Self::Output {
673 unimplemented!()
674 }
675}
676
677impl<U> From<Vector> for Quantity<U> {
678 fn from(_vector: Vector) -> Self {
679 unimplemented!()
680 }
681}
682
683impl<U, T> Differentiate<T> for Quantity<U>
684where
685 U: UnitDiv<T>,
686{
687 type Derivative = Quantity<<U as UnitDiv<T>>::Output>;
688}