Skip to main content

linked_markov/
lib.rs

1//! # linked-markov
2//!
3//! A minimal, thread-safe Markov chain implementation using reference-counted steps and weighted transitions.
4//!
5//! ## Features
6//! - Generic over state type `T` (must be `Eq + Copy + Hash + Debug`)
7//! - Weighted transitions between states
8//! - Deterministic and mutable walks
9//!
10//! ## Examples
11//! ```rust
12//! use linked_markov::{Step, ToStep, walk};
13//! use std::sync::Arc;
14//!
15//! let step_false: ToStep<bool> = Arc::new(Step::new(false));
16//! let step_true: ToStep<bool> = Arc::new(Step::new(true));
17//! step_false.insert_transition(step_true.clone(), 3);
18//! step_false.insert_transition(step_false.clone(), 1);
19//! step_true.insert_transition(step_false.clone(), 3);
20//! step_true.insert_transition(step_true.clone(), 1);
21//! let path = walk(step_false, 100);
22//! assert_eq!(path.len(), 100);
23//! ```
24mod step;
25pub use step::{Step, ToStep, mut_walk, walk};
26
27#[cfg(test)]
28mod tests {
29    use std::sync::Arc;
30
31    use super::*;
32
33    #[test]
34    fn two_state_walk() {
35        let step_false: ToStep<bool> = Arc::new(Step::new(false));
36        let step_true: ToStep<bool> = Arc::new(Step::new(true));
37
38        step_false.insert_transition(step_true.clone(), 3);
39        step_false.insert_transition(step_false.clone(), 1);
40        step_true.insert_transition(step_false.clone(), 3);
41        step_true.insert_transition(step_true.clone(), 1);
42        let path = walk(step_false, 100);
43        assert_eq!(path.len(), 100);
44        assert!(path.contains(&false));
45        assert!(path.contains(&true));
46    }
47
48    #[test]
49    fn two_state_mut_walk() {
50        let step_false: ToStep<bool> = Arc::new(Step::new(false));
51        let step_true: ToStep<bool> = Arc::new(Step::new(true));
52
53        step_false.insert_transition(step_true.clone(), 1);
54        step_false.insert_transition(step_false.clone(), 1);
55        step_true.insert_transition(step_false.clone(), 1);
56        step_true.insert_transition(step_true.clone(), 1);
57        let path = mut_walk(step_false.clone(), 100, |current, next| {
58            current
59                .transitions
60                .write()
61                .unwrap()
62                .entry(next)
63                .and_modify(|e| *e += 1)
64                .or_insert(1);
65            Ok(())
66        })
67        .unwrap();
68        let step_true_count = step_true
69            .transitions
70            .read()
71            .unwrap()
72            .values()
73            .sum::<usize>();
74        let step_false_count = step_false
75            .transitions
76            .read()
77            .unwrap()
78            .values()
79            .sum::<usize>();
80        assert_eq!(path.len(), 100);
81        assert!(path.contains(&false));
82        assert!(path.contains(&true));
83        assert_eq!(step_true_count + step_false_count, 103);
84    }
85}