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
//! Let's abstract an alloy

use rand::{distributions::WeightedIndex, prelude::Distribution, Rng};

/// An alloy is a collection of kinds of atoms and their ratios
///
/// It is used to pick a kind of atom from the alloy.
///
/// # Example
///
/// ```rust
/// use vegas_lattice::Alloy;
///
/// let alloy = Alloy::new(vec!["Fe", "Ni"], vec![1, 2]);
/// let kind = alloy.pick(&mut rand::thread_rng());
///
/// assert!(kind == "Fe" || kind == "Ni");
/// ```
#[derive(Debug)]
pub struct Alloy {
    kinds: Vec<String>,
    weights: WeightedIndex<u32>,
}

impl Alloy {
    /// Create a new alloy with a given list of kinds and their ratios
    pub fn new(kinds: Vec<&str>, ratios: Vec<u32>) -> Self {
        debug_assert!(kinds.len() == ratios.len());
        Self {
            kinds: kinds.into_iter().map(|s| s.to_owned()).collect(),
            weights: WeightedIndex::new(&ratios).unwrap(),
        }
    }

    /// Picks a kind of atom from the alloy
    pub fn pick<R: Rng + ?Sized>(&self, rng: &mut R) -> String {
        self.kinds[self.weights.sample(rng)].clone()
    }
}