lattice_qcd_rs/simulation/monte_carlo/
hybrid.rs

1//! Combine multiple Monte Carlo methods.
2//!
3//! this module present different ways to combine multiple method
4//!
5//! # Example
6//! ```
7//! # use std::error::Error;
8//! #
9//! # fn main() -> Result<(), Box<dyn Error>> {
10//! use lattice_qcd_rs::simulation::{HeatBathSweep, LatticeState, LatticeStateDefault, OverrelaxationSweepReverse, HybridMethodVec};
11//! use rand::SeedableRng;
12//!
13//! let rng = rand::rngs::StdRng::seed_from_u64(0); // change with your seed
14//! let mut heat_bath = HeatBathSweep::new(rng);
15//! let mut overrelax = OverrelaxationSweepReverse::default();
16//! let mut hybrid = HybridMethodVec::with_capacity(2);
17//! hybrid.push_method(&mut heat_bath);
18//! hybrid.push_method(&mut overrelax);
19//!
20//! let mut state = LatticeStateDefault::<3>::new_cold(1_f64, 8_f64, 4)?; // 1_f64 : size, 8_f64: beta, 4 number of points.
21//! for _ in 0..2 {
22//!     state = state.monte_carlo_step(&mut hybrid)?;
23//!     // operation to track the progress or the evolution
24//! }
25//! // operation at the end of the simulation
26//! #     Ok(())
27//! # }
28//! ```
29
30use core::fmt::{Debug, Display};
31use std::error::Error;
32use std::marker::PhantomData;
33use std::vec::Vec;
34
35#[cfg(feature = "serde-serialize")]
36use serde::{Deserialize, Serialize};
37
38use super::{super::state::LatticeState, MonteCarlo};
39
40/// Error given by [`HybridMethodVec`]
41#[non_exhaustive]
42#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
43#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
44pub enum HybridMethodVecError<Error> {
45    /// An Error coming from one of the method.
46    ///
47    /// the first field usize gives the position of the method giving the error
48    Error(usize, Error),
49    /// No method founds, give back the ownership of the state.
50    NoMethod,
51}
52
53impl<Error: Display> Display for HybridMethodVecError<Error> {
54    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55        match self {
56            Self::NoMethod => write!(f, "no monte carlo method"),
57            Self::Error(index, error) => {
58                write!(f, "error during integration step {}: {}", index, error)
59            }
60        }
61    }
62}
63
64impl<E: Display + Debug + Error + 'static> Error for HybridMethodVecError<E> {
65    fn source(&self) -> Option<&(dyn Error + 'static)> {
66        match self {
67            Self::NoMethod => None,
68            Self::Error(_, error) => Some(error),
69        }
70    }
71}
72
73/// Adaptor used to convert the error to another type. It is intended to use with [`HybridMethodVec`].
74#[derive(PartialEq, Eq, Debug)]
75pub struct AdaptorMethodError<'a, MC, State, ErrorBase, Error, const D: usize>
76where
77    MC: MonteCarlo<State, D, Error = ErrorBase> + ?Sized,
78    ErrorBase: Into<Error>,
79    State: LatticeState<D>,
80{
81    data: &'a mut MC,
82    _phantom: PhantomData<(&'a State, &'a ErrorBase, &'a Error)>,
83}
84
85impl<'a, MC, State, ErrorBase, Error, const D: usize>
86    AdaptorMethodError<'a, MC, State, ErrorBase, Error, D>
87where
88    MC: MonteCarlo<State, D, Error = ErrorBase> + ?Sized,
89    ErrorBase: Into<Error>,
90    State: LatticeState<D>,
91{
92    /// Create the Self using a mutable reference.
93    pub fn new(data: &'a mut MC) -> Self {
94        Self {
95            data,
96            _phantom: PhantomData,
97        }
98    }
99
100    /// Getter for the reference hold by self.
101    pub fn data_mut(&mut self) -> &mut MC {
102        self.data
103    }
104
105    /// Getter for the reference hold by self.
106    pub const fn data(&self) -> &MC {
107        self.data
108    }
109}
110
111impl<'a, MC, State, ErrorBase, Error, const D: usize> AsMut<MC>
112    for AdaptorMethodError<'a, MC, State, ErrorBase, Error, D>
113where
114    MC: MonteCarlo<State, D, Error = ErrorBase> + ?Sized,
115    ErrorBase: Into<Error>,
116    State: LatticeState<D>,
117{
118    fn as_mut(&mut self) -> &mut MC {
119        self.data_mut()
120    }
121}
122
123impl<'a, MC, State, ErrorBase, Error, const D: usize> AsRef<MC>
124    for AdaptorMethodError<'a, MC, State, ErrorBase, Error, D>
125where
126    MC: MonteCarlo<State, D, Error = ErrorBase> + ?Sized,
127    ErrorBase: Into<Error>,
128    State: LatticeState<D>,
129{
130    fn as_ref(&self) -> &MC {
131        self.data()
132    }
133}
134
135impl<'a, MC, State, ErrorBase, Error, const D: usize> MonteCarlo<State, D>
136    for AdaptorMethodError<'a, MC, State, ErrorBase, Error, D>
137where
138    MC: MonteCarlo<State, D, Error = ErrorBase> + ?Sized,
139    ErrorBase: Into<Error>,
140    State: LatticeState<D>,
141{
142    type Error = Error;
143
144    #[inline]
145    fn next_element(&mut self, state: State) -> Result<State, Self::Error> {
146        self.data.next_element(state).map_err(|err| err.into())
147    }
148}
149
150/// hybrid method that combine multiple methods. It requires that all methods return the same error.
151/// You can use [`AdaptorMethodError`] to convert the error.
152/// If you want type with different error you can use [`HybridMethodCouple`].
153///
154/// # Example
155/// see level module example [`super`].
156pub struct HybridMethodVec<'a, State, E, const D: usize>
157where
158    State: LatticeState<D>,
159{
160    methods: Vec<&'a mut dyn MonteCarlo<State, D, Error = E>>,
161}
162
163impl<'a, State, E, const D: usize> HybridMethodVec<'a, State, E, D>
164where
165    State: LatticeState<D>,
166{
167    getter!(
168        /// get the methods
169        pub,
170        methods,
171        Vec<&'a mut dyn MonteCarlo<State, D, Error = E>>
172    );
173
174    /// Create an empty Self.
175    pub fn new_empty() -> Self {
176        Self {
177            methods: Vec::new(),
178        }
179    }
180
181    /// Create an empty Self where the vector is preallocated for `capacity` element.
182    pub fn with_capacity(capacity: usize) -> Self {
183        Self {
184            methods: Vec::with_capacity(capacity),
185        }
186    }
187
188    /// Create a new Self from a list of [`MonteCarlo`]
189    pub fn new(methods: Vec<&'a mut dyn MonteCarlo<State, D, Error = E>>) -> Self {
190        Self { methods }
191    }
192
193    /// Get a mutable reference to the methods used,
194    pub fn methods_mut(&mut self) -> &mut Vec<&'a mut dyn MonteCarlo<State, D, Error = E>> {
195        &mut self.methods
196    }
197
198    /// Add a method at the end.
199    pub fn push_method(&mut self, mc_ref: &'a mut dyn MonteCarlo<State, D, Error = E>) {
200        self.methods.push(mc_ref);
201    }
202
203    /// Remove a method at the end an returns it. Return None if the methods is empty.
204    pub fn pop_method(&mut self) -> Option<&'a mut dyn MonteCarlo<State, D, Error = E>> {
205        self.methods.pop()
206    }
207
208    /// Get the number of methods
209    pub fn len(&self) -> usize {
210        self.methods.len()
211    }
212
213    /// Return wether the number is zero.
214    pub fn is_empty(&self) -> bool {
215        self.methods.is_empty()
216    }
217}
218
219impl<'a, State, E, const D: usize> AsRef<Vec<&'a mut dyn MonteCarlo<State, D, Error = E>>>
220    for HybridMethodVec<'a, State, E, D>
221where
222    State: LatticeState<D>,
223{
224    fn as_ref(&self) -> &Vec<&'a mut dyn MonteCarlo<State, D, Error = E>> {
225        self.methods()
226    }
227}
228
229impl<'a, State, E, const D: usize> AsMut<Vec<&'a mut dyn MonteCarlo<State, D, Error = E>>>
230    for HybridMethodVec<'a, State, E, D>
231where
232    State: LatticeState<D>,
233{
234    fn as_mut(&mut self) -> &mut Vec<&'a mut dyn MonteCarlo<State, D, Error = E>> {
235        self.methods_mut()
236    }
237}
238
239impl<'a, State, E, const D: usize> Default for HybridMethodVec<'a, State, E, D>
240where
241    State: LatticeState<D>,
242{
243    fn default() -> Self {
244        Self::new_empty()
245    }
246}
247
248impl<'a, State, E, const D: usize> MonteCarlo<State, D> for HybridMethodVec<'a, State, E, D>
249where
250    State: LatticeState<D>,
251{
252    type Error = HybridMethodVecError<E>;
253
254    #[inline]
255    fn next_element(&mut self, mut state: State) -> Result<State, Self::Error> {
256        if self.methods.is_empty() {
257            return Err(HybridMethodVecError::NoMethod);
258        }
259        for (index, m) in &mut self.methods.iter_mut().enumerate() {
260            let result = state.monte_carlo_step(*m);
261            match result {
262                Ok(new_state) => state = new_state,
263                Err(error) => return Err(HybridMethodVecError::Error(index, error)),
264            }
265        }
266        Ok(state)
267    }
268}
269
270/// Error given by [`HybridMethodCouple`]
271#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
272#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
273pub enum HybridMethodCoupleError<Error1, Error2> {
274    /// First method gave an error
275    ErrorFirst(Error1),
276    /// Second method gave an error
277    ErrorSecond(Error2),
278}
279
280impl<Error1: Display, Error2: Display> Display for HybridMethodCoupleError<Error1, Error2> {
281    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
282        match self {
283            Self::ErrorFirst(error) => write!(f, "error during integration step 1: {}", error),
284            Self::ErrorSecond(error) => write!(f, "error during integration step 2: {}", error),
285        }
286    }
287}
288
289impl<Error1: Display + Error + 'static, Error2: Display + Error + 'static> Error
290    for HybridMethodCoupleError<Error1, Error2>
291{
292    fn source(&self) -> Option<&(dyn Error + 'static)> {
293        match self {
294            Self::ErrorFirst(error) => Some(error),
295            Self::ErrorSecond(error) => Some(error),
296        }
297    }
298}
299
300/// This method can combine any two methods. The down side is that it can be very verbose to write
301/// Couples for a large number of methods.
302///
303/// # Example
304/// ```
305/// # use std::error::Error;
306/// #
307/// # fn main() -> Result<(), Box<dyn Error>> {
308/// use lattice_qcd_rs::simulation::{HeatBathSweep, LatticeState, LatticeStateDefault, OverrelaxationSweepReverse, HybridMethodCouple};
309/// use rand::SeedableRng;
310///
311/// let rng = rand::rngs::StdRng::seed_from_u64(0); // change with your seed
312/// let heat_bath = HeatBathSweep::new(rng);
313/// let overrelax = OverrelaxationSweepReverse::default();
314/// let mut couple = HybridMethodCouple::new(heat_bath,overrelax);
315///
316/// let mut state = LatticeStateDefault::<3>::new_cold(1_f64, 8_f64, 4)?; // 1_f64 : size, 8_f64: beta, 4 number of points.
317/// for _ in 0..2 {
318///     state = state.monte_carlo_step(&mut couple)?;
319///     // operation to track the progress or the evolution
320/// }
321/// // operation at the end of the simulation
322/// #     Ok(())
323/// # }
324/// ```
325#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
326#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
327pub struct HybridMethodCouple<MC1, Error1, MC2, Error2, State, const D: usize>
328where
329    MC1: MonteCarlo<State, D, Error = Error1>,
330    MC2: MonteCarlo<State, D, Error = Error2>,
331    State: LatticeState<D>,
332{
333    method_1: MC1,
334    method_2: MC2,
335    _phantom: PhantomData<(State, Error1, Error2)>,
336}
337
338impl<MC1, Error1, MC2, Error2, State, const D: usize>
339    HybridMethodCouple<MC1, Error1, MC2, Error2, State, D>
340where
341    MC1: MonteCarlo<State, D, Error = Error1>,
342    MC2: MonteCarlo<State, D, Error = Error2>,
343    State: LatticeState<D>,
344{
345    getter!(
346        /// get the first method
347        pub const,
348        method_1,
349        MC1
350    );
351
352    getter!(
353        /// get the second method
354        pub const,
355        method_2,
356        MC2
357    );
358
359    /// Create a new Self from two methods
360    pub const fn new(method_1: MC1, method_2: MC2) -> Self {
361        Self {
362            method_1,
363            method_2,
364            _phantom: PhantomData,
365        }
366    }
367
368    /// Deconstruct the structure ang gives back both methods
369    #[allow(clippy::missing_const_for_fn)] // false positive
370    pub fn deconstruct(self) -> (MC1, MC2) {
371        (self.method_1, self.method_2)
372    }
373}
374
375impl<MC1, Error1, MC2, Error2, State, const D: usize> MonteCarlo<State, D>
376    for HybridMethodCouple<MC1, Error1, MC2, Error2, State, D>
377where
378    MC1: MonteCarlo<State, D, Error = Error1>,
379    MC2: MonteCarlo<State, D, Error = Error2>,
380    State: LatticeState<D>,
381{
382    type Error = HybridMethodCoupleError<Error1, Error2>;
383
384    #[inline]
385    fn next_element(&mut self, mut state: State) -> Result<State, Self::Error> {
386        state = state
387            .monte_carlo_step(&mut self.method_1)
388            .map_err(HybridMethodCoupleError::ErrorFirst)?;
389        state
390            .monte_carlo_step(&mut self.method_2)
391            .map_err(HybridMethodCoupleError::ErrorSecond)
392    }
393}
394
395/// Combine three methods.
396pub type HybridMethodTriple<MC1, Error1, MC2, Error2, MC3, Error3, State, const D: usize> =
397    HybridMethodCouple<
398        HybridMethodCouple<MC1, Error1, MC2, Error2, State, D>,
399        HybridMethodCoupleError<Error1, Error2>,
400        MC3,
401        Error3,
402        State,
403        D,
404    >;
405
406/// Error returned by [`HybridMethodTriple`].
407pub type HybridMethodTripleError<Error1, Error2, Error3> =
408    HybridMethodCoupleError<HybridMethodCoupleError<Error1, Error2>, Error3>;
409
410/// Combine four methods.
411pub type HybridMethodQuadruple<
412    MC1,
413    Error1,
414    MC2,
415    Error2,
416    MC3,
417    Error3,
418    MC4,
419    Error4,
420    State,
421    const D: usize,
422> = HybridMethodCouple<
423    HybridMethodTriple<MC1, Error1, MC2, Error2, MC3, Error3, State, D>,
424    HybridMethodTripleError<Error1, Error2, Error3>,
425    MC4,
426    Error4,
427    State,
428    D,
429>;
430
431/// Error returned by [`HybridMethodQuadruple`].
432pub type HybridMethodQuadrupleError<Error1, Error2, Error3, Error4> =
433    HybridMethodCoupleError<HybridMethodTripleError<Error1, Error2, Error3>, Error4>;
434
435/// Combine four methods.
436pub type HybridMethodQuintuple<
437    MC1,
438    Error1,
439    MC2,
440    Error2,
441    MC3,
442    Error3,
443    MC4,
444    Error4,
445    MC5,
446    Error5,
447    State,
448    const D: usize,
449> = HybridMethodCouple<
450    HybridMethodQuadruple<MC1, Error1, MC2, Error2, MC3, Error3, MC4, Error4, State, D>,
451    HybridMethodQuadrupleError<Error1, Error2, Error3, Error4>,
452    MC5,
453    Error5,
454    State,
455    D,
456>;
457
458/// Error returned by [`HybridMethodQuintuple`].
459pub type HybridMethodQuintupleError<Error1, Error2, Error3, Error4, Error5> =
460    HybridMethodCoupleError<HybridMethodQuadrupleError<Error1, Error2, Error3, Error4>, Error5>;