lattice_qcd_rs/simulation/
state.rs

1//! Module containing the simulation State.
2//!
3//! The trait [`LatticeState`] is the most basic state with just the link matrices.
4//! The default implementation is [`LatticeStateDefault`].
5//! More over a more advance state with the color electrical field is given by
6//! the trait [`LatticeStateWithEField`] with the default implementation
7//! [`LatticeStateEFSyncDefault`]. Thw word "Sync" appears. It means that the simulation
8//! for the equation of movement are done at the same time for both the link matrices and
9//! the electric field. It is given by te trait [`SimulationStateSynchronous`]. It can also
10//! be done using the leapfrog method with the trait [`SimulationStateLeapFrog`]
11//! and the wrapper [`SimulationStateLeap`].
12//!
13//! See item documentation for more details.
14
15use crossbeam::thread;
16use na::{ComplexField, SVector};
17use rayon::iter::ParallelBridge;
18use rayon::prelude::*;
19#[cfg(feature = "serde-serialize")]
20use serde::{Deserialize, Serialize};
21
22use super::{
23    super::{
24        error::{
25            LatticeInitializationError, MultiIntegrationError, StateInitializationError,
26            ThreadedStateInitializationError,
27        },
28        field::{EField, LinkMatrix, Su3Adjoint},
29        integrator::SymplecticIntegrator,
30        lattice::{
31            Direction, DirectionList, LatticeCyclic, LatticeElementToIndex, LatticeLink,
32            LatticeLinkCanonical, LatticePoint,
33        },
34        su3,
35        thread::{ThreadAnyError, ThreadError},
36        CMatrix3, Complex, Real, Vector8,
37    },
38    monte_carlo::MonteCarlo,
39};
40
41/// Default leap frog simulation state
42pub type LeapFrogStateDefault<const D: usize> =
43    SimulationStateLeap<LatticeStateEFSyncDefault<LatticeStateDefault<D>, D>, D>;
44
45/// Trait to represent a pure gauge lattice state of dimension `D`.
46///
47/// It defines only one field: `link_matrix` of type [`LinkMatrix`].
48///
49/// # Example
50/// They are many examples throughout the carte see by instance
51/// [`super::monte_carlo::hybrid_monte_carlo`].
52pub trait LatticeState<const D: usize> {
53    /// Get the link matrices of this state.
54    ///
55    /// This is the field that stores the link matrices.
56    /// # Example
57    /// ```
58    /// use lattice_qcd_rs::lattice::{DirectionEnum, LatticePoint};
59    /// use lattice_qcd_rs::simulation::{LatticeState, LatticeStateDefault};
60    ///
61    /// # use std::error::Error;
62    /// # fn main() -> Result<(), Box<dyn Error>> {
63    /// let point = LatticePoint::new_zero();
64    /// let state = LatticeStateDefault::<4>::new_cold(1_f64, 10_f64, 4)?;
65    /// let _plaquette = state.link_matrix().pij(
66    ///     &point,
67    ///     &DirectionEnum::XPos.into(),
68    ///     &DirectionEnum::YPos.into(),
69    ///     state.lattice(),
70    /// );
71    /// # Ok(())
72    /// # }
73    /// ```
74    fn link_matrix(&self) -> &LinkMatrix;
75
76    /// Replace the links matrices with the given input. It should panic if link matrix
77    /// is not of the correct size.
78    ///
79    /// # Panic
80    /// Panic if the length of link_matrix is different from
81    /// `lattice.get_number_of_canonical_links_space()`
82    fn set_link_matrix(&mut self, link_matrix: LinkMatrix);
83
84    /// Get the lattice into which the state exists.
85    fn lattice(&self) -> &LatticeCyclic<D>;
86
87    /// Returns the beta parameter of the states.
88    fn beta(&self) -> Real;
89
90    /// C_A constant of the model, usually it is 3.
91    const CA: Real;
92
93    /// Returns the Hamiltonian of the links configuration.
94    fn hamiltonian_links(&self) -> Real;
95
96    /// Do one monte carlo step with the given method.
97    ///
98    /// # Errors
99    /// The error form `MonteCarlo::get_next_element` is propagated.
100    ///
101    /// # Example
102    /// see [`super::monte_carlo::hybrid_monte_carlo`].
103    fn monte_carlo_step<M>(self, m: &mut M) -> Result<Self, M::Error>
104    where
105        Self: Sized,
106        M: MonteCarlo<Self, D> + ?Sized,
107    {
108        m.next_element(self)
109    }
110
111    /// Take the average of the trace of all plaquettes.
112    ///
113    /// # Example
114    /// see the crate documentation [`crate`].
115    fn average_trace_plaquette(&self) -> Option<Complex> {
116        self.link_matrix().average_trace_plaquette(self.lattice())
117    }
118}
119
120/// Trait for a way to create a [`LatticeState`] from some parameters.
121///
122/// It is separated from the [`LatticeState`] because not all [`LatticeState`] can be create in this way.
123/// By instance when there is also a field of conjugate momenta of the link matrices.
124///
125/// This is used by the Monte Carlo algorithms to create the new states.
126pub trait LatticeStateNew<const D: usize>: LatticeState<D> + Sized {
127    /// Error type
128    type Error;
129
130    /// Create a new simulation state.
131    ///
132    /// # Errors
133    /// Give an error if the parameter are incorrect or the length of `link_matrix` does not correspond
134    /// to `lattice`.
135    ///
136    /// # Example
137    /// ```
138    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
139    /// use lattice_qcd_rs::field::LinkMatrix;
140    /// use lattice_qcd_rs::lattice::LatticeCyclic;
141    /// use lattice_qcd_rs::simulation::{LatticeStateDefault, LatticeStateNew};
142    ///
143    /// let lattice = LatticeCyclic::new(1_f64, 4)?;
144    /// let links = LinkMatrix::new_cold(&lattice);
145    /// let state = LatticeStateDefault::<4>::new(lattice, 1_f64, links)?;
146    /// # Ok(())
147    /// # }
148    /// ```
149    fn new(
150        lattice: LatticeCyclic<D>,
151        beta: Real,
152        link_matrix: LinkMatrix,
153    ) -> Result<Self, Self::Error>;
154}
155
156/// Represent a lattice state where the conjugate momenta of the link matrices are included.
157///
158/// If you have a LatticeState and want the default way of adding the conjugate momenta look at
159/// [`LatticeStateEFSyncDefault`].
160///
161/// If you want to solve the equation of motion using an [`SymplecticIntegrator`] also implement
162/// [`SimulationStateSynchronous`] and the wrapper [`SimulationStateLeap`] can give you an [`SimulationStateLeapFrog`].
163///
164/// It is used for the [`super::monte_carlo::HybridMonteCarlo`] algorithm.
165pub trait LatticeStateWithEField<const D: usize>: LatticeState<D> {
166    /// Reset the e_field with radom value distributed as N(0, 1 / beta)
167    /// [`rand_distr::StandardNormal`].
168    ///
169    /// # Errors
170    /// Gives and error if N(0, 0.5/beta ) is not a valid distribution (for example beta = 0).
171    ///
172    /// Gives [`StateInitializationError::GaussProjectionError`] if the Gauss projection failed
173    // TODO explain why !!!
174    fn reset_e_field<Rng>(&mut self, rng: &mut Rng) -> Result<(), StateInitializationError>
175    where
176        Rng: rand::Rng + ?Sized,
177    {
178        let d = rand_distr::Normal::new(0_f64, 0.5_f64 / self.beta())?;
179        let new_e_field = EField::new_determinist(self.lattice(), rng, &d);
180        if !self.lattice().has_compatible_length_e_field(&new_e_field) {
181            return Err(StateInitializationError::IncompatibleSize);
182        }
183        self.set_e_field(
184            new_e_field
185                .project_to_gauss(self.link_matrix(), self.lattice())
186                .ok_or(StateInitializationError::GaussProjectionError)?,
187        );
188        Ok(())
189    }
190
191    /// The "Electrical" field of this state.
192    fn e_field(&self) -> &EField<D>;
193
194    /// Replace the electrical field with the given input. It should panic if the input is not of
195    /// the correct size.
196    ///
197    /// # Panic
198    /// Panic if the length of link_matrix is different from `lattice.get_number_of_points()`
199    fn set_e_field(&mut self, e_field: EField<D>);
200
201    /// return the time state, i.e. the number of time the simulation ran.
202    fn t(&self) -> usize;
203
204    /// Get the derivative \partial_t U(link), returns [`None`] if the link is outside of the lattice.
205    ///
206    /// It is used in order to apply the equation of motion.
207    fn derivative_u(
208        link: &LatticeLinkCanonical<D>,
209        link_matrix: &LinkMatrix,
210        e_field: &EField<D>,
211        lattice: &LatticeCyclic<D>,
212    ) -> Option<CMatrix3>;
213
214    /// Get the derivative \partial_t E(point), returns [`None`] if the link is outside of the lattice.
215    ///
216    /// It is used in order to apply the equation of motion.
217    fn derivative_e(
218        point: &LatticePoint<D>,
219        link_matrix: &LinkMatrix,
220        e_field: &EField<D>,
221        lattice: &LatticeCyclic<D>,
222    ) -> Option<SVector<Su3Adjoint, D>>;
223
224    /// Get the energy of the conjugate momenta configuration
225    fn hamiltonian_efield(&self) -> Real;
226
227    /// Get the total energy, by default [`LatticeStateWithEField::hamiltonian_efield`]
228    /// + [`LatticeState::hamiltonian_links`]
229    fn hamiltonian_total(&self) -> Real {
230        self.hamiltonian_links() + self.hamiltonian_efield()
231    }
232}
233
234/// Trait to create a simulation state.
235///
236/// It is used by the [`super::monte_carlo::HybridMonteCarlo`] algorithm to create new state.
237pub trait LatticeStateWithEFieldNew<const D: usize>
238where
239    Self: LatticeStateWithEField<D> + Sized,
240{
241    /// Error type
242    type Error: From<rand_distr::NormalError>;
243
244    /// Create a new simulation state
245    ///
246    /// # Errors
247    /// Give an error if the parameter are incorrect or the length of `link_matrix`
248    /// and `e_field` does not correspond to `lattice`
249    fn new(
250        lattice: LatticeCyclic<D>,
251        beta: Real,
252        e_field: EField<D>,
253        link_matrix: LinkMatrix,
254        t: usize,
255    ) -> Result<Self, Self::Error>;
256
257    /// Create a new state with e_field randomly distributed as [`rand_distr::Normal`]^.
258    ///
259    /// # Errors
260    /// Gives an error if N(0, 0.5/beta ) is not a valid distribution (for example beta = 0)
261    /// or propagate the error from [`LatticeStateWithEFieldNew::new`]
262    fn new_random_e<R>(
263        lattice: LatticeCyclic<D>,
264        beta: Real,
265        link_matrix: LinkMatrix,
266        rng: &mut R,
267    ) -> Result<Self, Self::Error>
268    where
269        R: rand::Rng + ?Sized,
270    {
271        // TODO verify
272        let d = rand_distr::Normal::new(0_f64, 0.5_f64 / beta)?;
273        let e_field = EField::new_determinist(&lattice, rng, &d)
274            .project_to_gauss(&link_matrix, &lattice)
275            .expect("Projection to gauss failed");
276        Self::new(lattice, beta, e_field, link_matrix, 0)
277    }
278}
279
280/// [`LatticeStateWithEField`] who represent link matrices at the same time position as
281/// its conjugate momenta
282/// `e_field`.
283///
284/// If you have a LatticeState and want the default way of adding the conjugate momenta and doing
285/// simulation look at
286/// [`LatticeStateEFSyncDefault`].
287///
288/// I would advice of implementing this trait and not [`SimulationStateLeapFrog`], as there is
289/// a wrapper ([`SimulationStateLeap`]) for [`SimulationStateLeapFrog`].
290/// Also not implementing both trait gives you a compile time verification that you did not
291/// considered a leap frog state as a sync one.
292pub trait SimulationStateSynchronous<const D: usize>
293where
294    Self: LatticeStateWithEField<D> + Clone,
295{
296    /// does half a step for the conjugate momenta.
297    ///
298    /// # Errors
299    /// Return an error if the integration could not be done.
300    /// # Example
301    /// see [`SimulationStateLeapFrog::simulate_leap`]
302    fn simulate_to_leapfrog<I, State>(
303        &self,
304        integrator: &I,
305        delta_t: Real,
306    ) -> Result<State, I::Error>
307    where
308        State: SimulationStateLeapFrog<D>,
309        I: SymplecticIntegrator<Self, State, D> + ?Sized,
310    {
311        integrator.integrate_sync_leap(self, delta_t)
312    }
313
314    /// Does `number_of_steps` with `delta_t` at each step using a leap_frog algorithm by fist
315    /// doing half a step and then finishing by doing half step.
316    ///
317    /// # Errors
318    /// Return an error if the integration could not be done
319    /// or [`MultiIntegrationError::ZeroIntegration`] is the number of step is zero.
320    // TODO example
321    fn simulate_using_leapfrog_n<I, State>(
322        &self,
323        integrator: &I,
324        delta_t: Real,
325        number_of_steps: usize,
326    ) -> Result<Self, MultiIntegrationError<I::Error>>
327    where
328        State: SimulationStateLeapFrog<D>,
329        I: SymplecticIntegrator<Self, State, D> + ?Sized,
330    {
331        if number_of_steps == 0 {
332            return Err(MultiIntegrationError::ZeroIntegration);
333        }
334        let mut state_leap = self
335            .simulate_to_leapfrog(integrator, delta_t)
336            .map_err(|error| MultiIntegrationError::IntegrationError(0, error))?;
337        if number_of_steps > 1 {
338            let result = state_leap.simulate_leap_n(integrator, delta_t, number_of_steps - 1);
339            match result {
340                Ok(state) => state_leap = state,
341                Err(error) => {
342                    match error {
343                        MultiIntegrationError::IntegrationError(i, error) => {
344                            return Err(MultiIntegrationError::IntegrationError(i + 1, error))
345                        }
346                        MultiIntegrationError::ZeroIntegration => {
347                            // We cannot have 0 step integration as it is verified by the if
348                            unreachable!();
349                        }
350                    }
351                }
352            }
353        }
354        let state_sync = state_leap
355            .simulate_to_synchronous(integrator, delta_t)
356            .map_err(|error| MultiIntegrationError::IntegrationError(number_of_steps, error))?;
357        Ok(state_sync)
358    }
359
360    /// Does the same thing as [`SimulationStateSynchronous::simulate_using_leapfrog_n`]
361    /// but use the default wrapper [`SimulationStateLeap`] for the leap frog state.
362    ///
363    /// # Errors
364    /// Return an error if the integration could not be done.
365    // TODO example
366    fn simulate_using_leapfrog_n_auto<I>(
367        &self,
368        integrator: &I,
369        delta_t: Real,
370        number_of_steps: usize,
371    ) -> Result<Self, MultiIntegrationError<I::Error>>
372    where
373        I: SymplecticIntegrator<Self, SimulationStateLeap<Self, D>, D> + ?Sized,
374    {
375        self.simulate_using_leapfrog_n(integrator, delta_t, number_of_steps)
376    }
377
378    /// Does a simulation step using the sync algorithm
379    ///
380    /// # Errors
381    /// Return an error if the integration could not be done.
382    // TODO example
383    fn simulate_sync<I, T>(&self, integrator: &I, delta_t: Real) -> Result<Self, I::Error>
384    where
385        I: SymplecticIntegrator<Self, T, D> + ?Sized,
386        T: SimulationStateLeapFrog<D>,
387    {
388        integrator.integrate_sync_sync(self, delta_t)
389    }
390
391    /// Does `numbers_of_times` of step of size `delta_t` using the sync algorithm
392    ///
393    /// # Errors
394    /// Return an error if the integration could not be done
395    /// or [`MultiIntegrationError::ZeroIntegration`] is the number of step is zero.
396    // TODO example
397    fn simulate_sync_n<I, T>(
398        &self,
399        integrator: &I,
400        delta_t: Real,
401        numbers_of_times: usize,
402    ) -> Result<Self, MultiIntegrationError<I::Error>>
403    where
404        I: SymplecticIntegrator<Self, T, D> + ?Sized,
405        T: SimulationStateLeapFrog<D>,
406    {
407        if numbers_of_times == 0 {
408            return Err(MultiIntegrationError::ZeroIntegration);
409        }
410        let mut state = self
411            .simulate_sync(integrator, delta_t)
412            .map_err(|error| MultiIntegrationError::IntegrationError(0, error))?;
413        for i in 1..numbers_of_times {
414            state = state
415                .simulate_sync(integrator, delta_t)
416                .map_err(|error| MultiIntegrationError::IntegrationError(i, error))?;
417        }
418        Ok(state)
419    }
420
421    /// Integrate the state using the symplectic algorithm ( by going to leapfrog and back to sync)
422    ///
423    /// # Errors
424    /// Return an error if the integration could not be done
425    ///
426    /// # Example
427    /// ```
428    /// # use std::error::Error;
429    /// #
430    /// # fn main() -> Result<(), Box<dyn Error>> {
431    /// use lattice_qcd_rs::integrator::{SymplecticEulerRayon, SymplecticIntegrator};
432    /// use lattice_qcd_rs::simulation::{
433    ///     LatticeStateDefault, LatticeStateEFSyncDefault, LatticeStateWithEField,
434    ///     SimulationStateSynchronous,
435    /// };
436    /// use rand::SeedableRng;
437    ///
438    /// let mut rng = rand::rngs::StdRng::seed_from_u64(0); // change with your seed
439    /// let mut state = LatticeStateEFSyncDefault::new_random_e_state(
440    ///     LatticeStateDefault::<3>::new_determinist(1_f64, 2_f64, 4, &mut rng)?,
441    ///     &mut rng,
442    /// );
443    /// let h = state.hamiltonian_total();
444    ///
445    /// let integrator = SymplecticEulerRayon::default();
446    /// for _ in 0..1 {
447    ///     // Realistically you would want more steps
448    ///     state = state.simulate_symplectic(&integrator, 0.000_001_f64)?;
449    /// }
450    /// let h2 = state.hamiltonian_total();
451    ///
452    /// println!("The error on the Hamiltonian is {}", h - h2);
453    /// #     Ok(())
454    /// # }
455    /// ```
456    fn simulate_symplectic<I, T>(&self, integrator: &I, delta_t: Real) -> Result<Self, I::Error>
457    where
458        I: SymplecticIntegrator<Self, T, D> + ?Sized,
459        T: SimulationStateLeapFrog<D>,
460    {
461        integrator.integrate_symplectic(self, delta_t)
462    }
463
464    /// Does `numbers_of_times` of step of size `delta_t` using the symplectic algorithm
465    ///
466    /// # Errors
467    /// Return an error if the integration could not be done
468    /// or [`MultiIntegrationError::ZeroIntegration`] is the number of step is zero.
469    // TODO example
470    fn simulate_symplectic_n<I, T>(
471        &self,
472        integrator: &I,
473        delta_t: Real,
474        numbers_of_times: usize,
475    ) -> Result<Self, MultiIntegrationError<I::Error>>
476    where
477        I: SymplecticIntegrator<Self, T, D> + ?Sized,
478        T: SimulationStateLeapFrog<D>,
479    {
480        if numbers_of_times == 0 {
481            return Err(MultiIntegrationError::ZeroIntegration);
482        }
483        let mut state = self
484            .simulate_symplectic(integrator, delta_t)
485            .map_err(|error| MultiIntegrationError::IntegrationError(0, error))?;
486        for i in 1..numbers_of_times {
487            state = state
488                .simulate_symplectic(integrator, delta_t)
489                .map_err(|error| MultiIntegrationError::IntegrationError(i, error))?;
490        }
491        Ok(state)
492    }
493
494    /// Does the same thing as [`SimulationStateSynchronous::simulate_symplectic_n`]
495    /// but use the default wrapper [`SimulationStateLeap`] for the leap frog state.
496    ///
497    /// # Errors
498    /// Return an error if the integration could not be done.
499    // TODO example
500    fn simulate_symplectic_n_auto<I>(
501        &self,
502        integrator: &I,
503        delta_t: Real,
504        number_of_steps: usize,
505    ) -> Result<Self, MultiIntegrationError<I::Error>>
506    where
507        I: SymplecticIntegrator<Self, SimulationStateLeap<Self, D>, D> + ?Sized,
508    {
509        self.simulate_symplectic_n(integrator, delta_t, number_of_steps)
510    }
511}
512
513/// [`LatticeStateWithEField`] who represent link matrices at time T and its conjugate
514/// momenta at time T + 1/2.
515///
516/// If you have a [`SimulationStateSynchronous`] look at the wrapper [`SimulationStateLeap`].
517pub trait SimulationStateLeapFrog<const D: usize>
518where
519    Self: LatticeStateWithEField<D>,
520{
521    /// Simulate the state to synchronous by finishing the half step.
522    ///
523    /// # Errors
524    /// Return an error if the integration could not be done.
525    ///
526    /// # Example
527    /// see [`SimulationStateLeapFrog::simulate_leap`]
528    fn simulate_to_synchronous<I, State>(
529        &self,
530        integrator: &I,
531        delta_t: Real,
532    ) -> Result<State, I::Error>
533    where
534        Self: Sized,
535        State: SimulationStateSynchronous<D> + ?Sized,
536        I: SymplecticIntegrator<State, Self, D> + ?Sized,
537    {
538        integrator.integrate_leap_sync(self, delta_t)
539    }
540
541    /// Does one simulation step using the leap frog algorithm.
542    ///
543    /// # Errors
544    /// Return an error if the integration could not be done.
545    ///
546    /// # Example
547    ///  ```
548    /// # use std::error::Error;
549    /// #
550    /// # fn main() -> Result<(), Box<dyn Error>> {
551    /// use lattice_qcd_rs::integrator::{SymplecticEulerRayon, SymplecticIntegrator};
552    /// use lattice_qcd_rs::simulation::{
553    ///     LatticeStateDefault, LatticeStateEFSyncDefault, LatticeStateWithEField, SimulationStateSynchronous, SimulationStateLeapFrog,
554    /// };
555    /// use rand::SeedableRng;
556    ///
557    /// let mut rng = rand::rngs::StdRng::seed_from_u64(0); // change with your seed
558    /// let state = LatticeStateEFSyncDefault::new_random_e_state(
559    ///     LatticeStateDefault::<3>::new_determinist(1_f64, 2_f64, 4, &mut rng)?,
560    ///     &mut rng,
561    /// );
562    /// let h = state.hamiltonian_total();
563    /// let integrator = SymplecticEulerRayon::default();
564    /// let mut leap_frog = state.simulate_to_leapfrog(&integrator,0.000_001_f64)?;
565    /// drop(state);
566    /// for _ in 0..2 {
567    ///     // Realistically you would want more steps
568    ///     leap_frog = leap_frog.simulate_leap(&integrator, 0.000_001_f64)?;
569    /// }
570    /// let state = leap_frog.simulate_to_synchronous(&integrator, 0.000_001_f64)?;
571    /// let h2 = state.hamiltonian_total();
572    ///
573    /// println!("The error on the Hamiltonian is {}", h - h2);
574    /// #     Ok(())
575    /// # }
576    /// ```
577    fn simulate_leap<I, T>(&self, integrator: &I, delta_t: Real) -> Result<Self, I::Error>
578    where
579        Self: Sized,
580        I: SymplecticIntegrator<T, Self, D> + ?Sized,
581        T: SimulationStateSynchronous<D> + ?Sized,
582    {
583        integrator.integrate_leap_leap(self, delta_t)
584    }
585
586    /// does `numbers_of_times` simulation set of size `delta_t` using the leap frog algorithm.
587    ///
588    /// # Errors
589    /// Return an error if the integration could not be done
590    /// or [`MultiIntegrationError::ZeroIntegration`] is the number of step is zero.
591    ///
592    /// # Example
593    /// /// # Example
594    ///  ```
595    /// # use std::error::Error;
596    /// #
597    /// # fn main() -> Result<(), Box<dyn Error>> {
598    /// use lattice_qcd_rs::integrator::{SymplecticEulerRayon, SymplecticIntegrator};
599    /// use lattice_qcd_rs::simulation::{
600    ///     LatticeStateDefault, LatticeStateEFSyncDefault, LatticeStateWithEField, SimulationStateSynchronous, SimulationStateLeapFrog,
601    /// };
602    /// use rand::SeedableRng;
603    ///
604    /// let mut rng = rand::rngs::StdRng::seed_from_u64(0); // change with your seed
605    /// let state = LatticeStateEFSyncDefault::new_random_e_state(
606    ///     LatticeStateDefault::<3>::new_determinist(1_f64, 2_f64, 4, &mut rng)?,
607    ///     &mut rng,
608    /// );
609    /// let h = state.hamiltonian_total();
610    /// let integrator = SymplecticEulerRayon::default();
611    /// let mut leap_frog = state.simulate_to_leapfrog(&integrator,0.000_001_f64)?;
612    /// drop(state);
613    ///
614    /// // Realistically you would want more steps
615    /// leap_frog = leap_frog.simulate_leap_n(&integrator, 0.000_001_f64, 10)?;
616    ///
617    /// let state = leap_frog.simulate_to_synchronous(&integrator, 0.000_001_f64)?;
618    /// let h2 = state.hamiltonian_total();
619    ///
620    /// println!("The error on the Hamiltonian is {}", h - h2);
621    /// #     Ok(())
622    /// # }
623    /// ```
624    fn simulate_leap_n<I, T>(
625        &self,
626        integrator: &I,
627        delta_t: Real,
628        numbers_of_times: usize,
629    ) -> Result<Self, MultiIntegrationError<I::Error>>
630    where
631        Self: Sized,
632        I: SymplecticIntegrator<T, Self, D> + ?Sized,
633        T: SimulationStateSynchronous<D> + ?Sized,
634    {
635        if numbers_of_times == 0 {
636            return Err(MultiIntegrationError::ZeroIntegration);
637        }
638        let mut state = self
639            .simulate_leap(integrator, delta_t)
640            .map_err(|error| MultiIntegrationError::IntegrationError(0, error))?;
641        for i in 1..(numbers_of_times) {
642            state = state
643                .simulate_leap(integrator, delta_t)
644                .map_err(|error| MultiIntegrationError::IntegrationError(i, error))?;
645        }
646        Ok(state)
647    }
648}
649
650/// Represent a simulation state at a set time.
651///
652/// It has the default pure gauge hamiltonian
653#[derive(Debug, PartialEq, Clone)]
654#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
655pub struct LatticeStateDefault<const D: usize> {
656    lattice: LatticeCyclic<D>,
657    beta: Real,
658    link_matrix: LinkMatrix,
659}
660
661impl<const D: usize> LatticeStateDefault<D> {
662    /// Create a cold configuration. i.e. all the links are set to the unit matrix.
663    ///
664    /// With the lattice of size `size` and dimension `number_of_points` ( see [`LatticeCyclic::new`] )
665    /// and beta parameter `beta`.
666    ///
667    /// # Errors
668    /// Returns [`StateInitializationError::LatticeInitializationError`] if the parameter is invalid
669    /// for [`LatticeCyclic`].
670    /// Or propagate the error form [`Self::new`].
671    pub fn new_cold(
672        size: Real,
673        beta: Real,
674        number_of_points: usize,
675    ) -> Result<Self, StateInitializationError> {
676        let lattice = LatticeCyclic::new(size, number_of_points)?;
677        let link_matrix = LinkMatrix::new_cold(&lattice);
678        Self::new(lattice, beta, link_matrix)
679    }
680
681    /// Create a "hot" configuration, i.e. the link matrices are chosen randomly.
682    ///
683    /// With the lattice of size `size` and dimension `number_of_points` ( see [`LatticeCyclic::new`] )
684    /// and beta parameter `beta`.
685    ///
686    /// The creation is determinists meaning that it is reproducible:
687    ///
688    /// # Errors
689    /// Returns [`StateInitializationError::LatticeInitializationError`] if the parameter is invalid for [`LatticeCyclic`].
690    /// Or propagate the error form [`Self::new`].
691    ///
692    /// # Example
693    /// This example demonstrate how to reproduce the same configuration
694    /// ```
695    /// # use lattice_qcd_rs::{simulation::LatticeStateDefault, lattice::LatticeCyclic, dim};
696    /// use rand::{rngs::StdRng, SeedableRng};
697    ///
698    /// let mut rng_1 = StdRng::seed_from_u64(0);
699    /// let mut rng_2 = StdRng::seed_from_u64(0);
700    /// // They have the same seed and should generate the same numbers
701    /// assert_eq!(
702    ///     LatticeStateDefault::<4>::new_determinist(1_f64, 1_f64, 4, &mut rng_1).unwrap(),
703    ///     LatticeStateDefault::<4>::new_determinist(1_f64, 1_f64, 4, &mut rng_2).unwrap()
704    /// );
705    /// ```
706    pub fn new_determinist(
707        size: Real,
708        beta: Real,
709        number_of_points: usize,
710        rng: &mut impl rand::Rng,
711    ) -> Result<Self, StateInitializationError> {
712        let lattice = LatticeCyclic::new(size, number_of_points)?;
713        let link_matrix = LinkMatrix::new_determinist(&lattice, rng);
714        Self::new(lattice, beta, link_matrix)
715    }
716
717    /// Correct the numerical drift, reprojecting all the link matrices to SU(3).
718    /// see [`LinkMatrix::normalize`].
719    ///
720    /// # Example
721    /// ```
722    /// use lattice_qcd_rs::error::ImplementationError;
723    /// use lattice_qcd_rs::prelude::*;
724    /// use rand::SeedableRng;
725    /// # use std::error::Error;
726    ///
727    /// # fn main() -> Result<(), Box<dyn Error>> {
728    /// let mut rng = rand::rngs::StdRng::seed_from_u64(0); // change with your seed
729    ///
730    /// let size = 1_f64;
731    /// let number_of_pts = 3;
732    /// let beta = 1_f64;
733    ///
734    /// let mut simulation =
735    ///     LatticeStateDefault::<4>::new_determinist(size, beta, number_of_pts, &mut rng)?;
736    ///
737    /// let spread_parameter = 0.1_f64;
738    /// let mut mc = MetropolisHastingsSweep::new(1, spread_parameter, rng)
739    ///     .ok_or(ImplementationError::OptionWithUnexpectedNone)?;
740    ///
741    /// for _ in 0..2 {
742    ///     for _ in 0..10 {
743    ///         simulation = simulation.monte_carlo_step(&mut mc)?;
744    ///     }
745    ///     // the more we advance te more the link matrices
746    ///     // will deviate form SU(3), so we reproject to SU(3)
747    ///     // every 10 steps.
748    ///     simulation.normalize_link_matrices();
749    /// }
750    /// #
751    /// # Ok(())
752    /// # }
753    /// ```
754    pub fn normalize_link_matrices(&mut self) {
755        self.link_matrix.normalize();
756    }
757
758    /// Get a mutable reference to the link matrix at `link`
759    pub fn link_mut(&mut self, link: &LatticeLinkCanonical<D>) -> Option<&mut CMatrix3> {
760        let index = link.to_index(&self.lattice);
761        if index < self.link_matrix.len() {
762            Some(&mut self.link_matrix[index])
763        }
764        else {
765            None
766        }
767    }
768
769    /// Absorbs self anf return the link_matrix as owned
770    #[allow(clippy::missing_const_for_fn)] // false positive
771    pub fn link_matrix_owned(self) -> LinkMatrix {
772        self.link_matrix
773    }
774}
775
776impl<const D: usize> LatticeStateNew<D> for LatticeStateDefault<D> {
777    type Error = StateInitializationError;
778
779    fn new(
780        lattice: LatticeCyclic<D>,
781        beta: Real,
782        link_matrix: LinkMatrix,
783    ) -> Result<Self, Self::Error> {
784        if !lattice.has_compatible_length_links(&link_matrix) {
785            return Err(StateInitializationError::IncompatibleSize);
786        }
787        Ok(Self {
788            lattice,
789            beta,
790            link_matrix,
791        })
792    }
793}
794
795impl<const D: usize> LatticeState<D> for LatticeStateDefault<D> {
796    const CA: Real = 3_f64;
797
798    getter!(
799        /// The link matrices of this state.
800        link_matrix,
801        LinkMatrix
802    );
803
804    getter!(lattice, LatticeCyclic<D>);
805
806    getter_copy!(beta, Real);
807
808    /// # Panic
809    /// Panic if the length of link_matrix is different from `lattice.get_number_of_canonical_links_space()`
810    fn set_link_matrix(&mut self, link_matrix: LinkMatrix) {
811        if self.lattice.number_of_canonical_links_space() != link_matrix.len() {
812            panic!("Link matrices are not of the correct size");
813        }
814        self.link_matrix = link_matrix;
815    }
816
817    /// Get the default pure gauge Hamiltonian.
818    ///
819    /// # Panic
820    /// Panic if plaquettes cannot be found
821    fn hamiltonian_links(&self) -> Real {
822        // here it is ok to use par_bridge() as we do not care for the order
823        self.lattice()
824            .get_points()
825            .par_bridge()
826            .map(|el| {
827                Direction::positive_directions()
828                    .iter()
829                    .map(|dir_i| {
830                        Direction::positive_directions()
831                            .iter()
832                            .filter(|dir_j| dir_i.index() < dir_j.index())
833                            .map(|dir_j| {
834                                1_f64
835                                    - self
836                                        .link_matrix()
837                                        .pij(&el, dir_i, dir_j, self.lattice())
838                                        .expect("Plaquette not found")
839                                        .trace()
840                                        .real()
841                                        / Self::CA
842                            })
843                            .sum::<Real>()
844                    })
845                    .sum::<Real>()
846            })
847            .sum::<Real>()
848            * self.beta()
849    }
850}
851
852/// wrapper for a simulation state using leap frog ([`SimulationStateLeap`]) using a synchronous type
853/// ([`SimulationStateSynchronous`]).
854#[derive(Debug, PartialEq, Clone, Eq, PartialOrd, Ord, Hash)]
855#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
856pub struct SimulationStateLeap<State, const D: usize>
857where
858    State: SimulationStateSynchronous<D> + ?Sized,
859{
860    state: State,
861}
862
863impl<State, const D: usize> SimulationStateLeap<State, D>
864where
865    State: SimulationStateSynchronous<D> + LatticeStateWithEField<D> + ?Sized,
866{
867    getter!(
868        /// get a reference to the state
869        pub const,
870        state,
871        State
872    );
873
874    /// Create a new SimulationStateLeap directly from a state without applying any modification.
875    ///
876    /// In most cases wou will prefer to build it using [`LatticeStateNew`] or [`Self::from_synchronous`].
877    pub const fn new_from_state(state: State) -> Self {
878        Self { state }
879    }
880
881    /// get a mutable reference to the state
882    pub fn state_mut(&mut self) -> &mut State {
883        &mut self.state
884    }
885
886    /// Create a leap state from a sync one by integrating by half a step the e_field.
887    ///
888    /// # Errors
889    /// Returns an error if the integration failed.
890    pub fn from_synchronous<I>(s: &State, integrator: &I, delta_t: Real) -> Result<Self, I::Error>
891    where
892        I: SymplecticIntegrator<State, Self, D> + ?Sized,
893    {
894        s.simulate_to_leapfrog(integrator, delta_t)
895    }
896
897    /// Get the gauss coefficient `G(x) = \sum_i E_i(x) - U_{-i}(x) E_i(x - i) U^\dagger_{-i}(x)`.
898    pub fn gauss(&self, point: &LatticePoint<D>) -> Option<CMatrix3> {
899        self.e_field()
900            .gauss(self.link_matrix(), point, self.lattice())
901    }
902}
903
904impl<State, const D: usize> Default for SimulationStateLeap<State, D>
905where
906    State: SimulationStateSynchronous<D> + Default + ?Sized,
907{
908    fn default() -> Self {
909        Self::new_from_state(State::default())
910    }
911}
912
913impl<State, const D: usize> std::fmt::Display for SimulationStateLeap<State, D>
914where
915    State: SimulationStateSynchronous<D> + std::fmt::Display + ?Sized,
916{
917    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
918        write!(f, "leapfrog {}", self.state())
919    }
920}
921
922impl<State: SimulationStateSynchronous<D> + LatticeStateWithEField<D>, const D: usize> AsRef<State>
923    for SimulationStateLeap<State, D>
924{
925    fn as_ref(&self) -> &State {
926        self.state()
927    }
928}
929
930impl<State: SimulationStateSynchronous<D> + LatticeStateWithEField<D>, const D: usize> AsMut<State>
931    for SimulationStateLeap<State, D>
932{
933    fn as_mut(&mut self) -> &mut State {
934        self.state_mut()
935    }
936}
937
938/// This state is a leap frog state
939impl<State, const D: usize> SimulationStateLeapFrog<D> for SimulationStateLeap<State, D> where
940    State: SimulationStateSynchronous<D> + LatticeStateWithEField<D> + ?Sized
941{
942}
943
944/// We just transmit the function of `State`, there is nothing new.
945impl<State, const D: usize> LatticeState<D> for SimulationStateLeap<State, D>
946where
947    State: LatticeStateWithEField<D> + SimulationStateSynchronous<D> + ?Sized,
948{
949    const CA: Real = State::CA;
950
951    /// The link matrices of this state.
952    fn link_matrix(&self) -> &LinkMatrix {
953        self.state().link_matrix()
954    }
955
956    /// # Panic
957    /// panic under the same condition as `State::set_link_matrix`
958    fn set_link_matrix(&mut self, link_matrix: LinkMatrix) {
959        self.state.set_link_matrix(link_matrix);
960    }
961
962    fn lattice(&self) -> &LatticeCyclic<D> {
963        self.state().lattice()
964    }
965
966    fn beta(&self) -> Real {
967        self.state().beta()
968    }
969
970    fn hamiltonian_links(&self) -> Real {
971        self.state().hamiltonian_links()
972    }
973}
974
975impl<State, const D: usize> LatticeStateWithEFieldNew<D> for SimulationStateLeap<State, D>
976where
977    State: LatticeStateWithEField<D> + SimulationStateSynchronous<D> + LatticeStateWithEFieldNew<D>,
978{
979    type Error = State::Error;
980
981    fn new(
982        lattice: LatticeCyclic<D>,
983        beta: Real,
984        e_field: EField<D>,
985        link_matrix: LinkMatrix,
986        t: usize,
987    ) -> Result<Self, Self::Error> {
988        let state = State::new(lattice, beta, e_field, link_matrix, t)?;
989        Ok(Self { state })
990    }
991}
992
993/// We just transmit the function of `State`, there is nothing new.
994impl<State, const D: usize> LatticeStateWithEField<D> for SimulationStateLeap<State, D>
995where
996    State: LatticeStateWithEField<D> + SimulationStateSynchronous<D> + ?Sized,
997{
998    project!(hamiltonian_efield, state, Real);
999
1000    project!(
1001        /// The "Electrical" field of this state.
1002        e_field,
1003        state,
1004        &EField<D>
1005    );
1006
1007    project_mut!(
1008        /// # Panic
1009        /// panic under the same condition as `State::set_e_field`
1010        set_e_field,
1011        state,
1012        (),
1013        e_field: EField<D>
1014    );
1015
1016    project!(
1017        /// return the time state, i.e. the number of time the simulation ran.
1018        t,
1019        state,
1020        usize
1021    );
1022
1023    fn derivative_u(
1024        link: &LatticeLinkCanonical<D>,
1025        link_matrix: &LinkMatrix,
1026        e_field: &EField<D>,
1027        lattice: &LatticeCyclic<D>,
1028    ) -> Option<CMatrix3> {
1029        State::derivative_u(link, link_matrix, e_field, lattice)
1030    }
1031
1032    fn derivative_e(
1033        point: &LatticePoint<D>,
1034        link_matrix: &LinkMatrix,
1035        e_field: &EField<D>,
1036        lattice: &LatticeCyclic<D>,
1037    ) -> Option<SVector<Su3Adjoint, D>> {
1038        State::derivative_e(point, link_matrix, e_field, lattice)
1039    }
1040}
1041
1042/// wrapper to implement [`LatticeStateWithEField`] from a [`LatticeState`] using
1043/// the default implementation of conjugate momenta.
1044///
1045/// It also implement [`SimulationStateSynchronous`].
1046#[derive(Debug, PartialEq, Clone)]
1047#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
1048pub struct LatticeStateEFSyncDefault<State, const D: usize>
1049where
1050    State: LatticeState<D> + ?Sized,
1051{
1052    #[cfg_attr(
1053        feature = "serde-serialize",
1054        serde(bound(
1055            serialize = "SVector<Su3Adjoint, D>: Serialize",
1056            deserialize = "SVector<Su3Adjoint, D>: Deserialize<'de>"
1057        ))
1058    )]
1059    e_field: EField<D>,
1060    t: usize,
1061    lattice_state: State, // the DST must be at the end
1062}
1063
1064impl<State, const D: usize> LatticeStateEFSyncDefault<State, D>
1065where
1066    State: LatticeState<D> + ?Sized,
1067{
1068    /// Absorbs self and return the state as owned.
1069    /// It essentially deconstruct the structure.
1070    #[allow(clippy::missing_const_for_fn)] // false positive
1071    pub fn state_owned(self) -> State
1072    where
1073        State: Sized,
1074    {
1075        self.lattice_state
1076    }
1077
1078    /// Get a reference to the state.
1079    pub const fn lattice_state(&self) -> &State {
1080        &self.lattice_state
1081    }
1082
1083    /// Get a mutable reference to the state.
1084    pub fn lattice_state_mut(&mut self) -> &mut State {
1085        &mut self.lattice_state
1086    }
1087
1088    /// Take a state and generate a new random one and try projecting it to the Gauss law.
1089    ///
1090    /// # Panic
1091    /// Panics if N(0, 0.5/beta ) is not a valid distribution (for example beta = 0).
1092    /// Panics if the field could not be projected to the Gauss law.
1093    pub fn new_random_e_state(lattice_state: State, rng: &mut impl rand::Rng) -> Self
1094    where
1095        State: Sized,
1096    {
1097        let d = rand_distr::Normal::new(0_f64, 0.5_f64 / lattice_state.beta())
1098            .expect("Distribution not valid, check Beta.");
1099        let e_field = EField::new_determinist(lattice_state.lattice(), rng, &d)
1100            .project_to_gauss(lattice_state.link_matrix(), lattice_state.lattice())
1101            .unwrap();
1102        // TODO error management
1103        Self {
1104            lattice_state,
1105            e_field,
1106            t: 0,
1107        }
1108    }
1109
1110    /// Create a new Self from a state and a cold configuration of the e field (i.e. set to 0)
1111    pub fn new_e_cold(lattice_state: State) -> Self
1112    where
1113        State: Sized,
1114    {
1115        let e_field = EField::new_cold(lattice_state.lattice());
1116        Self {
1117            lattice_state,
1118            e_field,
1119            t: 0,
1120        }
1121    }
1122
1123    /// Get a mutable reference to the efield
1124    pub fn e_field_mut(&mut self) -> &mut EField<D> {
1125        &mut self.e_field
1126    }
1127}
1128
1129impl<State, const D: usize> LatticeStateEFSyncDefault<State, D>
1130where
1131    Self: LatticeStateWithEField<D>,
1132    State: LatticeState<D> + ?Sized,
1133{
1134    /// Get the gauss coefficient `G(x) = \sum_i E_i(x) - U_{-i}(x) E_i(x - i) U^\dagger_{-i}(x)`.
1135    pub fn gauss(&self, point: &LatticePoint<D>) -> Option<CMatrix3> {
1136        self.e_field
1137            .gauss(self.link_matrix(), point, self.lattice())
1138    }
1139}
1140
1141impl<State, const D: usize> LatticeStateEFSyncDefault<State, D>
1142where
1143    Self: LatticeStateWithEFieldNew<D>,
1144    <Self as LatticeStateWithEFieldNew<D>>::Error: From<LatticeInitializationError>,
1145    State: LatticeState<D>,
1146{
1147    /// Generate a hot (i.e. random) initial state.
1148    ///
1149    /// Single threaded generation with a given random number generator.
1150    /// `size` is the size parameter of the lattice and `number_of_points` is the number of points
1151    /// in each spatial dimension of the lattice. See [`LatticeCyclic::new`] for more info.
1152    ///
1153    /// useful to reproduce a set of data but slower than
1154    /// [`LatticeStateEFSyncDefault::new_random_threaded`].
1155    ///
1156    /// # Errors
1157    /// Return [`StateInitializationError::LatticeInitializationError`] if the parameter is invalid
1158    /// for [`LatticeCyclic`].
1159    /// Or propagates the error form [`Self::new`].
1160    ///
1161    /// # Example
1162    /// ```
1163    /// # use lattice_qcd_rs::{simulation::{LatticeStateEFSyncDefault, LatticeStateDefault}, lattice::LatticeCyclic};
1164    /// use rand::{SeedableRng,rngs::StdRng};
1165    ///
1166    /// let mut rng_1 = StdRng::seed_from_u64(0);
1167    /// let mut rng_2 = StdRng::seed_from_u64(0);
1168    /// // They have the same seed and should generate the same numbers
1169    /// let distribution = rand::distributions::Uniform::from(-1_f64..1_f64);
1170    /// assert_eq!(
1171    ///     LatticeStateEFSyncDefault::<LatticeStateDefault<4>, 4>::new_determinist(1_f64, 1_f64, 4, &mut rng_1, &distribution).unwrap(),
1172    ///     LatticeStateEFSyncDefault::<LatticeStateDefault<4>, 4>::new_determinist(1_f64, 1_f64, 4, &mut rng_2, &distribution).unwrap()
1173    /// );
1174    /// ```
1175    pub fn new_determinist<R>(
1176        size: Real,
1177        beta: Real,
1178        number_of_points: usize,
1179        rng: &mut R,
1180        d: &impl rand_distr::Distribution<Real>,
1181    ) -> Result<Self, <Self as LatticeStateWithEFieldNew<D>>::Error>
1182    where
1183        R: rand::Rng + ?Sized,
1184    {
1185        let lattice = LatticeCyclic::new(size, number_of_points)?;
1186        let e_field = EField::new_determinist(&lattice, rng, d);
1187        let link_matrix = LinkMatrix::new_determinist(&lattice, rng);
1188        Self::new(lattice, beta, e_field, link_matrix, 0)
1189    }
1190
1191    /// Generate a configuration with cold e_field and hot link matrices
1192    ///
1193    /// # Errors
1194    /// Return [`StateInitializationError::LatticeInitializationError`] if the parameter is invalid
1195    /// for [`LatticeCyclic`].
1196    /// Or propagates the error form [`Self::new`].
1197    pub fn new_determinist_cold_e_hot_link<R>(
1198        size: Real,
1199        beta: Real,
1200        number_of_points: usize,
1201        rng: &mut R,
1202    ) -> Result<Self, <Self as LatticeStateWithEFieldNew<D>>::Error>
1203    where
1204        R: rand::Rng + ?Sized,
1205    {
1206        let lattice = LatticeCyclic::new(size, number_of_points)?;
1207        let e_field = EField::new_cold(&lattice);
1208        let link_matrix = LinkMatrix::new_determinist(&lattice, rng);
1209
1210        Self::new(lattice, beta, e_field, link_matrix, 0)
1211    }
1212
1213    /// Generate a new cold state.
1214    ///
1215    /// It meas that the link matrices are set to the identity and electrical field are set to 0.
1216    ///
1217    /// # Errors
1218    /// Return [`StateInitializationError::LatticeInitializationError`] if the parameter is invalid
1219    /// for [`LatticeCyclic`].
1220    /// Or propagates the error form [`Self::new`].
1221    pub fn new_cold(
1222        size: Real,
1223        beta: Real,
1224        number_of_points: usize,
1225    ) -> Result<Self, <Self as LatticeStateWithEFieldNew<D>>::Error> {
1226        let lattice = LatticeCyclic::new(size, number_of_points)?;
1227        let link_matrix = LinkMatrix::new_cold(&lattice);
1228        let e_field = EField::new_cold(&lattice);
1229        Self::new(lattice, beta, e_field, link_matrix, 0)
1230    }
1231}
1232
1233impl<State, const D: usize> LatticeStateEFSyncDefault<State, D>
1234where
1235    Self: LatticeStateWithEFieldNew<D, Error = StateInitializationError>,
1236    State: LatticeState<D>,
1237{
1238    /// Generate a hot (i.e. random) initial state.
1239    ///
1240    /// Multi threaded generation of random data. Due to the non deterministic way threads
1241    /// operate a set cannot be reproduce easily, In that case use
1242    /// [`LatticeStateEFSyncDefault::new_determinist`].
1243    ///
1244    /// # Errors
1245    /// Return [`StateInitializationError::LatticeInitializationError`] if the parameter is invalid
1246    /// for [`LatticeCyclic`].
1247    /// Return [`ThreadError::ThreadNumberIncorrect`] if `number_of_points = 0`.
1248    /// Returns an error if a thread panicked. Finally, propagates the error form [`Self::new`].
1249    pub fn new_random_threaded<Distribution>(
1250        size: Real,
1251        beta: Real,
1252        number_of_points: usize,
1253        d: &Distribution,
1254        number_of_thread: usize,
1255    ) -> Result<Self, ThreadedStateInitializationError>
1256    where
1257        Distribution: rand_distr::Distribution<Real> + Sync,
1258    {
1259        if number_of_thread == 0 {
1260            return Err(ThreadedStateInitializationError::ThreadingError(
1261                ThreadError::ThreadNumberIncorrect,
1262            ));
1263        }
1264        else if number_of_thread == 1 {
1265            let mut rng = rand::thread_rng();
1266            return Self::new_determinist(size, beta, number_of_points, &mut rng, d)
1267                .map_err(|err| err.into());
1268        }
1269        let lattice = LatticeCyclic::new(size, number_of_points).map_err(|err| {
1270            ThreadedStateInitializationError::StateInitializationError(err.into())
1271        })?;
1272        thread::scope(|s| {
1273            let lattice_clone = lattice.clone();
1274            let handel = s.spawn(move |_| EField::new_random(&lattice_clone, d));
1275            let link_matrix = LinkMatrix::new_random_threaded(&lattice, number_of_thread - 1)?;
1276            let e_field = handel.join().map_err(|err| {
1277                ThreadedStateInitializationError::ThreadingError(
1278                    ThreadAnyError::Panic(vec![err]).into(),
1279                )
1280            })?;
1281            // TODO not very clean: improve
1282            Self::new(lattice, beta, e_field, link_matrix, 0)
1283                .map_err(ThreadedStateInitializationError::StateInitializationError)
1284        })
1285        .map_err(|err| {
1286            ThreadedStateInitializationError::ThreadingError(
1287                ThreadAnyError::Panic(vec![err]).into(),
1288            )
1289        })?
1290    }
1291}
1292
1293/// This is an sync State
1294impl<State, const D: usize> SimulationStateSynchronous<D> for LatticeStateEFSyncDefault<State, D>
1295where
1296    State: LatticeState<D> + Clone + ?Sized,
1297    Self: LatticeStateWithEField<D>,
1298{
1299}
1300
1301impl<State, const D: usize> LatticeState<D> for LatticeStateEFSyncDefault<State, D>
1302where
1303    State: LatticeState<D> + ?Sized,
1304{
1305    const CA: Real = State::CA;
1306
1307    fn link_matrix(&self) -> &LinkMatrix {
1308        self.lattice_state.link_matrix()
1309    }
1310
1311    /// # Panic
1312    /// panic under the same condition as `State::set_link_matrix`
1313    fn set_link_matrix(&mut self, link_matrix: LinkMatrix) {
1314        self.lattice_state.set_link_matrix(link_matrix);
1315    }
1316
1317    fn lattice(&self) -> &LatticeCyclic<D> {
1318        self.lattice_state.lattice()
1319    }
1320
1321    fn beta(&self) -> Real {
1322        self.lattice_state.beta()
1323    }
1324
1325    fn hamiltonian_links(&self) -> Real {
1326        self.lattice_state.hamiltonian_links()
1327    }
1328}
1329
1330impl<State, const D: usize> LatticeStateWithEFieldNew<D> for LatticeStateEFSyncDefault<State, D>
1331where
1332    State: LatticeState<D> + LatticeStateNew<D>,
1333    Self: LatticeStateWithEField<D>,
1334    StateInitializationError: Into<State::Error>,
1335    State::Error: From<rand_distr::NormalError>,
1336{
1337    type Error = State::Error;
1338
1339    /// create a new simulation state. If `e_field` or `link_matrix` does not have the corresponding
1340    /// amount of data compared to lattice it fails to create the state.
1341    /// `t` is the number of time the simulation ran. i.e. the time sate.
1342    fn new(
1343        lattice: LatticeCyclic<D>,
1344        beta: Real,
1345        e_field: EField<D>,
1346        link_matrix: LinkMatrix,
1347        t: usize,
1348    ) -> Result<Self, Self::Error> {
1349        if !lattice.has_compatible_length_e_field(&e_field) {
1350            return Err(StateInitializationError::IncompatibleSize.into());
1351        }
1352        let lattice_state_r = State::new(lattice, beta, link_matrix);
1353        match lattice_state_r {
1354            Ok(lattice_state) => Ok(Self {
1355                e_field,
1356                t,
1357                lattice_state,
1358            }),
1359            Err(err) => Err(err),
1360        }
1361    }
1362}
1363
1364impl<const D: usize> LatticeStateWithEField<D>
1365    for LatticeStateEFSyncDefault<LatticeStateDefault<D>, D>
1366where
1367    Direction<D>: DirectionList,
1368{
1369    /// By default \sum_x Tr(E_i E_i)
1370    fn hamiltonian_efield(&self) -> Real {
1371        self.lattice()
1372            .get_points()
1373            .par_bridge()
1374            .map(|el| {
1375                Direction::positive_directions()
1376                    .iter()
1377                    .map(|dir_i| {
1378                        let e_i = self.e_field().e_field(&el, dir_i, self.lattice()).unwrap();
1379                        e_i.trace_squared()
1380                    })
1381                    .sum::<Real>()
1382            })
1383            .sum::<Real>()
1384            * self.beta()
1385    }
1386
1387    /// The "Electrical" field of this state.
1388    fn e_field(&self) -> &EField<D> {
1389        &self.e_field
1390    }
1391
1392    /// # Panic
1393    /// Panic if the length of link_matrix is different from `lattice.get_number_of_points()`
1394    fn set_e_field(&mut self, e_field: EField<D>) {
1395        if self.lattice().number_of_points() != e_field.len() {
1396            panic!("e_field is not of the correct size");
1397        }
1398        self.e_field = e_field;
1399    }
1400
1401    /// return the time state, i.e. the number of time the simulation ran.
1402    fn t(&self) -> usize {
1403        self.t
1404    }
1405
1406    /// Get the derive of U_i(x).
1407    fn derivative_u(
1408        link: &LatticeLinkCanonical<D>,
1409        link_matrix: &LinkMatrix,
1410        e_field: &EField<D>,
1411        lattice: &LatticeCyclic<D>,
1412    ) -> Option<CMatrix3> {
1413        let c = Complex::new(0_f64, (2_f64 * Self::CA).sqrt());
1414        let u_i = link_matrix.matrix(&LatticeLink::from(*link), lattice)?;
1415        let e_i = e_field.e_field(link.pos(), link.dir(), lattice)?;
1416        Some(e_i.to_matrix() * u_i * c * Complex::from(1_f64 / lattice.size()))
1417    }
1418
1419    /// Get the derive of E(x) (as a vector of Su3Adjoint).
1420    fn derivative_e(
1421        point: &LatticePoint<D>,
1422        link_matrix: &LinkMatrix,
1423        _e_field: &EField<D>,
1424        lattice: &LatticeCyclic<D>,
1425    ) -> Option<SVector<Su3Adjoint, D>> {
1426        let c = -(2_f64 / Self::CA).sqrt();
1427        let dir_pos = Direction::<D>::positive_directions();
1428        let iterator = dir_pos.iter().map(|dir| {
1429            let u_i = link_matrix.matrix(&LatticeLink::new(*point, *dir), lattice)?;
1430            let sum_s: CMatrix3 = Direction::<D>::directions()
1431                .iter()
1432                .filter(|dir_2| dir_2.to_positive() != *dir)
1433                .map(|dir_2| {
1434                    link_matrix
1435                        .sij(point, dir, dir_2, lattice)
1436                        .map(|el| el.adjoint())
1437                })
1438                .sum::<Option<CMatrix3>>()?;
1439            Some(Su3Adjoint::new(Vector8::<Real>::from_fn(|index, _| {
1440                c * (su3::GENERATORS[index] * u_i * sum_s).trace().imaginary() / lattice.size()
1441            })))
1442        });
1443        let mut return_vector = SVector::<_, D>::from_element(Su3Adjoint::default());
1444        for (index, element) in iterator.enumerate() {
1445            return_vector[index] = element?;
1446        }
1447        Some(return_vector)
1448    }
1449}
1450
1451#[cfg(test)]
1452mod test {
1453
1454    use super::*;
1455    use crate::error::StateInitializationError;
1456
1457    #[test]
1458    fn leap_frog_simulation() -> Result<(), StateInitializationError> {
1459        let state =
1460            LatticeStateEFSyncDefault::<LatticeStateDefault<3>, 3>::new_cold(1_f64, 6_f64, 4)?;
1461
1462        let mut leap_frog = SimulationStateLeap::new_from_state(state.clone());
1463        assert_eq!(&state, leap_frog.as_ref());
1464
1465        assert_eq!(
1466            state.gauss(&LatticePoint::default()),
1467            leap_frog.gauss(&LatticePoint::default())
1468        );
1469
1470        let _: &mut LatticeStateEFSyncDefault<LatticeStateDefault<3>, 3> = leap_frog.as_mut();
1471        Ok(())
1472    }
1473}