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
use rand::rngs::SmallRng;
use crate::{algorithm::Algorithm, lattice::Lattice};
pub struct Simulation {
rng: SmallRng,
lattice: Lattice,
// Cache temperature to only send new temperatures to the algorithm.
temperature: f64,
algorithm: Box<dyn Algorithm>,
}
impl Simulation {
/// Creates a new simulation.
///
/// # Examples
/// ## Builtin algorithm types
/// ```
/// use rand::{rngs::SmallRng, SeedableRng};
/// use ising::{lattice::Lattice, Simulation, algorithm::AlgorithmType, CRITICAL_TEMPERATURE};
///
/// let side_length = 8;
/// let mut rng = SmallRng::seed_from_u64(42);
/// let lattice = Lattice::new(side_length, &mut rng);
///
/// let temperature = CRITICAL_TEMPERATURE;
/// let algorithm = AlgorithmType::Wolff.new_algorithm(&lattice, temperature);
///
/// let sim = Simulation::new(rng, lattice, temperature, algorithm);
///```
///
/// ## Custom algorithm types
/// You just have to wrap your initialized struct that implements `Algorithm` in a `Box<dyn Algorithm>`.
///
/// See also [`Algorithm`](crate::algorithm::Algorithm) for implementing the trait.
///
/// Lets assume that you did implement Metropolis yourself and that it is not a builtin algorithm:
/// ```
/// # use rand::{rngs::SmallRng, SeedableRng};
/// # use ising::{lattice::Lattice, Simulation, algorithm::AlgorithmType, CRITICAL_TEMPERATURE};
/// use ising::algorithm::{Algorithm, Metropolis};
///
/// # let side_length = 8;
/// # let mut rng = SmallRng::seed_from_u64(42);
/// # let lattice = Lattice::new(side_length, &mut rng);
/// #
/// # let temperature = CRITICAL_TEMPERATURE;
/// let algorithm: Box<dyn Algorithm> = Box::new(Metropolis::new(temperature));
///
/// let sim = Simulation::new(rng, lattice, temperature, algorithm);
///```
#[must_use]
pub fn new(
rng: SmallRng,
lattice: Lattice,
temperature: f64,
algorithm: Box<dyn Algorithm>,
) -> Self {
Self {
rng,
lattice,
temperature,
algorithm,
}
}
/// Sets a new random number generator.
pub fn set_rng(&mut self, rng: SmallRng) {
self.rng = rng;
}
/// Gets the lattice.
#[must_use]
pub const fn lattice(&self) -> &Lattice {
&self.lattice
}
/// Sets a new lattice.
pub fn set_lattice(&mut self, lattice: Lattice) {
self.lattice = lattice;
}
/// Gets the temperature.
#[must_use]
pub const fn temperature(&self) -> f64 {
self.temperature
}
/// Sets a new temperature.
pub fn set_temperature(&mut self, val: f64) {
// Only send a new temperature to the algorithm.
if self.temperature != val {
self.temperature = val;
self.algorithm.set_temperature(val);
}
}
/// Sets a new algorithm.
pub fn set_algorithm(&mut self, algorithm: Box<dyn Algorithm>) {
self.algorithm = algorithm;
}
/// Applies an algorithm step by calling [`Algorithm::step`](crate::algorithm::Algorithm::step).
pub fn step(&mut self) {
self.algorithm.step(&mut self.lattice, &mut self.rng);
}
}