differential_equations/
stats.rs

1//! Statistics and performance tracking for Numerical methods
2
3use crate::traits::Real;
4use std::{
5    ops::{Add, AddAssign},
6    time::Instant,
7};
8
9/// Number of evaluations
10///
11/// # Fields
12/// * `function` - Number of function evaluations
13/// * `jacobian` - Number of jacobian evaluations
14/// * `newton` - Number of Newton iterations
15///
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
17pub struct Evals {
18    pub function: usize,
19    pub jacobian: usize,
20    pub newton: usize,
21}
22
23impl Evals {
24    /// Create a new Evals struct
25    ///
26    /// # Arguments
27    /// * `diff` - Number of differntial equation function evaluations
28    /// * `jacobian`  - Number of jacobian evaluations
29    /// * `newton` - Number of Newton iterations
30    pub fn new() -> Self {
31        Self {
32            function: 0,
33            jacobian: 0,
34            newton: 0,
35        }
36    }
37}
38
39impl Add for Evals {
40    type Output = Self;
41
42    fn add(self, other: Self) -> Self {
43        Self {
44            function: self.function + other.function,
45            jacobian: self.jacobian + other.jacobian,
46            newton: self.newton + other.newton,
47        }
48    }
49}
50
51impl AddAssign for Evals {
52    fn add_assign(&mut self, other: Self) {
53        self.function += other.function;
54        self.jacobian += other.jacobian;
55        self.newton += other.newton;
56    }
57}
58
59/// Number of Steps
60///
61/// # Fields
62/// * `accepted` - Number of accepted steps
63/// * `rejected` - Number of rejected steps
64///
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
66pub struct Steps {
67    pub accepted: usize,
68    pub rejected: usize,
69}
70
71impl Steps {
72    /// Create a new Steps struct
73    pub fn new() -> Self {
74        Self {
75            accepted: 0,
76            rejected: 0,
77        }
78    }
79
80    /// Get the total number of steps (accepted + rejected)
81    pub fn total(&self) -> usize {
82        self.accepted + self.rejected
83    }
84}
85
86impl Add for Steps {
87    type Output = Self;
88
89    fn add(self, other: Self) -> Self {
90        Self {
91            accepted: self.accepted + other.accepted,
92            rejected: self.rejected + other.rejected,
93        }
94    }
95}
96
97impl AddAssign for Steps {
98    fn add_assign(&mut self, other: Self) {
99        self.accepted += other.accepted;
100        self.rejected += other.rejected;
101    }
102}
103
104/// Timer for tracking solution time
105#[derive(Debug, Clone)]
106pub enum Timer<T: Real> {
107    Off,
108    Running(Instant),
109    Completed(T),
110}
111
112impl<T: Real> Timer<T> {
113    /// Starts the timer
114    pub fn start(&mut self) {
115        *self = Timer::Running(Instant::now());
116    }
117
118    /// Returns the elapsed time in seconds
119    pub fn elapsed(&self) -> T {
120        match self {
121            Timer::Off => T::zero(),
122            Timer::Running(start_time) => T::from_f64(start_time.elapsed().as_secs_f64()).unwrap(),
123            Timer::Completed(t) => *t,
124        }
125    }
126
127    /// Complete the running timer and convert it to a completed state
128    pub fn complete(&mut self) {
129        match self {
130            Timer::Off => {}
131            Timer::Running(start_time) => {
132                *self = Timer::Completed(T::from_f64(start_time.elapsed().as_secs_f64()).unwrap());
133            }
134            Timer::Completed(_) => {}
135        }
136    }
137}