1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
use crate::{IntExt, RealExt, SimulationError, XResult, simulation::prelude::Moment};
/// Discrete process trait
pub trait DiscreteProcess<N: IntExt = usize, X: RealExt = f64>: Send + Sync {
/// Get the starting position
fn start(&self) -> X;
/// Get the ending position
fn end(&self, num_step: N) -> XResult<X> {
Ok(self.start() + self.displacement(num_step)?)
}
/// Get the displacement of the discrete process
///
/// # Arguments
///
/// * `num_step` - The number of steps of the simulation.
fn displacement(&self, num_step: N) -> XResult<X> {
let x = self.simulate(num_step)?;
let first_position = x.first();
let end_position = x.last();
match (first_position, end_position) {
(Some(initial), Some(position)) => Ok(*position - *initial),
_ => Err(SimulationError::Unknown.into()),
}
}
/// Simulate the discrete process
///
/// # Arguments
///
/// * `num_step` - The number of steps of the simulation.
fn simulate(&self, num_step: N) -> XResult<Vec<X>>;
/// Get the mean of the discrete process
///
/// # Arguments
///
/// * `num_step` - The number of steps of the simulation.
/// * `particles` - The number of particles.
fn mean(&self, num_step: N, particles: usize) -> XResult<f64>
where
Self: DiscreteTrajectoryTrait<N, X>,
{
let traj = self.step(num_step)?;
traj.raw_moment(1, particles, 0.1)
}
/// Get the mean square displacement of the discrete process
///
/// # Arguments
///
/// * `num_step` - The number of steps of the simulation.
/// * `particles` - The number of particles.
fn msd(&self, num_step: N, particles: usize) -> XResult<f64>
where
Self: DiscreteTrajectoryTrait<N, X>,
{
let traj = self.step(num_step)?;
traj.msd(particles, 0.1)
}
/// Get the raw moment of the discrete process
///
/// # Arguments
///
/// * `num_step` - The number of steps.
/// * `order` - The order of the moment.
/// * `particles` - The number of particles.
fn raw_moment(&self, num_step: N, order: i32, particles: usize) -> XResult<f64>
where
Self: DiscreteTrajectoryTrait<N, X>,
{
let traj = self.step(num_step)?;
traj.raw_moment(order, particles, 0.1)
}
/// Get the central moment of the discrete process
///
/// # Arguments
///
/// * `num_step` - The number of steps.
/// * `order` - The order of the moment.
/// * `particles` - The number of particles.
fn central_moment(&self, num_step: N, order: i32, particles: usize) -> XResult<f64>
where
Self: DiscreteTrajectoryTrait<N, X>,
{
let traj = self.step(num_step)?;
traj.central_moment(order, particles, 0.1)
}
/// Get the fractional raw moment of the discrete process
///
/// # Arguments
///
/// * `num_step` - The number of steps.
/// * `order` - The order of the moment.
/// * `particles` - The number of particles.
fn frac_raw_moment(&self, num_step: N, order: f64, particles: usize) -> XResult<f64>
where
Self: DiscreteTrajectoryTrait<N, X>,
{
let traj = self.step(num_step)?;
traj.frac_raw_moment(order, particles, 0.1)
}
/// Get the fractional central moment of the discrete process
///
/// # Arguments
///
/// * `num_step` - The number of steps.
/// * `order` - The order of the moment.
/// * `particles` - The number of particles.
fn frac_central_moment(&self, num_step: N, order: f64, particles: usize) -> XResult<f64>
where
Self: DiscreteTrajectoryTrait<N, X>,
{
let traj = self.step(num_step)?;
traj.frac_central_moment(order, particles, 0.1)
}
}
pub trait DiscreteTrajectoryTrait<N: IntExt = usize, X: RealExt = f64>:
DiscreteProcess<N, X> + Clone
{
/// Create a `DiscreteTrajectory` with given number of steps
///
/// # Arguments
///
/// * `num_step` - The number of steps of the trajectory
fn step(&self, num_step: N) -> XResult<DiscreteTrajectory<Self, N, X>> {
let traj = DiscreteTrajectory::new(self.clone(), num_step)?;
Ok(traj)
}
}
impl<SP: DiscreteProcess<N, X> + Clone, N: IntExt, X: RealExt> DiscreteTrajectoryTrait<N, X>
for SP
{
}
/// Discrete trajectory
#[derive(Debug, Clone)]
pub struct DiscreteTrajectory<
SP: DiscreteProcess<N, X> + Clone,
N: IntExt = usize,
X: RealExt = f64,
> {
/// The discrete process
pub(crate) sp: SP,
/// The number of steps
pub(crate) num_step: N,
pub(crate) _marker: std::marker::PhantomData<X>,
}
impl<SP: DiscreteProcess<N, X> + Clone, N: IntExt, X: RealExt> DiscreteTrajectory<SP, N, X> {
/// Create a new `DiscreteTrajetory` with given `DiscreteProcess` and num of steps.
pub fn new(sp: SP, num_step: N) -> XResult<Self> {
if num_step == N::zero() {
return Err(SimulationError::InvalidParameters(
"num_step must be positive".to_string(),
)
.into());
}
Ok(Self {
sp,
num_step,
_marker: std::marker::PhantomData,
})
}
/// Get the discrete process
pub fn get_process(&self) -> &SP {
&self.sp
}
/// Get the number of steps of the trajectory
pub fn get_num_step(&self) -> N {
self.num_step
}
/// Simulate method
pub fn simulate(&self) -> XResult<Vec<X>> {
self.sp.simulate(self.num_step)
}
}