1
#![forbid(unsafe_code)]
2

            
3
use rand::Rng;
4
use rustc_hash::FxHashSet;
5

            
6
use crate::ATerm;
7
use crate::Symbol;
8
use crate::Term;
9
use crate::storage::THREAD_TERM_POOL;
10

            
11
/// Create a random term consisting of the given symbol and constants. Performs
12
/// iterations number of constructions, and uses chance_duplicates to choose the
13
/// amount of subterms that are duplicated.
14
104000
pub fn random_term(rng: &mut impl Rng, symbols: &[(String, usize)], constants: &[String], iterations: usize) -> ATerm {
15
    use rand::prelude::IteratorRandom;
16

            
17
104000
    debug_assert!(!constants.is_empty(), "We need constants to be able to create a term");
18

            
19
104000
    let mut subterms = THREAD_TERM_POOL.with_borrow(|tp| {
20
108000
        FxHashSet::<ATerm>::from_iter(constants.iter().map(|name| {
21
108000
            let symbol = tp.create_symbol(name, 0);
22
108000
            let a: &[ATerm] = &[];
23
108000
            tp.create_term(&symbol, a).protect()
24
108000
        }))
25
104000
    });
26

            
27
104000
    let mut result = None;
28
104000
    for _ in 0..iterations {
29
1004000
        let (symbol, arity) = symbols.iter().choose(rng).unwrap();
30

            
31
1004000
        let mut arguments = vec![];
32
1505099
        for _ in 0..*arity {
33
1505099
            arguments.push(subterms.iter().choose(rng).unwrap().clone());
34
1505099
        }
35

            
36
1004000
        let symbol = Symbol::new(symbol, *arity);
37
1004000
        let term = ATerm::with_args(&symbol, &arguments).protect();
38

            
39
        // Make this term available as another subterm that can be used.
40
1004000
        subterms.insert(term.clone());
41

            
42
1004000
        result = Some(term);
43
    }
44

            
45
104000
    result.expect("At least one iteration was performed")
46
104000
}