pub fn generate(
transitions: &std::collections::HashMap<u32, Vec<(u32, f32)>>,
start_state: u32,
length: usize,
) -> Vec<u32> {
use rand::Rng;
let mut rng = rand::rng();
let mut sequence = vec![start_state];
let mut current_state = start_state;
for _ in 1..length {
if let Some(options) = transitions.get(¤t_state) {
if options.is_empty() {
break; }
let total_weight: f32 = options.iter().map(|(_, weight)| weight).sum();
if total_weight <= 0.0 {
break; }
let mut random_value = rng.random_range(0.0..total_weight);
for (state, weight) in options {
random_value -= weight;
if random_value <= 0.0 {
current_state = *state;
break;
}
}
} else {
break;
}
sequence.push(current_state);
}
sequence
}
pub fn build_markov_transitions(
data: &[u32],
_order: usize, ) -> std::collections::HashMap<u32, Vec<(u32, f32)>> {
use std::collections::HashMap;
let mut transition_counts: HashMap<u32, HashMap<u32, u32>> = HashMap::new();
for i in 0..data.len().saturating_sub(1) {
let current = data[i];
let next = data[i + 1];
transition_counts
.entry(current)
.or_default()
.entry(next)
.and_modify(|count| *count += 1)
.or_insert(1);
}
let mut transitions: HashMap<u32, Vec<(u32, f32)>> = HashMap::new();
for (state, next_states) in transition_counts {
let total: u32 = next_states.values().sum();
let total_f32 = total as f32;
let weighted_options: Vec<(u32, f32)> = next_states
.into_iter()
.map(|(next_state, count)| (next_state, count as f32 / total_f32))
.collect();
transitions.insert(state, weighted_options);
}
transitions
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn test_markov_chain_basic() {
let mut transitions = HashMap::new();
transitions.insert(0, vec![(1, 1.0)]);
transitions.insert(1, vec![(2, 1.0)]);
transitions.insert(2, vec![(0, 1.0)]);
let seq = generate(&transitions, 0, 7);
assert_eq!(seq, vec![0, 1, 2, 0, 1, 2, 0]);
}
#[test]
fn test_build_markov_transitions_simple() {
let data = vec![0, 1, 0, 1, 0, 1];
let transitions = build_markov_transitions(&data, 1);
assert!(transitions.contains_key(&0));
let from_0 = &transitions[&0];
assert_eq!(from_0.len(), 1);
assert_eq!(from_0[0].0, 1);
}
}
pub fn c_major_melody() -> Vec<u32> {
let mut transitions = std::collections::HashMap::new();
transitions.insert(0, vec![(0, 0.2), (1, 0.5), (2, 0.3)]);
transitions.insert(1, vec![(0, 0.3), (2, 0.6), (3, 0.1)]);
transitions.insert(2, vec![(1, 0.3), (4, 0.5), (0, 0.2)]);
transitions.insert(4, vec![(2, 0.4), (0, 0.6)]);
generate(&transitions, 0, 16)
}
pub fn up_down() -> Vec<u32> {
let training = vec![0, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1];
let transitions = build_markov_transitions(&training, 1);
generate(&transitions, 0, 24)
}
pub fn classic() -> Vec<u32> {
c_major_melody()
}