#![warn(missing_docs)]
#[allow(unused_attributes)]
#[macro_use]
pub use r_gen_macro::r_gen;
#[allow(unused_imports)]
#[macro_use]
extern crate r_gen_macro;
#[macro_export]
macro_rules! sample {
($sample_ident:ident $trace_ident:ident $name:ident ~ $dist:expr) => (
let $name = (Rc::get_mut(&mut $sample_ident).unwrap())(&String::from(stringify!($name)), $dist, $trace_ident);
);
($sample_ident:ident $trace_ident:ident $name:ident => $i:ident ~ $dist:expr) => (
let mut s = String::from(stringify!($name));
s.push_str("[");
s.push_str(&$i.to_string());
s.push_str("]");
$name[$i] = (Rc::get_mut(&mut $sample_ident).unwrap())(&s, $dist, $trace_ident);
);
($sample_ident:ident $trace_ident:ident $name:ident [ $i:ident ] ~ $dist:expr) => (
let mut s = String::from(stringify!($name));
s.push_str("[");
s.push_str(&$i.to_string());
s.push_str("]");
$name[$i] = (Rc::get_mut(&mut $sample_ident).unwrap())(&s, $dist, $trace_ident);
);
}
#[allow(unused_variables)]
#[cfg(test)]
mod tests {
use std::rc::Rc;
use crate::{trace::{Trace, Choicemap}, distributions::{Distribution, Value}};
use crate::{simulate, generate};
#[test]
fn test_simulate(){
fn flip_biased_coin(mut sample : Rc<dyn FnMut(&String, Distribution, &mut Trace) -> Value>, trace : &mut Trace, p : f64) {
(Rc::get_mut(&mut sample).unwrap())(&String::from("flip"), Distribution::Bernoulli(p), trace);
}
let (t, _) : (Trace, _)= simulate(&mut flip_biased_coin, 0.2);
println!("test_simulate flip_biased_coin trace: {:?}", t);
fn flip_multiple_biased_coins(mut sample : Rc<dyn FnMut(&String, Distribution, &mut Trace) -> Value>, trace : &mut Trace, (n, p) : (i64, f64)) {
(Rc::get_mut(&mut sample).unwrap())(&String::from("heads"), Distribution::Binomial(n, p), trace);
}
let (t, _) : (Trace, _)= simulate(&mut flip_multiple_biased_coins, (5, 0.7));
println!("test_simulate flip_multiple_biased_coin trace: {:?}", t);
}
#[test]
fn test_generate(){
#[r_gen]
fn flip_multiple_biased_coins((n, p) : (i64, f64)) {
sample!(heads ~ Distribution::Binomial(n, p));
println!("Result of flips: {:?}", heads)
}
let mut constraints = Choicemap::new();
constraints.add_choice("heads", Value::Integer(4));
let (trace, _) : (Trace, _)= generate(&mut flip_multiple_biased_coins, (5, 0.7), &constraints);
println!("Trace from generate: {:?}", trace);
}
#[test]
fn test_macros(){
#[r_gen]
fn my_coin_model(p : f64) {
sample!(flip ~ Distribution::Bernoulli(p));
println!("Result of flip: {:?}", flip)
}
let (trace, _) = simulate(&mut my_coin_model, 0.2);
println!("testing macro: {:?}", trace);
#[r_gen]
fn flip_multiple_biased_coins((n, p) : (i64, f64)) {
sample!(heads ~ Distribution::Binomial(n, p));
println!("Result of flips: {:?}", heads)
}
let (trace, _) : (Trace, _)= simulate(&mut flip_multiple_biased_coins, (5, 0.7));
println!("tesing macro: {:?}", trace);
#[r_gen]
fn flip_my_biased_coin((n, p) : (usize, f64)) {
let mut flips = vec![Value::Integer(0); n];
for i in 0..n {
sample!(flips => i ~ Distribution::Bernoulli(p));
}
}
let (trace, _) : (Trace, _)= simulate(&mut flip_my_biased_coin, (5 as usize, 0.7));
println!("my flip coin trace: {:?}", trace);
#[r_gen]
fn flip_my_biased_coin2((n, p) : (usize, f64)) {
let mut flips = vec![Value::Integer(0); n];
for i in 0..n {
sample!(flips[i] ~ Distribution::Bernoulli(p));
}
println!("flips: {:?}", flips);
}
let (trace, _) : (Trace, _)= simulate(&mut flip_my_biased_coin2, (5 as usize, 0.7));
println!("my flip coin 2 trace: {:?}", trace);
}
#[test]
fn test_bernoulli(){
#[r_gen]
fn my_bernoulli(p : f64) {
let mut tests = vec![Value::Real(0.0); 100];
for i in 0..100 {
sample!(tests[i] ~ Distribution::Bernoulli(p));
}
let mut tot : f64 = 0.0;
for t in tests {
match t {
Value::Boolean(true) => {
tot = tot + 1.0;
},
_ => ()
}
}
println!("P: {}\nResult of tests:{:?}", p, tot/100.0);
}
let (_, _) = simulate(&mut my_bernoulli, 0.5);
}
#[test]
fn test_binom(){
#[r_gen]
fn my_binomial((n, p): (i64, f64)) {
let mut tests = vec![Value::Real(0.0); 100];
for i in 0..100 {
sample!(tests[i] ~ Distribution::Binomial(n, p));
}
let mut tot : f64 = 0.0;
for t in tests {
match t {
Value::Integer(i) => {
tot = tot + (i as f64);
},
_ => ()
}
}
println!("N*P: {}\nResult of tests:{:?}", ((n as f64)*p), tot/100.0);
}
let (_, _) = simulate(&mut my_binomial, (100, 0.5));
}
#[test]
fn test_normal(){
#[r_gen]
fn my_normal((m, s): (f64, f64)) {
let mut tests = vec![Value::Real(0.0); 100];
for i in 0..100 {
sample!(tests[i] ~ Distribution::Normal(m, s));
}
let mut tot : f64 = 0.0;
for t in tests {
match t {
Value::Real(r) => {
tot = tot + r;
},
_ => ()
}
}
println!("Mean: {}\nResult of tests:{:?}", m, tot/100.0);
}
let (_, _) = simulate(&mut my_normal, (60.0, 10.0));
}
#[test]
fn test_importance_resampling(){
#[r_gen]
fn my_model(():()){
sample!(p ~ Distribution::Beta(1.0, 1.0));
sample!(num_heads ~ Distribution::Binomial(100, p.into()));
}
let (t, _) : (Trace, _)= simulate(&mut my_model, ());
let choices = Choicemap::from(vec![("num_heads", t.choices["num_heads"].clone())]);
let mut traces = Vec::new();
for _ in 0..1000 {
let (gt, _) : (Trace, _)= generate(&mut my_model, (), &choices);
traces.push(gt);
}
println!("Actual value for p:\t {}", t.choices["p"]);
println!("Generated value for p:\t {}", Trace::sample_weighted_traces(&traces).unwrap().choices["p"]);
}
#[test]
fn test_trace_string(){
#[r_gen]
fn my_biased_coin_model(():()){
sample!(p ~ Distribution::Beta(1.0, 1.0)); sample!(num_heads ~ Distribution::Binomial(100, p.into())); }
println!("GO");
let (trace, result) = simulate(&mut my_biased_coin_model, ());
println!("Trace String: \n{}", trace.get_trace_string());
}
}
use std::rc::Rc;
use self::{distributions::{Value, Sampleable}, trace::{Choicemap, Trace}};
pub mod distributions;
pub mod trace;
pub fn simulate<F, A, R, S : Sampleable>(generative_function : &mut F, arguments : A) -> (Trace, R)
where
F : FnMut(Rc<dyn FnMut(&String, S, &mut Trace) -> Value>, &mut Trace, A) -> R,
{
let sample = |name : &String, dist : S, trace : &mut Trace| {
let value = dist.sample(); let prob = dist.liklihood(&value).unwrap(); trace.update_logscore(prob); trace.choices.add_choice(&name, value.clone()); value
};
let mut trace = Trace::new();
let return_value = generative_function(Rc::new(sample), &mut trace, arguments);
(trace, return_value)
}
pub fn generate<F, A, R, S: Sampleable>(generative_function : &mut F, arguments : A, conditions : &Choicemap) -> (Trace, R)
where
F : FnMut(Rc<dyn FnMut(&String, S, &mut Trace) -> Value>, &mut Trace, A) -> R,
{
let sample = |name : &String, dist : S, trace : &mut Trace| {
let mut _value = Value::Real(0.0);
_value = if trace.choices.contains_key(name) {
trace.choices[name.as_str()].clone()
} else {
dist.sample()
};
let prob = dist.liklihood(&_value).unwrap(); trace.update_logscore(prob); trace.choices.add_choice(name.as_str(), _value.clone()); _value
};
let mut trace = Trace::new();
for (k, v) in conditions.get_choices() {
trace.choices.add_choice(k, v);
}
let return_value = generative_function(Rc::new(sample), &mut trace, arguments);
(trace, return_value)
}