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
use{
    crate::{wang_landau::*, Histogram},
    std::io::Write
};

/// # Traits for quantities that all Wang Landau simulations have
/// * see also: `WangLandauHist`
/// * this trait is for convinience, so that you do not have
/// to write all the trait bounds of, e.g.,  `WangLandauHist`, if you are
/// not using functuinality, that requires it
pub trait WangLandau
{
    /// get current value of log_f
    fn log_f(&self) -> f64;

    /// # returns currently set threshold for log_f
    fn log_f_threshold(&self) -> f64;
    
    /// Try to set the threshold. 
    /// * `log_f_threshold > 0.0` has to be true
    /// * `log_f_threshold` has to be finite
    fn set_log_f_threshold(&mut self, log_f_threshold: f64) -> Result<f64, WangLandauErrors>;
    
    /// # Checks wang landau threshold
    /// * `log_f <= log_f_threshold`
    #[inline(always)]
    fn is_finished(&self) -> bool
    {
        self.log_f() <= self.log_f_threshold()
    }
    
    /// # Current (non normalized) estimate of ln(P(E))
    /// * i.e., of the natural logarithm of the 
    /// probability density function
    /// for the requested interval
    /// * this is what we are doing the simulations for
    fn log_density(&self) -> &Vec<f64>;

    /// # Current (non normalized) estimate of log10(P(E))
    /// * i.e., of logarithm with base 10 of the 
    /// probability density function
    /// for the requested interval
    /// * this is what we are doing the simulations for
    fn log_density_base10(&self) -> Vec<f64>{
        self.log_density()
            .iter()
            .map(|val| val * std::f64::consts::LOG10_E)
            .collect()
    }

    /// # Current (non normalized) estimate of log_base(P(E))
    /// * i.e., of logarithm with arbitrary base of the 
    /// probability density function
    /// for the requested interval
    /// * this is what we are doing the simulations for
    fn log_density_base(&self, base: f64) -> Vec<f64>{
        let factor = std::f64::consts::E.log(base);
        self.log_density()
            .iter()
            .map(|val| val * factor)
            .collect()
    }

    /// Writes Information about the simulation to a file.
    /// E.g. How many steps were performed.
    fn write_log<W: Write>(&self, writer: W) -> Result<(), std::io::Error>;
    
    /// # Returns current wang landau mode
    /// * see `WangLandauMode` for an explaination
    fn mode(&self) -> WangLandauMode;
    
    /// # Counter
    /// * how many wang Landau steps were performed until now?
    /// * this does not include steps, that were perfored to find a inital valid ensemble
    fn step_counter(&self) -> usize;

    /// # Counter
    /// * how many wang Landau steps were performed until now?
    /// * this includes steps, that were perfored to find a inital valid ensemble
    fn steps_total(&self) -> usize{
        self.total_steps_accepted() + self.total_steps_rejected()
    }

    /// # How many steps were accepted until now?
    /// * this includes steps, that were perfored to find a inital valid ensemble
    fn total_steps_accepted(&self) -> usize;

    /// # How many steps were rejected until now?
    /// * this includes steps, that were perfored to find a inital valid ensemble
    fn total_steps_rejected(&self) -> usize;

    /// # Calculate, which fraction of steps were accepted
    /// * this includes steps, that were perfored to find a inital valid ensemble
    /// * if no steps were performed, it returns `f64::NAN`
    fn fraction_accepted_total(&self) -> f64 {
        let total_acc = self.total_steps_accepted();
        let total_steps = total_acc + self.total_steps_rejected();

        if total_steps == 0 {
            f64::NAN
        } else {
            total_acc as f64 / total_steps as f64
        }
    }

    /// # Calculate, which fraction of steps were rejected
    /// * this includes steps, that were perfored to find a inital valid ensemble
    /// * if no steps were performed, it returns `f64::NAN`
    fn fraction_rejected_total(&self) -> f64 {
        let total_rej = self.total_steps_rejected();
        let total_steps = total_rej + self.total_steps_accepted();

        if total_steps == 0 {
            f64::NAN
        } else {
            total_rej as f64 / total_steps as f64
        }
    }
}


/// # trait to request a reference to the current (state of the) ensemble 
/// * See also [WangLandauEEH](trait.WangLandauEEH.html)
pub trait WangLandauEnsemble<E> : WangLandau
{
    /// return reference to current state of ensemble
    fn ensemble(&self) -> &E;

    /// # mutable reference to current state
    /// * **unsafe** you should not make any changes, that effect the energy state of the system.
    /// otherwise the WangLandau simulations will give false results!
    unsafe fn ensemble_mut(&mut self) -> &mut E;
}

/// # trait to request the current histogram from a WangLandau simulation
/// * Note: The histogram will likely be reset multiple times during a simulation
/// * See also [WangLandauEEH](trait.WangLandauEEH.html)
pub trait WangLandauHist<Hist> : WangLandau
{
    /// # returns current histogram
    /// * **Note**: histogram will be reset multiple times during the simulation
    /// * please refere to the [papers](struct.WangLandauAdaptive.html#adaptive-wanglandau-1t)
    fn hist(&self) -> &Hist;
}

/// # trait to request the current energy from a WangLandau simulation
/// * `None` if the energy was not calculated yet
/// * See also [WangLandauEEH](trait.WangLandauEEH.html)
pub trait WangLandauEnergy<Energy> : WangLandau
{
    /// returns the last accepted `Energy` calculated
    /// `None` if no energy was calculated yet
    fn energy(&self) -> Option<&Energy>;
}

/// Helper trait, so that you have to type less
pub trait WangLandauEEH<E, Hist, Energy> 
    : WangLandauEnergy<Energy> + WangLandauEnsemble<E>
        + WangLandauHist<Hist>{}

impl<A, E, Hist, Energy> WangLandauEEH<E, Hist, Energy> for A
    where 
    A: WangLandauEnergy<Energy> 
        + WangLandauEnsemble<E>
        + WangLandauHist<Hist>{}

pub(crate) trait WangLandau1TCalc<Hist> : WangLandauHist<Hist>
where Hist: Histogram{
    #[inline(always)]
    fn log_f_1_t(&self) -> f64 
    {
        self.hist().bin_count() as f64 / self.step_counter() as f64
    }
}

impl<A, Hist> WangLandau1TCalc<Hist> for A
    where A: WangLandauHist<Hist>,
    Hist: Histogram{}