pub struct Chain<T, M: Map<T> = BTree> { /* private fields */ }
Expand description
A Markov chain.
This type implements Serialize
and Deserialize
when the
serde
feature is enabled (which it is by default).
Implementations§
Source§impl<T, M: Map<T>> Chain<T, M>
impl<T, M: Map<T>> Chain<T, M>
Sourcepub fn new(depth: usize) -> Self
pub fn new(depth: usize) -> Self
Creates a new chain.
See Self::depth
for an explanation of the depth.
Examples found in repository?
19fn main() -> io::Result<()> {
20 const DEPTH: usize = 6;
21 // Maps each sequence of 6 items to a list of possible next items.
22 // `HashChain` uses hash maps internally; b-trees can also be used.
23 let mut chain = HashChain::new(DEPTH);
24
25 // In this case, corpus.txt contains one paragraph per line.
26 let file = File::open("examples/corpus.txt")?;
27 let mut reader = BufReader::new(file);
28 let mut line = String::new();
29 // The previous `DEPTH` characters before `line`.
30 let mut prev = Vec::<char>::new();
31
32 while let Ok(1..) = reader.read_line(&mut line) {
33 // `Both` means that the generated random output could start with the
34 // beginning of `line` or end after the end of `line`.
35 chain.add_all(line.chars(), AddEdges::Both);
36
37 // This makes sure there's a chance that the end of the previous line
38 // could be followed by the start of the current line when generating
39 // random output.
40 chain.add_all(
41 prev.iter().copied().chain(line.chars().take(DEPTH)),
42 AddEdges::Neither,
43 );
44
45 if let Some((n, (i, _c))) =
46 line.char_indices().rev().enumerate().take(DEPTH).last()
47 {
48 // Keep only the most recent `DEPTH` characters.
49 prev.drain(0..prev.len().saturating_sub(DEPTH - n - 1));
50 prev.extend(line[i..].chars());
51 }
52 line.clear();
53 }
54
55 // Generate and print random Markov data.
56 let mut stdout = BufWriter::new(io::stdout().lock());
57 let mut prev_newline = false;
58 for &c in chain.generate() {
59 if prev_newline {
60 writeln!(stdout)?;
61 }
62 prev_newline = c == '\n';
63 write!(stdout, "{c}")?;
64 }
65 stdout.flush()
66}
Sourcepub fn depth(&self) -> usize
pub fn depth(&self) -> usize
Gets the chain’s depth.
A depth of n
means the chain maps sequences of n
items of type T
to a list of possible next items.
Sourcepub fn add_all<I>(&mut self, items: I, edges: AddEdges)where
I: IntoIterator<Item = T>,
T: Clone,
pub fn add_all<I>(&mut self, items: I, edges: AddEdges)where
I: IntoIterator<Item = T>,
T: Clone,
Adds all items in an iterator to the chain.
This essentially calls Self::add
on every overlapping window
of self.depth()
elements plus the item following each window.
(Smaller windows at the start of the sequence may also be added
depending on the value of edges
.)
edges
controls whether the start or end of items
may be used as the
start or end of a generated sequence from the chain. See the
documentation for AddEdges
for more information.
Examples found in repository?
19fn main() -> io::Result<()> {
20 const DEPTH: usize = 6;
21 // Maps each sequence of 6 items to a list of possible next items.
22 // `HashChain` uses hash maps internally; b-trees can also be used.
23 let mut chain = HashChain::new(DEPTH);
24
25 // In this case, corpus.txt contains one paragraph per line.
26 let file = File::open("examples/corpus.txt")?;
27 let mut reader = BufReader::new(file);
28 let mut line = String::new();
29 // The previous `DEPTH` characters before `line`.
30 let mut prev = Vec::<char>::new();
31
32 while let Ok(1..) = reader.read_line(&mut line) {
33 // `Both` means that the generated random output could start with the
34 // beginning of `line` or end after the end of `line`.
35 chain.add_all(line.chars(), AddEdges::Both);
36
37 // This makes sure there's a chance that the end of the previous line
38 // could be followed by the start of the current line when generating
39 // random output.
40 chain.add_all(
41 prev.iter().copied().chain(line.chars().take(DEPTH)),
42 AddEdges::Neither,
43 );
44
45 if let Some((n, (i, _c))) =
46 line.char_indices().rev().enumerate().take(DEPTH).last()
47 {
48 // Keep only the most recent `DEPTH` characters.
49 prev.drain(0..prev.len().saturating_sub(DEPTH - n - 1));
50 prev.extend(line[i..].chars());
51 }
52 line.clear();
53 }
54
55 // Generate and print random Markov data.
56 let mut stdout = BufWriter::new(io::stdout().lock());
57 let mut prev_newline = false;
58 for &c in chain.generate() {
59 if prev_newline {
60 writeln!(stdout)?;
61 }
62 prev_newline = c == '\n';
63 write!(stdout, "{c}")?;
64 }
65 stdout.flush()
66}
Sourcepub fn add<I>(&mut self, items: I, next: Option<T>)where
I: IntoIterator<Item = T>,
pub fn add<I>(&mut self, items: I, next: Option<T>)where
I: IntoIterator<Item = T>,
Adds items to the chain.
If items
yields at least self.depth()
items, this increases the
chance that the first self.depth()
items will be followed by next
in a generated sequence (additional items in items
are ignored).
If items
yields fewer than self.depth()
items, this method
increases the chance that those items, when they are the only items
that have been generated so far in a sequence (i.e., the start of a
sequence), will be followed by next
. In the case where items
yields
no elements, this increases the chance that item
will be produced as
the first element of a generated sequence.
If next
is None
, this method increases the chance that items
will
be considered the end of a sequence.
Sourcepub fn generate(&self) -> Generator<'_, T, ThreadRng, M> ⓘ
Available on crate feature std
only.
pub fn generate(&self) -> Generator<'_, T, ThreadRng, M> ⓘ
std
only.Generates random Markov chain data.
Returns an iterator that yields the elements by reference. If you want
them by value, simply use Iterator::cloned
(as long as T
is
Clone
).
Examples found in repository?
19fn main() -> io::Result<()> {
20 const DEPTH: usize = 6;
21 // Maps each sequence of 6 items to a list of possible next items.
22 // `HashChain` uses hash maps internally; b-trees can also be used.
23 let mut chain = HashChain::new(DEPTH);
24
25 // In this case, corpus.txt contains one paragraph per line.
26 let file = File::open("examples/corpus.txt")?;
27 let mut reader = BufReader::new(file);
28 let mut line = String::new();
29 // The previous `DEPTH` characters before `line`.
30 let mut prev = Vec::<char>::new();
31
32 while let Ok(1..) = reader.read_line(&mut line) {
33 // `Both` means that the generated random output could start with the
34 // beginning of `line` or end after the end of `line`.
35 chain.add_all(line.chars(), AddEdges::Both);
36
37 // This makes sure there's a chance that the end of the previous line
38 // could be followed by the start of the current line when generating
39 // random output.
40 chain.add_all(
41 prev.iter().copied().chain(line.chars().take(DEPTH)),
42 AddEdges::Neither,
43 );
44
45 if let Some((n, (i, _c))) =
46 line.char_indices().rev().enumerate().take(DEPTH).last()
47 {
48 // Keep only the most recent `DEPTH` characters.
49 prev.drain(0..prev.len().saturating_sub(DEPTH - n - 1));
50 prev.extend(line[i..].chars());
51 }
52 line.clear();
53 }
54
55 // Generate and print random Markov data.
56 let mut stdout = BufWriter::new(io::stdout().lock());
57 let mut prev_newline = false;
58 for &c in chain.generate() {
59 if prev_newline {
60 writeln!(stdout)?;
61 }
62 prev_newline = c == '\n';
63 write!(stdout, "{c}")?;
64 }
65 stdout.flush()
66}
Sourcepub fn generate_with_rng<R: Rng>(&self, rng: R) -> Generator<'_, T, R, M> ⓘ
pub fn generate_with_rng<R: Rng>(&self, rng: R) -> Generator<'_, T, R, M> ⓘ
Like Self::generate
, but takes a custom random number generator.
Sourcepub fn get<'a, B>(&'a self, items: &[B]) -> Option<&'a T>where
B: Borrow<T>,
Available on crate feature std
only.
pub fn get<'a, B>(&'a self, items: &[B]) -> Option<&'a T>where
B: Borrow<T>,
std
only.Gets a random item that has followed items
in the added data.
If items
yields more than self.depth()
items, only the first
self.depth()
items are considered. If items
yields fewer than
self.depth()
items (potentially zero), those items are interpreted
as the beginning of a generated sequence.