differential_equations/
traits.rs

1//! Defines Generics for the library. Includes generics for the floating point numbers.
2
3use nalgebra::{RealField, SMatrix};
4use num_complex::Complex;
5use std::{fmt::Debug, ops::{Add, AddAssign, Div, Mul, Sub}};
6
7/// Real Number Trait
8///
9/// This trait specifies the acceptable types for real numbers.
10/// Currently implemented for:
11/// * `f32` - 32-bit floating point
12/// * `f64` - 64-bit floating point
13///
14/// Provides additional functionality required for ODE solvers beyond
15/// what's provided by nalgebra's RealField trait.
16///
17pub trait Real: Copy + RealField {
18    fn infinity() -> Self;
19}
20
21impl Real for f32 {
22    fn infinity() -> Self {
23        f32::INFINITY
24    }
25}
26
27impl Real for f64 {
28    fn infinity() -> Self {
29        f64::INFINITY
30    }
31}
32
33/// State vector trait
34///
35/// Represents the state of the system being solved.
36///
37/// Implements for the following types:
38/// * `f32` - 32-bit floating point
39/// * `f64` - 64-bit floating point
40/// * `SMatrix` - Matrix type from nalgebra
41/// * `Complex` - Complex number type from num-complex
42/// * `Struct<T>` - Any struct with all fields of type T using #[derive(State)] from the `derive` module
43///
44pub trait State<T: Real>:
45    Clone
46    + Copy
47    + Debug
48    + Add<Output = Self>
49    + Sub<Output = Self>
50    + AddAssign
51    + Mul<T, Output = Self>
52    + Div<T, Output = Self>
53{
54    fn len(&self) -> usize;
55
56    fn get(&self, i: usize) -> T;
57
58    fn set(&mut self, i: usize, value: T);
59
60    fn zeros() -> Self;
61}
62
63impl<T: Real> State<T> for T {
64    fn len(&self) -> usize {
65        1
66    }
67
68    fn get(&self, i: usize) -> T {
69        if i == 0 {
70            *self
71        } else {
72            panic!("Index out of bounds")
73        }
74    }
75
76    fn set(&mut self, i: usize, value: T) {
77        if i == 0 {
78            *self = value;
79        } else {
80            panic!("Index out of bounds")
81        }
82    }
83
84    fn zeros() -> Self {
85        T::zero()
86    }
87}
88
89impl<T, const R: usize, const C: usize> State<T> for SMatrix<T, R, C>
90where
91    T: Real,
92{
93    fn len(&self) -> usize {
94        R * C
95    }
96
97    fn get(&self, i: usize) -> T {
98        if i < self.len() {
99            self[(i / C, i % C)]
100        } else {
101            panic!("Index out of bounds")
102        }
103    }
104
105    fn set(&mut self, i: usize, value: T) {
106        if i < self.len() {
107            self[(i / C, i % C)] = value;
108        } else {
109            panic!("Index out of bounds")
110        }
111    }
112
113    fn zeros() -> Self {
114        SMatrix::<T, R, C>::zeros()
115    }
116}
117
118impl<T> State<T> for Complex<T>
119where
120    T: Real,
121{
122    fn len(&self) -> usize {
123        2
124    }
125
126    fn get(&self, i: usize) -> T {
127        if i == 0 {
128            self.re
129        } else if i == 1 {
130            self.im
131        } else {
132            panic!("Index out of bounds")
133        }
134    }
135
136    fn set(&mut self, i: usize, value: T) {
137        if i == 0 {
138            self.re = value;
139        } else if i == 1 {
140            self.im = value;
141        } else {
142            panic!("Index out of bounds")
143        }
144    }
145
146    fn zeros() -> Self {
147        Complex::new(T::zero(), T::zero())
148    }
149}
150
151/// Callback data trait
152///
153/// This trait represents data that can be returned from functions
154/// that are used to control the solver's execution flow. The
155/// Clone and Debug traits are required for internal use but anything
156/// that implements this trait can be used as callback data.
157/// For example, this can be a string, a number, or any other type
158/// that implements the Clone and Debug traits.
159///
160pub trait CallBackData: Clone + std::fmt::Debug {}
161
162// Implement for any type that already satisfies the bounds
163impl<T: Clone + std::fmt::Debug> CallBackData for T {}