differential_equations/
stats.rs

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