1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
use prelude::*; use std::collections::HashMap; pub enum Command<'a> { Define(&'a str, Vec<&'a str>, NodeRc), Expr(NodeRc), Eval(NodeRc), Bench(NodeRc) } pub struct EvalContext { builder: Builder, defines: HashMap<String, f64> } impl EvalContext { pub fn new() -> EvalContext { EvalContext { builder: Builder::new(), defines: HashMap::new() } } pub fn eval(&self, node: &Node) -> Result<f64, Error> { use func::Transient::*; use func::Func; match *node { Node::Poly(ref p) => { let mut sum = 0.0; for (base, r) in p.factors() { let mut prod = r.to_f64(); for &(ref f, n) in base.iter() { prod *= self.eval(f)?.powi(n.cast().ok_or(Error::Overflow)?); } sum += prod; } Ok(sum) } Node::Apply(ref f, ref g) => { let x = self.eval(g)?; match **f { Node::Op(Func::Transient(f)) => Ok(match f { Sin => x.sin(), Cos => x.cos(), Log => x.ln(), Exp => x.exp() }), _ => todo!("apply non transients") } }, Node::Op(_) => todo!("?"), Node::Var(ref s) => self.defines.get(s).cloned().ok_or(Error::Undefined(s.clone())), _ => unimplemented!() } } pub fn set(&mut self, var: &str, val: f64) { self.defines.insert(var.into(), val); } pub fn get(&self, var: &str) -> Option<f64> { self.defines.get(var).cloned() } #[cfg(target_feature = "avx")] fn bench(&self, expr: NodeRc) -> Result<String, Error> { use std::time::Instant; use simd::x86::avx::f32x8; use rt::simd_jit::jit; let code = jit(&[expr], &["x"])?; let data_in = vec![f32x8::splat(self.get("x").unwrap_or(0.1) as f32); code.num_inputs]; let mut data_out = vec![f32x8::splat(0.0); code.num_outputs]; let n = 1024*1024; let t0 = Instant::now(); code.bench(&data_in, &mut data_out, n/8); let dt = t0.elapsed(); Ok(format!("{} values/s", n as f64 / duration_as_seconds(dt))) } pub fn run(&mut self, input: &str) -> Result<Option<String>, Error> { use lang::parse_Command; use self::Command::*; let cmd = match parse_Command(&self.builder, input) { Ok(r) => r?, Err(e) => return Err(Error::parse_error(e, input)) }; #[allow(unreachable_patterns)] Ok(match cmd { Define(f, args, expr) => { self.builder.define(f, &args, expr); None }, Expr(e) => Some(e.to_string()), Eval(e) => Some(self.eval(&e)?.to_string()), #[cfg(target_feature="avx")] Bench(e) => Some(self.bench(e)?), _ => None }) } }