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
use{
    crate::{*, glue_helper::*},
    std::cmp::*
};


/// # Combine multiple WangLandau intervals to get the probability distribution of the whole interval
/// * `list`: Vector/slice of Wang landau distributions.
/// # Restrictions
/// * `original_hist` has to contain all the borders of the histograms.
/// Meaning: The size of a bin has to be constant among all histograms of the `list`.
/// If it is not, you might get an error, or you might get wrong results. 
/// **I do not check for this exaustingly**.
/// * There is an **easy way** to make sure, that you don`t get problems here:
/// Create the `original_hist` first. Then create the other Histograms using the `HistogramPartion` trait.
/// This is the intended way. But as long as the borders and bin sizes match, this function will work properly
/// # Understanding returned Parameters (OK(..)):
pub fn glue_entropic<Entr, HIST, T>(list: &[Entr], original_hist: &HIST) -> Result<GlueResult<T>, GlueErrors>
where Entr: EntropicHist<HIST>,
    HIST: Histogram + HistogramVal<T>,
    T: PartialOrd,
{
    if list.is_empty(){
        return Err(GlueErrors::EmptyList);
    }

    let total_steps = list.iter()
        .fold(0_usize, |acc, wl| acc + wl.steps_total());
    let total_steps_accepted = list.iter()
        .fold(0_usize, |acc, wl| acc + wl.total_steps_accepted());
    let total_steps_rejected = list.iter()
        .fold(0, |acc, wl| acc + wl.total_steps_rejected());

    let mut list: Vec<_> = list.iter().collect();

    // sort
    list.sort_unstable_by(|a, b| {
            a.hist()
                .first_border()
                .partial_cmp(
                    &b.hist()
                    .first_border()
                ).unwrap_or(Ordering::Less)
        }
    );
    
    let borders = original_hist.borders_clone()
        .map_err(GlueErrors::BorderCreation)?;

    let mut left_list = Vec::with_capacity(list.len());
    let mut right_list = Vec::with_capacity(list.len());
    for &entr in list.iter()
    {
        left_list.push(get_index(&entr.hist().first_border(), &borders)?);
        right_list.push(get_index(&entr.hist().second_last_border(), &borders)?);
    }

    // get log densitys
    let mut log10_vec: Vec<_> = list.iter()
        .map(|&entr| entr.log_density_base10())
        .collect();

    // re-normalize to prevent later precision problems
    inner_subtract_max(&mut log10_vec);

    // calc z
    let z_vec = calc_z(&log10_vec, &left_list, &right_list)?;

    // correct height
    height_correction(&mut log10_vec, &z_vec);

    // glueing together
    let mut glue_log_density = glue(original_hist.bin_count(), &log10_vec, &left_list, &right_list)?;

    // now norm the result
    norm_log10_sum_to_1(&mut glue_log_density);
    
    let glue_res = GlueResult{
        total_steps_rejected,
        total_steps_accepted,
        total_steps,
        log10_vec,
        glued_log10_probability: glue_log_density,
        left_list,
        borders,
    };
    Ok(glue_res)
}