1use crate::expr::Expr;
2use crate::prng::PRNG;
3
4extern crate anyhow;
5use anyhow::{bail, Result};
6
7macro_rules! assert_arity {
8 (= $arity:expr, $term:expr) => {
9 if $arity != $term.1.len() {
10 bail!("Arity Error: {} required {} args", $term.0, $arity);
11 }
12 };
13 (<= $arity:expr, $term:expr) => {
14 if $arity < $term.1.len() {
15 bail!("Arity Error: {} required <= {} args", $term.0, $arity);
16 }
17 };
18}
19
20pub fn eval(expr: &Expr) -> Result<f64> {
21 let mut rng = PRNG::new();
22 let mut ret: f64 = 0.0;
23 for t in expr.code.iter() {
24 match t.0.as_str() {
25 "seed" => {
26 assert_arity!(= 1, &t);
27 let state = t.1[0] as u64;
28 rng.setseed(state);
29 }
30 "int" | "floor" => {
31 assert_arity!(= 0, &t);
32 ret = ret.floor();
33 }
34 "round" => {
35 assert_arity!(= 0, &t);
36 ret = ret.round();
37 }
38 "uniform" => {
39 assert_arity!(<= 2, &t);
40 let args = fillarg(&t.1, &mut vec![0.0, 1.0]);
41 if args[0] >= args[1] {
42 bail!("uniform required non-empty range");
43 }
44 ret = rng.uniform(args[0], args[1]);
45 }
46 "gauss" | "gaussian" | "normal" | "norm" => {
47 assert_arity!(<= 2, &t);
48 let args = fillarg(&t.1, &mut vec![0.0, 1.0]);
49 if args[1] <= 0.0 {
50 bail!("variance for gauss must be positive");
51 }
52 ret = rng.gaussian(args[0], args[1]);
53 }
54 "exp" | "exponential" => {
55 assert_arity!(<= 1, &t);
56 let args = fillarg(&t.1, &mut vec![1.0]);
57 if args[0] <= 0.0 {
58 bail!("lambda for exp must be positive");
59 }
60 ret = rng.exponential(args[0]);
61 }
62 "binom" => {
63 assert_arity!(= 2, &t);
64 let n = t.1[0] as usize;
65 let p = t.1[1];
66 if n as f64 != t.1[0] {
67 bail!("n for binom must be unsigned int");
68 }
69 if p < 0.0 || p > 1.0 {
70 bail!("p for binom must be `0 <= p <= 1`");
71 }
72 ret = rng.binom(n, p);
73 }
74 "bernoulli" => {
75 assert_arity!(<= 1, &t);
76 let args = fillarg(&t.1, &mut vec![0.5]);
77 let p = args[0];
78 if p < 0.0 || p > 1.0 {
79 bail!("p for bernoulli must be `0 <= p <= 1`");
80 }
81 ret = rng.binom(1, p);
82 }
83 _ => {
84 bail!("Unknown function: {}", t.0);
85 }
86 }
87 }
88 Ok(ret)
89}
90
91fn fillarg(given: &Vec<f64>, args: &mut Vec<f64>) -> Vec<f64> {
92 let n = given.len();
93 let m = args.len();
94 for i in 0..n.min(m) {
95 args[i] = given[i];
96 }
97 args.to_vec()
98}