<commit_before>// Copyright 2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::f64;
use std::iter;
use std::slice;

use num::traits::{cast, NumCast};
use itertools::Itertools;

use bio::stats::logprobs::{self, LogProb};

/// Implementation of a cumulative distribution function.
#[derive(Debug, Clone)]
pub struct CDF<T: PartialOrd> {
    inner: Vec<(T, LogProb)>
}

impl<T: PartialOrd> CDF<T> {
    /// Create CDF from given probability mass function (PMF). The PMF may contain duplicate values
    /// the probabilities of which are summed during generation of the CDF.
    pub fn from_pmf(mut entries: Vec<(T, LogProb)>) -> Self {
        entries.sort_by(|&(ref a, _), &(ref b, _)| a.partial_cmp(b).unwrap());
        let mut inner: Vec<(T, LogProb)> = Vec::new();
        for mut e in entries.into_iter() {
            let p = logprobs::add(inner.last().map_or(f64::NEG_INFINITY, |e| e.1), e.1);
            if !inner.is_empty() && inner.last().unwrap().0 == e.0 {
                inner.last_mut().unwrap().1 = p;
            }
            else {
                e.1 = p;
                inner.push(e);
            }
        }
        let mut cdf = CDF {
            inner: inner
        };

        if relative_eq!(cdf.total_prob(), 0.0) && cdf.total_prob() > 0.0 {
            cdf.inner.last_mut().unwrap().1 = 0.0;
        }

        cdf
    }

    /// Create CDF from iterator. This can be used to replace the values of a CDF.
    pub fn from_cdf<I: Iterator<Item = (T, LogProb)>>(entries: I) -> Self {
        CDF { inner: entries.collect_vec() }
    }

    pub fn reduce(self) -> Self {
        let mut inner = Vec::new();
        let mut last = f64::NEG_INFINITY;
        for e in self.inner.into_iter() {
            if last != e.1 {
                last = e.1;
                inner.push(e);
            }
        }
        CDF { inner: inner }
    }

    pub fn sample(mut self, n: usize) -> Self {
        if self.inner.len() <= n {
            self
        }
        else {
            let s = self.inner.len() / (n - 1);
            let last = self.inner.pop().unwrap();
            let mut inner = self.inner.into_iter().step(s).collect_vec();
            inner.push(last);
            CDF {
                inner: inner
            }
        }
    }

    pub fn iter(&self) -> slice::Iter<(T, f64)>{
        self.inner.iter()
    }

    pub fn iter_pmf<'a>(&'a self) -> CDFPMFIter<'a, T> {
        fn cdf_to_pmf<'a, G>(last_prob: &mut LogProb, e: &'a (G, LogProb)) -> Option<(&'a G, LogProb)> {
            let &(ref value, cdf_prob) = e;
            let prob = logprobs::sub(cdf_prob, *last_prob);
            *last_prob = cdf_prob;
            Some((value, prob))
        }
        self.inner.iter().scan(f64::NEG_INFINITY, cdf_to_pmf)
    }

    /// Get cumulative probability for a given value. If the value is not present,
    /// return the probability of the previous value.
    pub fn get(&self, value: &T) -> Option<LogProb> {
        if self.inner.is_empty() {
            None
        }
        else {
            Some(match self.inner.binary_search_by(|e| e.0.partial_cmp(value).unwrap()) {
                Ok(i) => self.inner[i].1,
                Err(i) => if i > 0 { self.inner[i - 1].1 } else { f64::NEG_INFINITY }
            })
        }
    }

    pub fn get_pmf(&self, value: &T) -> Option<LogProb> {
        if self.inner.is_empty() {
            None
        }
        else {
            Some(match self.inner.binary_search_by(|e| e.0.partial_cmp(value).unwrap()) {
                Ok(i) => if i > 0 { logprobs::sub(self.inner[i].1, self.inner[i - 1].1) } else { self.inner[0].1 },
                Err(i) => if i > 0 { self.inner[i - 1].1 } else { f64::NEG_INFINITY }
            })
        }
    }

    pub fn total_prob(&self) -> LogProb {
        let &(_, prob) = self.inner.last().unwrap();
        prob
    }

    /// Return maximum a posteriori probability estimate (MAP).
    pub fn map(&self) -> &T {
        let mut max = self.iter_pmf().next().unwrap();
        for e in self.iter_pmf() {
            if e.1 >= max.1 {
                max = e;
            }
        }
        &max.0
    }

    /// Return the 95% credible interval.
    pub fn credible_interval(&self) -> (&T, &T) {
        let lower = self.inner.binary_search_by(|&(_, p)| p.partial_cmp(&0.025f64.ln()).unwrap()).unwrap_or_else(|i| if i > 0 { i - 1 } else { 0 });
        let lower_p = self.inner[lower].1;
        let upper = self.inner.binary_search_by(|&(_, p)| logprobs::sub(p, lower_p).partial_cmp(&0.95f64.ln()).unwrap()).unwrap_or_else(|i| i);

        (&self.inner[lower].0, &self.inner[upper].0)
    }

    pub fn len(&self) -> usize {
        self.inner.len()
    }
}

impl<T: NumCast + Clone + PartialOrd> CDF<T> {
    pub fn expected_value(&self) -> f64 {
        self.iter_pmf().map(|(value, prob)| {
            cast::<T, f64>(value.clone()).unwrap() * prob.exp()
        }).fold(0.0f64, |s, e| s + e)
    }

    pub fn variance(&self) -> f64 {
        let ev = self.expected_value();
        self.iter_pmf().map(|(value, prob)| {
                (cast::<T, f64>(value.clone()).unwrap() - ev).powi(2) * prob.exp()
        }).fold(0.0, |s, e| s + e)
    }

    pub fn standard_deviation(&self) -> f64 {
        self.variance().sqrt()
    }
}

pub type CDFPMFIter<'a, T> = iter::Scan<slice::Iter<'a, (T, LogProb)>, LogProb, fn(&mut LogProb, &'a (T, LogProb)) -> Option<(&'a T, LogProb)>>;

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_cdf() {
        let mut pmf = vec![(0.0, 0.1f64.ln())];
        for i in 0..9 {
            pmf.push((i as f64, 0.1f64.ln()));
        }
        println!("{:?}", pmf);

        let cdf = CDF::from_pmf(pmf.clone());
        println!("{:?}", cdf);
        for &(value, prob) in pmf.iter().skip(2) {
            assert_ulps_eq!(prob, cdf.get_pmf(&value).unwrap(), epsilon = 0.0000000000001);
        }
        assert_relative_eq!(cdf.total_prob(), 1.0f64.ln());
        assert_relative_eq!(cdf.get(&1.0).unwrap(), 0.3f64.ln(), epsilon = 0.00000001);
    }
}
<commit_msg>Fix upper.<commit_after>// Copyright 2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::f64;
use std::iter;
use std::slice;

use num::traits::{cast, NumCast};
use itertools::Itertools;

use bio::stats::logprobs::{self, LogProb};

/// Implementation of a cumulative distribution function.
#[derive(Debug, Clone)]
pub struct CDF<T: PartialOrd> {
    inner: Vec<(T, LogProb)>
}

impl<T: PartialOrd> CDF<T> {
    /// Create CDF from given probability mass function (PMF). The PMF may contain duplicate values
    /// the probabilities of which are summed during generation of the CDF.
    pub fn from_pmf(mut entries: Vec<(T, LogProb)>) -> Self {
        entries.sort_by(|&(ref a, _), &(ref b, _)| a.partial_cmp(b).unwrap());
        let mut inner: Vec<(T, LogProb)> = Vec::new();
        for mut e in entries.into_iter() {
            let p = logprobs::add(inner.last().map_or(f64::NEG_INFINITY, |e| e.1), e.1);
            if !inner.is_empty() && inner.last().unwrap().0 == e.0 {
                inner.last_mut().unwrap().1 = p;
            }
            else {
                e.1 = p;
                inner.push(e);
            }
        }
        let mut cdf = CDF {
            inner: inner
        };

        if relative_eq!(cdf.total_prob(), 0.0) && cdf.total_prob() > 0.0 {
            cdf.inner.last_mut().unwrap().1 = 0.0;
        }

        cdf
    }

    /// Create CDF from iterator. This can be used to replace the values of a CDF.
    pub fn from_cdf<I: Iterator<Item = (T, LogProb)>>(entries: I) -> Self {
        CDF { inner: entries.collect_vec() }
    }

    pub fn reduce(self) -> Self {
        let mut inner = Vec::new();
        let mut last = f64::NEG_INFINITY;
        for e in self.inner.into_iter() {
            if last != e.1 {
                last = e.1;
                inner.push(e);
            }
        }
        CDF { inner: inner }
    }

    pub fn sample(mut self, n: usize) -> Self {
        if self.inner.len() <= n {
            self
        }
        else {
            let s = self.inner.len() / (n - 1);
            let last = self.inner.pop().unwrap();
            let mut inner = self.inner.into_iter().step(s).collect_vec();
            inner.push(last);
            CDF {
                inner: inner
            }
        }
    }

    pub fn iter(&self) -> slice::Iter<(T, f64)>{
        self.inner.iter()
    }

    pub fn iter_pmf<'a>(&'a self) -> CDFPMFIter<'a, T> {
        fn cdf_to_pmf<'a, G>(last_prob: &mut LogProb, e: &'a (G, LogProb)) -> Option<(&'a G, LogProb)> {
            let &(ref value, cdf_prob) = e;
            let prob = logprobs::sub(cdf_prob, *last_prob);
            *last_prob = cdf_prob;
            Some((value, prob))
        }
        self.inner.iter().scan(f64::NEG_INFINITY, cdf_to_pmf)
    }

    /// Get cumulative probability for a given value. If the value is not present,
    /// return the probability of the previous value.
    pub fn get(&self, value: &T) -> Option<LogProb> {
        if self.inner.is_empty() {
            None
        }
        else {
            Some(match self.inner.binary_search_by(|e| e.0.partial_cmp(value).unwrap()) {
                Ok(i) => self.inner[i].1,
                Err(i) => if i > 0 { self.inner[i - 1].1 } else { f64::NEG_INFINITY }
            })
        }
    }

    pub fn get_pmf(&self, value: &T) -> Option<LogProb> {
        if self.inner.is_empty() {
            None
        }
        else {
            Some(match self.inner.binary_search_by(|e| e.0.partial_cmp(value).unwrap()) {
                Ok(i) => if i > 0 { logprobs::sub(self.inner[i].1, self.inner[i - 1].1) } else { self.inner[0].1 },
                Err(i) => if i > 0 { self.inner[i - 1].1 } else { f64::NEG_INFINITY }
            })
        }
    }

    pub fn total_prob(&self) -> LogProb {
        let &(_, prob) = self.inner.last().unwrap();
        prob
    }

    /// Return maximum a posteriori probability estimate (MAP).
    pub fn map(&self) -> &T {
        let mut max = self.iter_pmf().next().unwrap();
        for e in self.iter_pmf() {
            if e.1 >= max.1 {
                max = e;
            }
        }
        &max.0
    }

    /// Return the 95% credible interval.
    pub fn credible_interval(&self) -> (&T, &T) {
        let lower = self.inner.binary_search_by(|&(_, p)| p.partial_cmp(&0.025f64.ln()).unwrap()).unwrap_or_else(|i| if i > 0 { i - 1 } else { 0 });
        let lower_p = self.inner[lower].1;
        let mut upper = self.inner.binary_search_by(|&(_, p)| logprobs::sub(p, lower_p).partial_cmp(&0.95f64.ln()).unwrap()).unwrap_or_else(|i| i);
        if upper == self.inner.len() {
            upper -= 1;
        }

        (&self.inner[lower].0, &self.inner[upper].0)
    }

    pub fn len(&self) -> usize {
        self.inner.len()
    }
}

impl<T: NumCast + Clone + PartialOrd> CDF<T> {
    pub fn expected_value(&self) -> f64 {
        self.iter_pmf().map(|(value, prob)| {
            cast::<T, f64>(value.clone()).unwrap() * prob.exp()
        }).fold(0.0f64, |s, e| s + e)
    }

    pub fn variance(&self) -> f64 {
        let ev = self.expected_value();
        self.iter_pmf().map(|(value, prob)| {
                (cast::<T, f64>(value.clone()).unwrap() - ev).powi(2) * prob.exp()
        }).fold(0.0, |s, e| s + e)
    }

    pub fn standard_deviation(&self) -> f64 {
        self.variance().sqrt()
    }
}

pub type CDFPMFIter<'a, T> = iter::Scan<slice::Iter<'a, (T, LogProb)>, LogProb, fn(&mut LogProb, &'a (T, LogProb)) -> Option<(&'a T, LogProb)>>;

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_cdf() {
        let mut pmf = vec![(0.0, 0.1f64.ln())];
        for i in 0..9 {
            pmf.push((i as f64, 0.1f64.ln()));
        }
        println!("{:?}", pmf);

        let cdf = CDF::from_pmf(pmf.clone());
        println!("{:?}", cdf);
        for &(value, prob) in pmf.iter().skip(2) {
            assert_ulps_eq!(prob, cdf.get_pmf(&value).unwrap(), epsilon = 0.0000000000001);
        }
        assert_relative_eq!(cdf.total_prob(), 1.0f64.ln());
        assert_relative_eq!(cdf.get(&1.0).unwrap(), 0.3f64.ln(), epsilon = 0.00000001);
    }
}
<|endoftext|>


<commit_before>use libc::{uint32_t, c_void};
use std::mem;
use sys::timer as ll;

pub fn get_ticks() -> u32 {
    unsafe { ll::SDL_GetTicks() }
}

pub fn get_performance_counter() -> u64 {
    unsafe { ll::SDL_GetPerformanceCounter() }
}

pub fn get_performance_frequency() -> u64 {
    unsafe { ll::SDL_GetPerformanceFrequency() }
}

pub fn delay(ms: u32) {
    unsafe { ll::SDL_Delay(ms) }
}

pub type TimerCallback<'a> = Box<FnMut() -> u32+'a+Sync>;

#[unstable = "Unstable because of move to unboxed closures and `box` syntax"]
pub struct Timer<'a> {
    callback: Option<Box<TimerCallback<'a>>>,
    _delay: u32,
    raw: ll::SDL_TimerID,
}

impl<'a> Timer<'a> {
    /// Constructs a new timer using the boxed closure `callback`.
    /// The timer is started immediately, it will be cancelled either:
    ///   * when the timer is dropped
    ///   * or when the callback returns a non-positive continuation interval
    pub fn new(delay: u32, callback: TimerCallback<'a>) -> Timer<'a> {
        unsafe {
			let callback = Box::new(callback);
            let timer_id = ll::SDL_AddTimer(delay,
                                            Some(c_timer_callback),
                                            mem::transmute_copy(&callback));

            Timer {
                callback: Some(callback),
                _delay: delay,
                raw: timer_id,
            }
        }
    }

	/// Returns the closure as a trait-object and cancels the timer
	/// by consuming it...
	pub fn into_inner(mut self) -> TimerCallback<'a> {
		*self.callback.take().unwrap()
	}
}

#[unsafe_destructor]
impl<'a> Drop for Timer<'a> {
    fn drop(&mut self) {
        let ret = unsafe { ll::SDL_RemoveTimer(self.raw) };
        if ret != 1 {
            println!("error dropping timer {}, maybe already removed.", self.raw);
        }
    }
}

extern "C" fn c_timer_callback(_interval: u32, param: *const c_void) -> uint32_t {
    unsafe {
        let f: *const  Box<Fn() -> u32> = mem::transmute(param);
        (*f)() as uint32_t
    }
}

#[cfg(test)] use std::sync::{StaticMutex, MUTEX_INIT};
#[cfg(test)] static TIMER_INIT_LOCK: StaticMutex = MUTEX_INIT;

#[test]
fn test_timer_runs_multiple_times() {
    use std::sync::{Arc, Mutex};
    let running = TIMER_INIT_LOCK.lock().unwrap();
    ::sdl::init(::sdl::INIT_TIMER);

    let local_num = Arc::new(Mutex::new(0));
    let timer_num = local_num.clone();

    let timer = Timer::new(20, Box::new(|| {
        // increment up to 10 times (0 -> 9)
        // tick again in 100ms after each increment
        //
        let mut num = timer_num.lock().unwrap();
        if *num < 9 {
            *num += 1;
            20
        } else { 0 }
    }));

    delay(250);                         // tick the timer at least 10 times w/ 200ms of "buffer"
    let num = local_num.lock().unwrap(); // read the number back
    assert_eq!(*num, 9);                 // it should have incremented at least 10 times...
}

#[test]
fn test_timer_runs_at_least_once() {
    use std::sync::{Arc, Mutex};
    let running = TIMER_INIT_LOCK.lock().unwrap();
    ::sdl::init(::sdl::INIT_TIMER);

    let local_flag = Arc::new(Mutex::new(false));
    let timer_flag = local_flag.clone();

    let timer = Timer::new(20, Box::new(|| {
        let mut flag = timer_flag.lock().unwrap();
        *flag = true; 0
    }));

    delay(50);
    let flag = local_flag.lock().unwrap();
    assert_eq!(*flag, true);
}

#[test]
fn test_timer_can_be_recreated() {
    use std::sync::{Arc, Mutex};
    let running = TIMER_INIT_LOCK.lock().unwrap();
    ::sdl::init(::sdl::INIT_TIMER);

    let local_num = Arc::new(Mutex::new(0));
    let timer_num = local_num.clone();

    // run the timer once and reclaim its closure
    let mut timer_1 = Timer::new(20, Box::new(move|| {
        let mut num = timer_num.lock().unwrap();
        *num += 1; // increment the number
        0          // do not run timer again
    }));

    // reclaim closure after timer runs
    delay(50);
    let closure = timer_1.into_inner();

    // create a second timer and increment again
    let timer_2 = Timer::new(20, closure);
    delay(50);

    // check that timer was incremented twice
    let num = local_num.lock().unwrap();
    assert_eq!(*num, 2);
}
<commit_msg>(fix whitespace in timer.rs)<commit_after>use libc::{uint32_t, c_void};
use std::mem;
use sys::timer as ll;

pub fn get_ticks() -> u32 {
    unsafe { ll::SDL_GetTicks() }
}

pub fn get_performance_counter() -> u64 {
    unsafe { ll::SDL_GetPerformanceCounter() }
}

pub fn get_performance_frequency() -> u64 {
    unsafe { ll::SDL_GetPerformanceFrequency() }
}

pub fn delay(ms: u32) {
    unsafe { ll::SDL_Delay(ms) }
}

pub type TimerCallback<'a> = Box<FnMut() -> u32+'a+Sync>;

#[unstable = "Unstable because of move to unboxed closures and `box` syntax"]
pub struct Timer<'a> {
    callback: Option<Box<TimerCallback<'a>>>,
    _delay: u32,
    raw: ll::SDL_TimerID,
}

impl<'a> Timer<'a> {
    /// Constructs a new timer using the boxed closure `callback`.
    /// The timer is started immediately, it will be cancelled either:
    ///   * when the timer is dropped
    ///   * or when the callback returns a non-positive continuation interval
    pub fn new(delay: u32, callback: TimerCallback<'a>) -> Timer<'a> {
        unsafe {
            let callback = Box::new(callback);
            let timer_id = ll::SDL_AddTimer(delay,
                                            Some(c_timer_callback),
                                            mem::transmute_copy(&callback));

            Timer {
                callback: Some(callback),
                _delay: delay,
                raw: timer_id,
            }
        }
    }

    /// Returns the closure as a trait-object and cancels the timer
    /// by consuming it...
    pub fn into_inner(mut self) -> TimerCallback<'a> {
        *self.callback.take().unwrap()
    }
}

#[unsafe_destructor]
impl<'a> Drop for Timer<'a> {
    fn drop(&mut self) {
        let ret = unsafe { ll::SDL_RemoveTimer(self.raw) };
        if ret != 1 {
            println!("error dropping timer {}, maybe already removed.", self.raw);
        }
    }
}

extern "C" fn c_timer_callback(_interval: u32, param: *const c_void) -> uint32_t {
    unsafe {
        let f: *const  Box<Fn() -> u32> = mem::transmute(param);
        (*f)() as uint32_t
    }
}

#[cfg(test)] use std::sync::{StaticMutex, MUTEX_INIT};
#[cfg(test)] static TIMER_INIT_LOCK: StaticMutex = MUTEX_INIT;

#[test]
fn test_timer_runs_multiple_times() {
    use std::sync::{Arc, Mutex};
    let running = TIMER_INIT_LOCK.lock().unwrap();
    ::sdl::init(::sdl::INIT_TIMER);

    let local_num = Arc::new(Mutex::new(0));
    let timer_num = local_num.clone();

    let timer = Timer::new(20, Box::new(|| {
        // increment up to 10 times (0 -> 9)
        // tick again in 100ms after each increment
        //
        let mut num = timer_num.lock().unwrap();
        if *num < 9 {
            *num += 1;
            20
        } else { 0 }
    }));

    delay(250);                         // tick the timer at least 10 times w/ 200ms of "buffer"
    let num = local_num.lock().unwrap(); // read the number back
    assert_eq!(*num, 9);                 // it should have incremented at least 10 times...
}

#[test]
fn test_timer_runs_at_least_once() {
    use std::sync::{Arc, Mutex};
    let running = TIMER_INIT_LOCK.lock().unwrap();
    ::sdl::init(::sdl::INIT_TIMER);

    let local_flag = Arc::new(Mutex::new(false));
    let timer_flag = local_flag.clone();

    let timer = Timer::new(20, Box::new(|| {
        let mut flag = timer_flag.lock().unwrap();
        *flag = true; 0
    }));

    delay(50);
    let flag = local_flag.lock().unwrap();
    assert_eq!(*flag, true);
}

#[test]
fn test_timer_can_be_recreated() {
    use std::sync::{Arc, Mutex};
    let running = TIMER_INIT_LOCK.lock().unwrap();
    ::sdl::init(::sdl::INIT_TIMER);

    let local_num = Arc::new(Mutex::new(0));
    let timer_num = local_num.clone();

    // run the timer once and reclaim its closure
    let mut timer_1 = Timer::new(20, Box::new(move|| {
        let mut num = timer_num.lock().unwrap();
        *num += 1; // increment the number
        0          // do not run timer again
    }));

    // reclaim closure after timer runs
    delay(50);
    let closure = timer_1.into_inner();

    // create a second timer and increment again
    let timer_2 = Timer::new(20, closure);
    delay(50);

    // check that timer was incremented twice
    let num = local_num.lock().unwrap();
    assert_eq!(*num, 2);
}
<|endoftext|>


<commit_before>use super::{ActionEdge, ActionNode, CCFGEdge, CCFGNode, CCFGRef, ValueEdge, CCFG};
use backend::ctrl_flow_struct as flstr;
use backend::ctrl_flow_struct::ast_context::{AstContext, AstContextMut};
use backend::lang_c::c_ast::{self, CAST};

use petgraph::stable_graph::StableDiGraph;
use petgraph::visit::EdgeRef;

use std::collections::hash_map::Entry;
use std::collections::HashMap;

pub fn structure_and_convert(ccfg: CCFG) -> Result<CAST, &'static str> {
    let cstore = flstr::condition::Storage::new();
    let flstr_cfg = Importer::new(cstore.cctx(), ccfg).run()?;
    let (flstr_ast, ccfg) = flstr_cfg.structure_whole();
    flstr::export::to_c_ast(&ccfg, flstr_ast)
}

struct Importer<'cd> {
    cctx: flstr::condition::Context<'cd, CCFGRef>,
    ccfg: CCFG,
    new_graph: StableDiGraph<flstr::CfgNode<'cd, CCFG>, flstr::CfgEdge>,
}

enum SuccInfo {
    Single(CCFGRef),
    Branch(CCFGRef, CCFGRef, CCFGRef),
}

impl<'cd> Importer<'cd> {
    fn new(cctx: flstr::condition::Context<'cd, CCFGRef>, ccfg: CCFG) -> Self {
        Self {
            cctx,
            ccfg,
            new_graph: StableDiGraph::new(),
        }
    }

    fn run(mut self) -> Result<flstr::ControlFlowGraph<'cd, CCFG>, &'static str> {
        let new_entry = self.new_graph.add_node(flstr::empty_node());
        let mut converted = HashMap::new();

        if let Some(first) = self.ccfg.next_action(self.ccfg.entry) {
            let mut worklist = Vec::new();
            worklist.push((new_entry, flstr::CfgEdge::True, first));

            while let Some((f_pred_block, pred_edge_ty, cur_block)) = worklist.pop() {
                let f_cur_block = match converted.entry(cur_block) {
                    Entry::Occupied(oe) => *oe.into_mut(),
                    Entry::Vacant(ve) => {
                        let (block, opt_succs) = self.find_block(cur_block)?;

                        let f_cur_block = self.new_graph.add_node(flstr::mk_code_node(block));
                        ve.insert(f_cur_block);

                        match opt_succs {
                            None => (),
                            Some(SuccInfo::Single(next_block)) => {
                                worklist.push((f_cur_block, flstr::CfgEdge::True, next_block));
                            }
                            Some(SuccInfo::Branch(cond, then_block, else_block)) => {
                                let f_cond_node = self
                                    .new_graph
                                    .add_node(flstr::mk_cond_node(self.cctx, cond));
                                self.new_graph.add_edge(
                                    f_cur_block,
                                    f_cond_node,
                                    flstr::CfgEdge::True,
                                );
                                worklist.push((f_cond_node, flstr::CfgEdge::True, then_block));
                                worklist.push((f_cond_node, flstr::CfgEdge::False, else_block));
                            }
                        }

                        f_cur_block
                    }
                };

                self.new_graph
                    .add_edge(f_pred_block, f_cur_block, pred_edge_ty);
            }
        }

        Ok(flstr::ControlFlowGraph::new(
            self.new_graph,
            new_entry,
            self.cctx,
            self.ccfg,
        ))
    }

    fn find_block(&self, block: CCFGRef) -> Result<(Vec<CCFGRef>, Option<SuccInfo>), &'static str> {
        if self.ccfg.g[block] != CCFGNode::Action(ActionNode::BasicBlock) {
            return Err("import: basic block doesn't begin with BasicBlock");
        }

        let mut ret = Vec::new();
        let mut cur_node = if let Some(start) = self.ccfg.next_action(block) {
            start
        } else {
            return Ok((Vec::new(), None));
        };

        loop {
            match self.ccfg.g[cur_node] {
                CCFGNode::Action(ActionNode::BasicBlock) => {
                    return Ok((ret, Some(SuccInfo::Single(cur_node))));
                }
                CCFGNode::Action(ActionNode::If) => {
                    let (condition, then_goto, else_goto) = if_info(&self.ccfg, cur_node)?;
                    let then_block = goto_next(&self.ccfg, then_goto)?;
                    let else_block = goto_next(&self.ccfg, else_goto)?;
                    return Ok((
                        ret,
                        Some(SuccInfo::Branch(condition, then_block, else_block)),
                    ));
                }
                CCFGNode::Action(ActionNode::Goto) => {
                    let next_block = goto_next(&self.ccfg, cur_node)?;
                    return Ok((ret, Some(SuccInfo::Single(next_block))));
                }
                CCFGNode::Action(_) => {
                    ret.push(cur_node);
                    if let Some(next) = self.ccfg.next_action(cur_node) {
                        cur_node = next;
                    } else {
                        return Ok((ret, None));
                    }
                }
                CCFGNode::Value(_) => return Err("import: found Value node"),
                _ => return Err("import: unknown node type"),
            }
        }
    }
}

fn goto_next(ccfg: &CCFG, goto_node: CCFGRef) -> Result<CCFGRef, &'static str> {
    ccfg.goto(goto_node)
        .ok_or("import: Goto node has no destination")
}

fn if_info(ccfg: &CCFG, if_node: CCFGRef) -> Result<(CCFGRef, CCFGRef, CCFGRef), &'static str> {
    let mut condition = None;
    let mut then_dst = None;
    let mut else_dst = None;
    for e in ccfg.g.edges(if_node) {
        match e.weight() {
            CCFGEdge::Value(ValueEdge::Conditional) => condition = Some(e.target()),
            CCFGEdge::Action(ActionEdge::IfThen) => then_dst = Some(e.target()),
            CCFGEdge::Action(ActionEdge::IfElse) => else_dst = Some(e.target()),
            _ => (),
        }
    }
    match (condition, then_dst, else_dst) {
        (Some(c), Some(t), Some(e)) => Ok((c, t, e)),
        _ => Err("import: If node has no condition, then node, and/or else node"),
    }
}

impl AstContext for CCFG {
    type Block = Vec<CCFGRef>;
    type Variable = CCFGRef;
    type BoolVariable = CCFGRef;
    type Condition = CCFGRef;
}

fn var_ty() -> c_ast::Ty {
    c_ast::Ty::new(c_ast::BTy::Int, false, 0)
}

impl AstContextMut for CCFG {
    fn mk_fresh_var(&mut self) -> Self::Variable {
        // XXX: initialized to something
        let var = format!("i_{}", self.vars.len());
        self.var(&var, Some(var_ty()))
    }

    fn mk_fresh_var_zeroed(&mut self) -> Self::Variable {
        // XXX: initialized to zero
        let var = format!("i_{}", self.vars.len());
        self.var(&var, Some(var_ty()))
    }

    fn mk_fresh_bool_var(&mut self) -> Self::BoolVariable {
        // XXX: initialized to something
        let var = format!("c_{}", self.vars.len());
        self.var(&var, Some(var_ty()))
    }

    fn mk_cond_equals(&mut self, &var: &Self::Variable, val: u64) -> Self::Condition {
        let val = self.constant(&format!("{}", val), Some(var_ty()));
        self.expr(&[var, val], c_ast::Expr::Eq)
    }

    fn mk_cond_from_bool_var(&mut self, &var: &Self::BoolVariable) -> Self::Condition {
        var
    }

    fn mk_var_assign(&mut self, &var: &Self::Variable, val: u64) -> Self::Block {
        let val = self.constant(&format!("{}", val), Some(var_ty()));
        let unk = self.unknown;
        vec![self.assign(var, val, unk)]
    }

    fn mk_bool_var_assign(
        &mut self,
        &var: &Self::BoolVariable,
        &cond: &Self::Condition,
    ) -> Self::Block {
        let unk = self.unknown;
        vec![self.assign(var, cond, unk)]
    }
}
<commit_msg>[c_cfg] Don't create empty code nodes before condition nodes<commit_after>use super::{ActionEdge, ActionNode, CCFGEdge, CCFGNode, CCFGRef, ValueEdge, CCFG};
use backend::ctrl_flow_struct as flstr;
use backend::ctrl_flow_struct::ast_context::{AstContext, AstContextMut};
use backend::lang_c::c_ast::{self, CAST};

use petgraph::stable_graph::StableDiGraph;
use petgraph::visit::EdgeRef;

use std::collections::hash_map::Entry;
use std::collections::HashMap;

pub fn structure_and_convert(ccfg: CCFG) -> Result<CAST, &'static str> {
    let cstore = flstr::condition::Storage::new();
    let flstr_cfg = Importer::new(cstore.cctx(), ccfg).run()?;
    let (flstr_ast, ccfg) = flstr_cfg.structure_whole();
    flstr::export::to_c_ast(&ccfg, flstr_ast)
}

struct Importer<'cd> {
    cctx: flstr::condition::Context<'cd, CCFGRef>,
    ccfg: CCFG,
    new_graph: StableDiGraph<flstr::CfgNode<'cd, CCFG>, flstr::CfgEdge>,
}

enum SuccInfo {
    Single(CCFGRef),
    Branch(CCFGRef, CCFGRef, CCFGRef),
}

impl<'cd> Importer<'cd> {
    fn new(cctx: flstr::condition::Context<'cd, CCFGRef>, ccfg: CCFG) -> Self {
        Self {
            cctx,
            ccfg,
            new_graph: StableDiGraph::new(),
        }
    }

    fn run(mut self) -> Result<flstr::ControlFlowGraph<'cd, CCFG>, &'static str> {
        let new_entry = self.new_graph.add_node(flstr::empty_node());
        let mut converted = HashMap::new();

        // do a DFS over CCFG, inserting nodes and edges into `new_graph` as we
        // discover them
        if let Some(first) = self.ccfg.next_action(self.ccfg.entry) {
            // list of edges to process
            let mut worklist = Vec::new();
            worklist.push((new_entry, flstr::CfgEdge::True, first));

            while let Some((f_pred_block, pred_edge_ty, cur_block)) = worklist.pop() {
                // find the node in `new_graph` corresponding to `cur_block` in
                // CCFG, adding a new node if necessary
                let f_cur_block = match converted.entry(cur_block) {
                    Entry::Occupied(oe) => *oe.into_mut(),
                    Entry::Vacant(ve) => {
                        let (block, opt_succs) = self.find_block(cur_block)?;

                        let f_cur_block = match opt_succs {
                            None => {
                                self.new_graph.add_node(flstr::mk_code_node(block))
                            }
                            Some(SuccInfo::Single(next_block)) => {
                                let f_cur_block =
                                    self.new_graph.add_node(flstr::mk_code_node(block));
                                worklist.push((f_cur_block, flstr::CfgEdge::True, next_block));
                                f_cur_block
                            }
                            Some(SuccInfo::Branch(cond, then_block, else_block)) => {
                                // make the cond node
                                let f_cond_node = self
                                    .new_graph
                                    .add_node(flstr::mk_cond_node(self.cctx, cond));
                                worklist.push((f_cond_node, flstr::CfgEdge::True, then_block));
                                worklist.push((f_cond_node, flstr::CfgEdge::False, else_block));

                                // only insert a preceding code node if needed
                                if block.is_empty() {
                                    f_cond_node
                                } else {
                                    let f_cur_block =
                                        self.new_graph.add_node(flstr::mk_code_node(block));
                                    self.new_graph.add_edge(
                                        f_cur_block,
                                        f_cond_node,
                                        flstr::CfgEdge::True,
                                    );
                                    f_cur_block
                                }
                            }
                        };

                        *ve.insert(f_cur_block)
                    }
                };

                self.new_graph
                    .add_edge(f_pred_block, f_cur_block, pred_edge_ty);
            }
        }

        Ok(flstr::ControlFlowGraph::new(
            self.new_graph,
            new_entry,
            self.cctx,
            self.ccfg,
        ))
    }

    fn find_block(&self, block: CCFGRef) -> Result<(Vec<CCFGRef>, Option<SuccInfo>), &'static str> {
        if self.ccfg.g[block] != CCFGNode::Action(ActionNode::BasicBlock) {
            return Err("import: basic block doesn't begin with BasicBlock");
        }

        let mut ret = Vec::new();
        let mut cur_node = if let Some(start) = self.ccfg.next_action(block) {
            start
        } else {
            return Ok((Vec::new(), None));
        };

        loop {
            match self.ccfg.g[cur_node] {
                CCFGNode::Action(ActionNode::BasicBlock) => {
                    return Ok((ret, Some(SuccInfo::Single(cur_node))));
                }
                CCFGNode::Action(ActionNode::If) => {
                    let (condition, then_goto, else_goto) = if_info(&self.ccfg, cur_node)?;
                    let then_block = goto_next(&self.ccfg, then_goto)?;
                    let else_block = goto_next(&self.ccfg, else_goto)?;
                    return Ok((
                        ret,
                        Some(SuccInfo::Branch(condition, then_block, else_block)),
                    ));
                }
                CCFGNode::Action(ActionNode::Goto) => {
                    let next_block = goto_next(&self.ccfg, cur_node)?;
                    return Ok((ret, Some(SuccInfo::Single(next_block))));
                }
                CCFGNode::Action(_) => {
                    ret.push(cur_node);
                    if let Some(next) = self.ccfg.next_action(cur_node) {
                        cur_node = next;
                    } else {
                        return Ok((ret, None));
                    }
                }
                CCFGNode::Value(_) => return Err("import: found Value node"),
                _ => return Err("import: unknown node type"),
            }
        }
    }
}

fn goto_next(ccfg: &CCFG, goto_node: CCFGRef) -> Result<CCFGRef, &'static str> {
    ccfg.goto(goto_node)
        .ok_or("import: Goto node has no destination")
}

fn if_info(ccfg: &CCFG, if_node: CCFGRef) -> Result<(CCFGRef, CCFGRef, CCFGRef), &'static str> {
    let mut condition = None;
    let mut then_dst = None;
    let mut else_dst = None;
    for e in ccfg.g.edges(if_node) {
        match e.weight() {
            CCFGEdge::Value(ValueEdge::Conditional) => condition = Some(e.target()),
            CCFGEdge::Action(ActionEdge::IfThen) => then_dst = Some(e.target()),
            CCFGEdge::Action(ActionEdge::IfElse) => else_dst = Some(e.target()),
            _ => (),
        }
    }
    match (condition, then_dst, else_dst) {
        (Some(c), Some(t), Some(e)) => Ok((c, t, e)),
        _ => Err("import: If node has no condition, then node, and/or else node"),
    }
}

impl AstContext for CCFG {
    type Block = Vec<CCFGRef>;
    type Variable = CCFGRef;
    type BoolVariable = CCFGRef;
    type Condition = CCFGRef;
}

fn var_ty() -> c_ast::Ty {
    c_ast::Ty::new(c_ast::BTy::Int, false, 0)
}

impl AstContextMut for CCFG {
    fn mk_fresh_var(&mut self) -> Self::Variable {
        // XXX: initialized to something
        let var = format!("i_{}", self.vars.len());
        self.var(&var, Some(var_ty()))
    }

    fn mk_fresh_var_zeroed(&mut self) -> Self::Variable {
        // XXX: initialized to zero
        let var = format!("i_{}", self.vars.len());
        self.var(&var, Some(var_ty()))
    }

    fn mk_fresh_bool_var(&mut self) -> Self::BoolVariable {
        // XXX: initialized to something
        let var = format!("c_{}", self.vars.len());
        self.var(&var, Some(var_ty()))
    }

    fn mk_cond_equals(&mut self, &var: &Self::Variable, val: u64) -> Self::Condition {
        let val = self.constant(&format!("{}", val), Some(var_ty()));
        self.expr(&[var, val], c_ast::Expr::Eq)
    }

    fn mk_cond_from_bool_var(&mut self, &var: &Self::BoolVariable) -> Self::Condition {
        var
    }

    fn mk_var_assign(&mut self, &var: &Self::Variable, val: u64) -> Self::Block {
        let val = self.constant(&format!("{}", val), Some(var_ty()));
        let unk = self.unknown;
        vec![self.assign(var, val, unk)]
    }

    fn mk_bool_var_assign(
        &mut self,
        &var: &Self::BoolVariable,
        &cond: &Self::Condition,
    ) -> Self::Block {
        let unk = self.unknown;
        vec![self.assign(var, cond, unk)]
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Gamma and derived distributions.

use std::num::Float;
use std::num;
use {Rng, Open01};
use super::normal::StandardNormal;
use super::{IndependentSample, Sample, Exp};

/// The Gamma distribution `Gamma(shape, scale)` distribution.
///
/// The density function of this distribution is
///
/// ```notrust
/// f(x) =  x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k)
/// ```
///
/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the
/// scale and both `k` and `θ` are strictly positive.
///
/// The algorithm used is that described by Marsaglia & Tsang 2000[1],
/// falling back to directly sampling from an Exponential for `shape
/// == 1`, and using the boosting technique described in [1] for
/// `shape < 1`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{IndependentSample, Gamma};
///
/// let gamma = Gamma::new(2.0, 5.0);
/// let v = gamma.ind_sample(&mut rand::task_rng());
/// println!("{} is from a Gamma(2, 5) distribution", v);
/// ```
///
/// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method
/// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
/// (September 2000),
/// 363-372. DOI:[10.1145/358407.358414](http://doi.acm.org/10.1145/358407.358414)
pub enum Gamma {
    priv Large(GammaLargeShape),
    priv One(Exp),
    priv Small(GammaSmallShape)
}

// These two helpers could be made public, but saving the
// match-on-Gamma-enum branch from using them directly (e.g. if one
// knows that the shape is always > 1) doesn't appear to be much
// faster.

/// Gamma distribution where the shape parameter is less than 1.
///
/// Note, samples from this require a compulsory floating-point `pow`
/// call, which makes it significantly slower than sampling from a
/// gamma distribution where the shape parameter is greater than or
/// equal to 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
struct GammaSmallShape {
    inv_shape: f64,
    large_shape: GammaLargeShape
}

/// Gamma distribution where the shape parameter is larger than 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
struct GammaLargeShape {
    shape: f64,
    scale: f64,
    c: f64,
    d: f64
}

impl Gamma {
    /// Construct an object representing the `Gamma(shape, scale)`
    /// distribution.
    ///
    /// Fails if `shape <= 0` or `scale <= 0`.
    pub fn new(shape: f64, scale: f64) -> Gamma {
        assert!(shape > 0.0, "Gamma::new called with shape <= 0");
        assert!(scale > 0.0, "Gamma::new called with scale <= 0");

        match shape {
            1.0        => One(Exp::new(1.0 / scale)),
            0.0 .. 1.0 => Small(GammaSmallShape::new_raw(shape, scale)),
            _          => Large(GammaLargeShape::new_raw(shape, scale))
        }
    }
}

impl GammaSmallShape {
    fn new_raw(shape: f64, scale: f64) -> GammaSmallShape {
        GammaSmallShape {
            inv_shape: 1. / shape,
            large_shape: GammaLargeShape::new_raw(shape + 1.0, scale)
        }
    }
}

impl GammaLargeShape {
    fn new_raw(shape: f64, scale: f64) -> GammaLargeShape {
        let d = shape - 1. / 3.;
        GammaLargeShape {
            shape: shape,
            scale: scale,
            c: 1. / num::sqrt(9. * d),
            d: d
        }
    }
}

impl Sample<f64> for Gamma {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaSmallShape {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaLargeShape {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}

impl IndependentSample<f64> for Gamma {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        match *self {
            Small(ref g) => g.ind_sample(rng),
            One(ref g) => g.ind_sample(rng),
            Large(ref g) => g.ind_sample(rng),
        }
    }
}
impl IndependentSample<f64> for GammaSmallShape {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        let Open01(u) = rng.gen::<Open01<f64>>();

        self.large_shape.ind_sample(rng) * num::powf(u, self.inv_shape)
    }
}
impl IndependentSample<f64> for GammaLargeShape {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        loop {
            let StandardNormal(x) = rng.gen::<StandardNormal>();
            let v_cbrt = 1.0 + self.c * x;
            if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0
                continue
            }

            let v = v_cbrt * v_cbrt * v_cbrt;
            let Open01(u) = rng.gen::<Open01<f64>>();

            let x_sqr = x * x;
            if u < 1.0 - 0.0331 * x_sqr * x_sqr ||
                num::ln(u) < 0.5 * x_sqr + self.d * (1.0 - v + num::ln(v)) {
                return self.d * v * self.scale
            }
        }
    }
}

/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of
/// freedom.
///
/// For `k > 0` integral, this distribution is the sum of the squares
/// of `k` independent standard normal random variables. For other
/// `k`, this uses the equivalent characterisation `χ²(k) = Gamma(k/2,
/// 2)`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{ChiSquared, IndependentSample};
///
/// let chi = ChiSquared::new(11.0);
/// let v = chi.ind_sample(&mut rand::task_rng());
/// println!("{} is from a χ²(11) distribution", v)
/// ```
pub enum ChiSquared {
    // k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1,
    // e.g. when alpha = 1/2 as it would be for this case, so special-
    // casing and using the definition of N(0,1)^2 is faster.
    priv DoFExactlyOne,
    priv DoFAnythingElse(Gamma)
}

impl ChiSquared {
    /// Create a new chi-squared distribution with degrees-of-freedom
    /// `k`. Fails if `k < 0`.
    pub fn new(k: f64) -> ChiSquared {
        if k == 1.0 {
            DoFExactlyOne
        } else {
            assert!(k > 0.0, "ChiSquared::new called with `k` < 0");
            DoFAnythingElse(Gamma::new(0.5 * k, 2.0))
        }
    }
}
impl Sample<f64> for ChiSquared {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for ChiSquared {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        match *self {
            DoFExactlyOne => {
                // k == 1 => N(0,1)^2
                let StandardNormal(norm) = rng.gen::<StandardNormal>();
                norm * norm
            }
            DoFAnythingElse(ref g) => g.ind_sample(rng)
        }
    }
}

/// The Fisher F distribution `F(m, n)`.
///
/// This distribution is equivalent to the ratio of two normalised
/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) /
/// (χ²(n)/n)`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{FisherF, IndependentSample};
///
/// let f = FisherF::new(2.0, 32.0);
/// let v = f.ind_sample(&mut rand::task_rng());
/// println!("{} is from an F(2, 32) distribution", v)
/// ```
pub struct FisherF {
    numer: ChiSquared,
    denom: ChiSquared,
    // denom_dof / numer_dof so that this can just be a straight
    // multiplication, rather than a division.
    dof_ratio: f64,
}

impl FisherF {
    /// Create a new `FisherF` distribution, with the given
    /// parameter. Fails if either `m` or `n` are not positive.
    pub fn new(m: f64, n: f64) -> FisherF {
        assert!(m > 0.0, "FisherF::new called with `m < 0`");
        assert!(n > 0.0, "FisherF::new called with `n < 0`");

        FisherF {
            numer: ChiSquared::new(m),
            denom: ChiSquared::new(n),
            dof_ratio: n / m
        }
    }
}
impl Sample<f64> for FisherF {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for FisherF {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        self.numer.ind_sample(rng) / self.denom.ind_sample(rng) * self.dof_ratio
    }
}

/// The Student t distribution, `t(nu)`, where `nu` is the degrees of
/// freedom.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{StudentT, IndependentSample};
///
/// let t = StudentT::new(11.0);
/// let v = t.ind_sample(&mut rand::task_rng());
/// println!("{} is from a t(11) distribution", v)
/// ```
pub struct StudentT {
    chi: ChiSquared,
    dof: f64
}

impl StudentT {
    /// Create a new Student t distribution with `n` degrees of
    /// freedom. Fails if `n <= 0`.
    pub fn new(n: f64) -> StudentT {
        assert!(n > 0.0, "StudentT::new called with `n <= 0`");
        StudentT {
            chi: ChiSquared::new(n),
            dof: n
        }
    }
}
impl Sample<f64> for StudentT {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for StudentT {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        let StandardNormal(norm) = rng.gen::<StandardNormal>();
        norm * (self.dof / self.chi.ind_sample(rng)).sqrt()
    }
}

#[cfg(test)]
mod test {
    use distributions::{Sample, IndependentSample};
    use {Rng, task_rng};
    use super::{ChiSquared, StudentT, FisherF};

    #[test]
    fn test_chi_squared_one() {
        let mut chi = ChiSquared::new(1.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    fn test_chi_squared_small() {
        let mut chi = ChiSquared::new(0.5);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    fn test_chi_squared_large() {
        let mut chi = ChiSquared::new(30.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    #[should_fail]
    fn test_chi_squared_invalid_dof() {
        ChiSquared::new(-1.0);
    }

    #[test]
    fn test_f() {
        let mut f = FisherF::new(2.0, 32.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            f.sample(&mut rng);
            f.ind_sample(&mut rng);
        }
    }

    #[test]
    fn test_t() {
        let mut t = StudentT::new(11.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            t.sample(&mut rng);
            t.ind_sample(&mut rng);
        }
    }
}

#[cfg(test)]
mod bench {
    extern crate test;
    use self::test::BenchHarness;
    use std::mem::size_of;
    use distributions::IndependentSample;
    use {XorShiftRng, RAND_BENCH_N};
    use super::Gamma;

    #[bench]
    fn bench_gamma_large_shape(bh: &mut BenchHarness) {
        let gamma = Gamma::new(10., 1.0);
        let mut rng = XorShiftRng::new().unwrap();

        bh.iter(|| {
            for _ in range(0, RAND_BENCH_N) {
                gamma.ind_sample(&mut rng);
            }
        });
        bh.bytes = size_of::<f64>() as u64 * RAND_BENCH_N;
    }

    #[bench]
    fn bench_gamma_small_shape(bh: &mut BenchHarness) {
        let gamma = Gamma::new(0.1, 1.0);
        let mut rng = XorShiftRng::new().unwrap();

        bh.iter(|| {
            for _ in range(0, RAND_BENCH_N) {
                gamma.ind_sample(&mut rng);
            }
        });
        bh.bytes = size_of::<f64>() as u64 * RAND_BENCH_N;
    }
}
<commit_msg>auto merge of #13225 : thestinger/rust/num, r=cmr<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Gamma and derived distributions.

use std::num::Float;
use {Rng, Open01};
use super::normal::StandardNormal;
use super::{IndependentSample, Sample, Exp};

/// The Gamma distribution `Gamma(shape, scale)` distribution.
///
/// The density function of this distribution is
///
/// ```notrust
/// f(x) =  x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k)
/// ```
///
/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the
/// scale and both `k` and `θ` are strictly positive.
///
/// The algorithm used is that described by Marsaglia & Tsang 2000[1],
/// falling back to directly sampling from an Exponential for `shape
/// == 1`, and using the boosting technique described in [1] for
/// `shape < 1`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{IndependentSample, Gamma};
///
/// let gamma = Gamma::new(2.0, 5.0);
/// let v = gamma.ind_sample(&mut rand::task_rng());
/// println!("{} is from a Gamma(2, 5) distribution", v);
/// ```
///
/// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method
/// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
/// (September 2000),
/// 363-372. DOI:[10.1145/358407.358414](http://doi.acm.org/10.1145/358407.358414)
pub enum Gamma {
    priv Large(GammaLargeShape),
    priv One(Exp),
    priv Small(GammaSmallShape)
}

// These two helpers could be made public, but saving the
// match-on-Gamma-enum branch from using them directly (e.g. if one
// knows that the shape is always > 1) doesn't appear to be much
// faster.

/// Gamma distribution where the shape parameter is less than 1.
///
/// Note, samples from this require a compulsory floating-point `pow`
/// call, which makes it significantly slower than sampling from a
/// gamma distribution where the shape parameter is greater than or
/// equal to 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
struct GammaSmallShape {
    inv_shape: f64,
    large_shape: GammaLargeShape
}

/// Gamma distribution where the shape parameter is larger than 1.
///
/// See `Gamma` for sampling from a Gamma distribution with general
/// shape parameters.
struct GammaLargeShape {
    shape: f64,
    scale: f64,
    c: f64,
    d: f64
}

impl Gamma {
    /// Construct an object representing the `Gamma(shape, scale)`
    /// distribution.
    ///
    /// Fails if `shape <= 0` or `scale <= 0`.
    pub fn new(shape: f64, scale: f64) -> Gamma {
        assert!(shape > 0.0, "Gamma::new called with shape <= 0");
        assert!(scale > 0.0, "Gamma::new called with scale <= 0");

        match shape {
            1.0        => One(Exp::new(1.0 / scale)),
            0.0 .. 1.0 => Small(GammaSmallShape::new_raw(shape, scale)),
            _          => Large(GammaLargeShape::new_raw(shape, scale))
        }
    }
}

impl GammaSmallShape {
    fn new_raw(shape: f64, scale: f64) -> GammaSmallShape {
        GammaSmallShape {
            inv_shape: 1. / shape,
            large_shape: GammaLargeShape::new_raw(shape + 1.0, scale)
        }
    }
}

impl GammaLargeShape {
    fn new_raw(shape: f64, scale: f64) -> GammaLargeShape {
        let d = shape - 1. / 3.;
        GammaLargeShape {
            shape: shape,
            scale: scale,
            c: 1. / (9. * d).sqrt(),
            d: d
        }
    }
}

impl Sample<f64> for Gamma {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaSmallShape {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl Sample<f64> for GammaLargeShape {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}

impl IndependentSample<f64> for Gamma {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        match *self {
            Small(ref g) => g.ind_sample(rng),
            One(ref g) => g.ind_sample(rng),
            Large(ref g) => g.ind_sample(rng),
        }
    }
}
impl IndependentSample<f64> for GammaSmallShape {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        let Open01(u) = rng.gen::<Open01<f64>>();

        self.large_shape.ind_sample(rng) * u.powf(&self.inv_shape)
    }
}
impl IndependentSample<f64> for GammaLargeShape {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        loop {
            let StandardNormal(x) = rng.gen::<StandardNormal>();
            let v_cbrt = 1.0 + self.c * x;
            if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0
                continue
            }

            let v = v_cbrt * v_cbrt * v_cbrt;
            let Open01(u) = rng.gen::<Open01<f64>>();

            let x_sqr = x * x;
            if u < 1.0 - 0.0331 * x_sqr * x_sqr ||
                u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln()) {
                return self.d * v * self.scale
            }
        }
    }
}

/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of
/// freedom.
///
/// For `k > 0` integral, this distribution is the sum of the squares
/// of `k` independent standard normal random variables. For other
/// `k`, this uses the equivalent characterisation `χ²(k) = Gamma(k/2,
/// 2)`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{ChiSquared, IndependentSample};
///
/// let chi = ChiSquared::new(11.0);
/// let v = chi.ind_sample(&mut rand::task_rng());
/// println!("{} is from a χ²(11) distribution", v)
/// ```
pub enum ChiSquared {
    // k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1,
    // e.g. when alpha = 1/2 as it would be for this case, so special-
    // casing and using the definition of N(0,1)^2 is faster.
    priv DoFExactlyOne,
    priv DoFAnythingElse(Gamma)
}

impl ChiSquared {
    /// Create a new chi-squared distribution with degrees-of-freedom
    /// `k`. Fails if `k < 0`.
    pub fn new(k: f64) -> ChiSquared {
        if k == 1.0 {
            DoFExactlyOne
        } else {
            assert!(k > 0.0, "ChiSquared::new called with `k` < 0");
            DoFAnythingElse(Gamma::new(0.5 * k, 2.0))
        }
    }
}
impl Sample<f64> for ChiSquared {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for ChiSquared {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        match *self {
            DoFExactlyOne => {
                // k == 1 => N(0,1)^2
                let StandardNormal(norm) = rng.gen::<StandardNormal>();
                norm * norm
            }
            DoFAnythingElse(ref g) => g.ind_sample(rng)
        }
    }
}

/// The Fisher F distribution `F(m, n)`.
///
/// This distribution is equivalent to the ratio of two normalised
/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) /
/// (χ²(n)/n)`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{FisherF, IndependentSample};
///
/// let f = FisherF::new(2.0, 32.0);
/// let v = f.ind_sample(&mut rand::task_rng());
/// println!("{} is from an F(2, 32) distribution", v)
/// ```
pub struct FisherF {
    numer: ChiSquared,
    denom: ChiSquared,
    // denom_dof / numer_dof so that this can just be a straight
    // multiplication, rather than a division.
    dof_ratio: f64,
}

impl FisherF {
    /// Create a new `FisherF` distribution, with the given
    /// parameter. Fails if either `m` or `n` are not positive.
    pub fn new(m: f64, n: f64) -> FisherF {
        assert!(m > 0.0, "FisherF::new called with `m < 0`");
        assert!(n > 0.0, "FisherF::new called with `n < 0`");

        FisherF {
            numer: ChiSquared::new(m),
            denom: ChiSquared::new(n),
            dof_ratio: n / m
        }
    }
}
impl Sample<f64> for FisherF {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for FisherF {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        self.numer.ind_sample(rng) / self.denom.ind_sample(rng) * self.dof_ratio
    }
}

/// The Student t distribution, `t(nu)`, where `nu` is the degrees of
/// freedom.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{StudentT, IndependentSample};
///
/// let t = StudentT::new(11.0);
/// let v = t.ind_sample(&mut rand::task_rng());
/// println!("{} is from a t(11) distribution", v)
/// ```
pub struct StudentT {
    chi: ChiSquared,
    dof: f64
}

impl StudentT {
    /// Create a new Student t distribution with `n` degrees of
    /// freedom. Fails if `n <= 0`.
    pub fn new(n: f64) -> StudentT {
        assert!(n > 0.0, "StudentT::new called with `n <= 0`");
        StudentT {
            chi: ChiSquared::new(n),
            dof: n
        }
    }
}
impl Sample<f64> for StudentT {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for StudentT {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        let StandardNormal(norm) = rng.gen::<StandardNormal>();
        norm * (self.dof / self.chi.ind_sample(rng)).sqrt()
    }
}

#[cfg(test)]
mod test {
    use distributions::{Sample, IndependentSample};
    use {Rng, task_rng};
    use super::{ChiSquared, StudentT, FisherF};

    #[test]
    fn test_chi_squared_one() {
        let mut chi = ChiSquared::new(1.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    fn test_chi_squared_small() {
        let mut chi = ChiSquared::new(0.5);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    fn test_chi_squared_large() {
        let mut chi = ChiSquared::new(30.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            chi.sample(&mut rng);
            chi.ind_sample(&mut rng);
        }
    }
    #[test]
    #[should_fail]
    fn test_chi_squared_invalid_dof() {
        ChiSquared::new(-1.0);
    }

    #[test]
    fn test_f() {
        let mut f = FisherF::new(2.0, 32.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            f.sample(&mut rng);
            f.ind_sample(&mut rng);
        }
    }

    #[test]
    fn test_t() {
        let mut t = StudentT::new(11.0);
        let mut rng = task_rng();
        for _ in range(0, 1000) {
            t.sample(&mut rng);
            t.ind_sample(&mut rng);
        }
    }
}

#[cfg(test)]
mod bench {
    extern crate test;
    use self::test::BenchHarness;
    use std::mem::size_of;
    use distributions::IndependentSample;
    use {XorShiftRng, RAND_BENCH_N};
    use super::Gamma;

    #[bench]
    fn bench_gamma_large_shape(bh: &mut BenchHarness) {
        let gamma = Gamma::new(10., 1.0);
        let mut rng = XorShiftRng::new().unwrap();

        bh.iter(|| {
            for _ in range(0, RAND_BENCH_N) {
                gamma.ind_sample(&mut rng);
            }
        });
        bh.bytes = size_of::<f64>() as u64 * RAND_BENCH_N;
    }

    #[bench]
    fn bench_gamma_small_shape(bh: &mut BenchHarness) {
        let gamma = Gamma::new(0.1, 1.0);
        let mut rng = XorShiftRng::new().unwrap();

        bh.iter(|| {
            for _ in range(0, RAND_BENCH_N) {
                gamma.ind_sample(&mut rng);
            }
        });
        bh.bytes = size_of::<f64>() as u64 * RAND_BENCH_N;
    }
}
<|endoftext|>


<commit_before>//! Helper functions for signed json.

use std;
use std::collections::BTreeMap;

use serde_json::{value, ser};
use serde_json::error::Error as SerdeJsonError;
use sodiumoxide::crypto::sign;

use rustc_serialize::base64;
use rustc_serialize::base64::ToBase64;

pub type Object = BTreeMap<String, value::Value>;

quick_error! {
    #[derive(Debug)]
    pub enum SigningJsonError {
        Serialization(err: SerdeJsonError) {
            from()
        }
    }
}

pub type Result<T> = std::result::Result<T, SigningJsonError>;

pub const UNPADDED_BASE64 : base64::Config = base64::Config {
    char_set: base64::CharacterSet::Standard,
    newline: base64::Newline::LF,
    pad: false,
    line_length: None,
};

#[derive(Debug, Clone)]
pub struct SigningKey {
    /// Public part of ED25519 signing key
    pub public: sign::PublicKey,
    /// Secret part of ED25519 signing key
    pub secret: sign::SecretKey,
    /// A unique ID for this signing key.
    pub key_id: String,
}

impl SigningKey {
    /// Create the signing key from a standard ED25519 seed
    pub fn from_seed(seed: &[u8], key_id: String) -> Option<SigningKey> {
        if let Some(seed) = sign::Seed::from_slice(seed) {
            let (public, secret) = sign::keypair_from_seed(&seed);
            Some(SigningKey {
                public: public,
                secret: secret,
                key_id: key_id,
            })
        } else {
            None
        }
    }

    /// Return a unpadded base64 version of the public key.
    pub fn public_key_b64(&self) -> String {
        self.public.0.to_base64(UNPADDED_BASE64)
    }
}

/// Takes a JSON object, signs it, and adds the signature to the object.
pub fn sign_json(key: &SigningKey, entity_name: String, json: &mut Object) -> Result<()> {
    let b64sig = try!(get_sig_for_json_b64(key, json));

    // json.entry("Signature".to_string()).or_insert();
    let mut sig_obj = get_or_insert(json, "signatures".to_string());
    let mut sig_place = get_or_insert(sig_obj, entity_name);
    sig_place.insert(key.key_id.clone(), value::Value::String(b64sig));
    Ok(())
}

/// Returns the base64 encoded signature for a JSON object
pub fn get_sig_for_json_b64(key: &SigningKey, json: &Object) -> Result<String> {
    let serialized = if json.contains_key("signatures") {
        let mut j = json.clone();
        j.remove("signatures");
        try!(ser::to_string(&j))
    } else {
        try!(ser::to_string(&json))
    };

    let signature = sign::sign_detached(serialized.as_bytes(), &key.secret);
    Ok(signature.0.to_base64(UNPADDED_BASE64))
}

fn get_or_insert<'a>(json: &'a mut Object, s: String) -> &'a mut Object {
    let mut val = json.entry(s).or_insert(value::Value::Object(Object::new()));

    if let &mut value::Value::Object(ref mut obj) = val {
        obj
    } else {
        *val = value::Value::Object(Object::new());
        val.as_object_mut().unwrap()
    }
}

// Tests

#[cfg(test)] use serde_json;
#[cfg(test)] use rustc_serialize::base64::FromBase64;

#[test]
fn test_get_or_insert() {
    let mut map = Object::new();
    get_or_insert(&mut map, "foo".to_string());
    println!("{}", ser::to_string(&map).unwrap());
    map.get_mut("foo").unwrap().as_object_mut().unwrap().insert("test".to_string(), value::Value::U64(1));
    get_or_insert(&mut map, "foo".to_string());
    println!("{}", ser::to_string(&map).unwrap());

    map.insert("foo".to_string(), value::Value::Null);
    println!("{}", ser::to_string(&map).unwrap());
    get_or_insert(&mut map, "foo".to_string());
    println!("{}", ser::to_string(&map).unwrap());
}

#[test]
fn test_sign() {
    let seed_bytes = "YJDBA9Xnr2sVqXD9Vj7XVUnmFZcZrlw8Md7kMW+3XA1".from_base64().unwrap();
    let seed = sign::Seed::from_slice(&seed_bytes[..]).unwrap();
    let (pub_key, priv_key) = sign::keypair_from_seed(&seed);

    let sig_key = SigningKey {
        public: pub_key,
        secret: priv_key,
        key_id: "ed25519:1".to_string(),
    };

    {
        let mut json = serde_json::from_slice::<value::Value>(b"{}").unwrap();
        sign_json(&sig_key, "domain".to_string(), json.as_object_mut().unwrap()).unwrap();

        let signed_json = ser::to_string(&json).unwrap();

        assert_eq!(
            signed_json,
            r#"{"signatures":{"domain":{"ed25519:1":"K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ"}}}"#
        );
    }

    {
        let mut json = serde_json::from_slice::<value::Value>(
            br#"{"one": 1, "two": "Two"}"#
        ).unwrap();
        sign_json(&sig_key, "domain".to_string(), json.as_object_mut().unwrap()).unwrap();

        let signed_json = ser::to_string(&json).unwrap();

        assert_eq!(
            signed_json,
            r#"{"one":1,"signatures":{"domain":{"ed25519:1":"KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw"}},"two":"Two"}"#
        );
    }

    {
        let mut json = serde_json::from_slice::<value::Value>(
            br#"{"one": 1, "two": "Two", "signatures": {}}"#
        ).unwrap();
        sign_json(&sig_key, "domain".to_string(), json.as_object_mut().unwrap()).unwrap();

        let signed_json = ser::to_string(&json).unwrap();

        assert_eq!(
            signed_json,
            r#"{"one":1,"signatures":{"domain":{"ed25519:1":"KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw"}},"two":"Two"}"#
        );
    }
}
<commit_msg>More test cases<commit_after>//! Helper functions for signed json.

use std;
use std::collections::BTreeMap;

use serde_json::{value, ser};
use serde_json::error::Error as SerdeJsonError;
use sodiumoxide::crypto::sign;

use rustc_serialize::base64;
use rustc_serialize::base64::ToBase64;

pub type Object = BTreeMap<String, value::Value>;

quick_error! {
    #[derive(Debug)]
    pub enum SigningJsonError {
        Serialization(err: SerdeJsonError) {
            from()
        }
    }
}

pub type Result<T> = std::result::Result<T, SigningJsonError>;

pub const UNPADDED_BASE64 : base64::Config = base64::Config {
    char_set: base64::CharacterSet::Standard,
    newline: base64::Newline::LF,
    pad: false,
    line_length: None,
};

#[derive(Debug, Clone)]
pub struct SigningKey {
    /// Public part of ED25519 signing key
    pub public: sign::PublicKey,
    /// Secret part of ED25519 signing key
    pub secret: sign::SecretKey,
    /// A unique ID for this signing key.
    pub key_id: String,
}

impl SigningKey {
    /// Create the signing key from a standard ED25519 seed
    pub fn from_seed(seed: &[u8], key_id: String) -> Option<SigningKey> {
        if let Some(seed) = sign::Seed::from_slice(seed) {
            let (public, secret) = sign::keypair_from_seed(&seed);
            Some(SigningKey {
                public: public,
                secret: secret,
                key_id: key_id,
            })
        } else {
            None
        }
    }

    /// Return a unpadded base64 version of the public key.
    pub fn public_key_b64(&self) -> String {
        self.public.0.to_base64(UNPADDED_BASE64)
    }
}

/// Takes a JSON object, signs it, and adds the signature to the object.
pub fn sign_json(key: &SigningKey, entity_name: String, json: &mut Object) -> Result<()> {
    let b64sig = try!(get_sig_for_json_b64(key, json));

    // json.entry("Signature".to_string()).or_insert();
    let mut sig_obj = get_or_insert(json, "signatures".to_string());
    let mut sig_place = get_or_insert(sig_obj, entity_name);
    sig_place.insert(key.key_id.clone(), value::Value::String(b64sig));
    Ok(())
}

/// Returns the base64 encoded signature for a JSON object
pub fn get_sig_for_json_b64(key: &SigningKey, json: &Object) -> Result<String> {
    let serialized = if json.contains_key("signatures") {
        let mut j = json.clone();
        j.remove("signatures");
        try!(ser::to_string(&j))
    } else {
        try!(ser::to_string(&json))
    };

    let signature = sign::sign_detached(serialized.as_bytes(), &key.secret);
    Ok(signature.0.to_base64(UNPADDED_BASE64))
}

fn get_or_insert<'a>(json: &'a mut Object, s: String) -> &'a mut Object {
    let mut val = json.entry(s).or_insert(value::Value::Object(Object::new()));

    if let &mut value::Value::Object(ref mut obj) = val {
        obj
    } else {
        *val = value::Value::Object(Object::new());
        val.as_object_mut().unwrap()
    }
}

// Tests

#[cfg(test)] use serde_json;
#[cfg(test)] use rustc_serialize::base64::FromBase64;

#[test]
fn test_get_or_insert() {
    let mut map = Object::new();
    get_or_insert(&mut map, "foo".to_string());
    println!("{}", ser::to_string(&map).unwrap());
    map.get_mut("foo").unwrap().as_object_mut().unwrap().insert("test".to_string(), value::Value::U64(1));
    get_or_insert(&mut map, "foo".to_string());
    println!("{}", ser::to_string(&map).unwrap());

    map.insert("foo".to_string(), value::Value::Null);
    println!("{}", ser::to_string(&map).unwrap());
    get_or_insert(&mut map, "foo".to_string());
    println!("{}", ser::to_string(&map).unwrap());
}

#[test]
fn test_sign() {
    let seed_bytes = "YJDBA9Xnr2sVqXD9Vj7XVUnmFZcZrlw8Md7kMW+3XA1".from_base64().unwrap();
    let seed = sign::Seed::from_slice(&seed_bytes[..]).unwrap();
    let (pub_key, priv_key) = sign::keypair_from_seed(&seed);

    let sig_key = SigningKey {
        public: pub_key,
        secret: priv_key,
        key_id: "ed25519:1".to_string(),
    };

    assert_eq!(
        sign_bytes_json(&sig_key, b"{}"),
        r#"{"signatures":{"domain":{"ed25519:1":"K8280/U9SSy9IVtjBuVeLr+HpOB4BQFWbg+UZaADMtTdGYI7Geitb76LTrr5QV/7Xg4ahLwYGYZzuHGZKM5ZAQ"}}}"#
    );

    assert_eq!(
        sign_bytes_json(&sig_key, br#"{"one": 1, "two": "Two"}"#),
        r#"{"one":1,"signatures":{"domain":{"ed25519:1":"KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw"}},"two":"Two"}"#
    );

    assert_eq!(
        sign_bytes_json(&sig_key,
            br#"{"one": 1, "two": "Two", "signatures": {}}"#
        ),
        r#"{"one":1,"signatures":{"domain":{"ed25519:1":"KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw"}},"two":"Two"}"#
    );

    assert_eq!(
        sign_bytes_json(&sig_key,
            br#"{"one": 1, "two": "Two", "signatures": {"domain2": {}}}"#
        ),
        r#"{"one":1,"signatures":{"domain":{"ed25519:1":"KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw"},"domain2":{}},"two":"Two"}"#
    );

    assert_eq!(
        sign_bytes_json(&sig_key,
            br#"{"one": 1, "two": "Two", "signatures": {"domain": {"ed25519:2": "ABC"}}}"#
        ),
        r#"{"one":1,"signatures":{"domain":{"ed25519:1":"KqmLSbO39/Bzb0QIYE82zqLwsA+PDzYIpIRA2sRQ4sL53+sN6/fpNSoqE7BP7vBZhG6kYdD13EIMJpvhJI+6Bw","ed25519:2":"ABC"}},"two":"Two"}"#
    );
}

#[cfg(test)]
fn sign_bytes_json(sig_key: &SigningKey, s: &[u8]) -> String {
    let mut json = serde_json::from_slice::<value::Value>(s).unwrap();
    sign_json(&sig_key, "domain".to_string(), json.as_object_mut().unwrap()).unwrap();
    ser::to_string(&json).unwrap()
}
<|endoftext|>


<commit_before>// Copyright 2013 The noise-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This is a form of gradient noise, similar to Perlin or simplex noise,
//! but using a simplectic honeycomb. The 2D case is functionally identical
//! to simplex noise. The 3D case is a tetrahedral-octohedral honeycomb and
//! the 4D case is a 5-cell honeycomb. See the Wikipedia article on
//! simplectic honeycombs for more info:
//! http://en.wikipedia.org/wiki/Simplectic_honeycomb
//!
//! The virtue of this noise, over the alternatives, is it's algorithmic
//! cleanliness. In any dimension, it can be seen as a series of layers of
//! the noise function from the lower dimension. So for any given point,
//! one can calculate the lower dimensional noise twice, one for the layer
//! below and one for the layer above, to get the relevant set of gradient
//! points. Thus, 3D noise can be composed out of two iterations of 2D
//! noise, and 4D noise can be composed out of two iterations of 3D noise,
//! or four iterations of 2D noise.

use std::num::{cast, Float};

use {gradient, math, Seed};

struct SimplecticPoint2<T: Float> {
    cell: math::Point2<i64>,
    offset: math::Vector2<T>,
}

impl<T: Float> SimplecticPoint2<T> {
    fn to_simplectic_point3(&self, z_cell: i64, z_offset: T) -> SimplecticPoint3<T> {
        SimplecticPoint3 {
            cell: [self.cell[0], self.cell[1], z_cell],
            offset: [self.offset[0], self.offset[1], z_offset],
        }
    }
}

struct SimplecticPoint3<T: Float> {
    cell: math::Point3<i64>,
    offset: math::Vector3<T>,
}

impl<T: Float> SimplecticPoint3<T> {
    fn to_simplectic_point4(&self, w_cell: i64, w_offset: T) -> SimplecticPoint4<T> {
        SimplecticPoint4 {
            cell: [self.cell[0], self.cell[1], self.cell[2], w_cell],
            offset: [self.offset[0], self.offset[1], self.offset[2], w_offset],
        }
    }
}

struct SimplecticPoint4<T: Float> {
    cell: math::Point4<i64>,
    offset: math::Vector4<T>,
}

fn skew_constant<T: Float>() -> T { math::cast(0.36602540378_f64) } // 0.5 * (sqrt(3.0) - 1.0)
fn unskew_constant<T: Float>() -> T { math::cast(0.2113248654_f64) } // (3.0 - sqrt(3.0)) / 6.0

fn simplex_size<T: Float>() -> T { math::cast(0.70710678119_f64) }
fn inv_simplex_size<T: Float>() -> T { math::cast(1.41421356235_f64) } // 1 / simplex_size()
fn layer_offset_x<T: Float>() -> T { math::cast(0.45534180126_f64) } // (2.0 - 3.0 * unskew_constant()) / 3.0
fn layer_offset_y<T: Float>() -> T { math::cast(0.12200846793_f64) } // (1.0 - 3.0 * unskew_constant()) / 3.0
fn layer_offset_z<T: Float>() -> T { math::cast(0.35355339059_f64) } // (1.0 - 3.0 * unskew_constant()) / 3.0

fn norm2_constant<T: Float>() -> T { math::cast(8.0_f64) }
fn norm3_constant<T: Float>() -> T { math::cast(9.0_f64) }
fn norm4_constant<T: Float>() -> T { math::cast(10.0_f64) }

#[inline(always)]
fn simplectic2_points<T: Float>(point: &math::Point2<T>) -> [SimplecticPoint2<T>; 3] {
    let zero: T = math::cast(0u);
    let one: T = math::cast(1u);
    let two: T = math::cast(2u);

    // Skew the input coordinates into the grid to figure out which grid cell we're in
    let skew_offset = (point[0] + point[1]) * skew_constant();
    let x_cell = (point[0] + skew_offset).floor();
    let y_cell = (point[1] + skew_offset).floor();

    // Unskew the floored coordinates to find the real coordinates of the cell's origin
    let unskew_offset = (x_cell + y_cell) * unskew_constant();
    let x_origin = x_cell - unskew_offset;
    let y_origin = y_cell - unskew_offset;

    // Compute the delta from the first point, which is the cell origin
    let dx0 = point[0] - x_origin;
    let dy0 = point[1] - y_origin;

    // Compute the delta from the second point, which depends on which simplex we're in
    let (x1_offset, y1_offset) = if dx0 > dy0 { (one, zero) } else { (zero, one) };
    let dx1 = dx0 - x1_offset + unskew_constant();
    let dy1 = dy0 - y1_offset + unskew_constant();

    // Compute the delta from the third point
    let dx2 = dx0 - one + two * unskew_constant();
    let dy2 = dy0 - one + two * unskew_constant();

    [
        SimplecticPoint2 {
            cell: [math::cast(x_cell), math::cast(y_cell)],
            offset: [dx0, dy0],
        },
        SimplecticPoint2 {
            cell: [math::cast(x_cell + x1_offset), math::cast(y_cell + y1_offset)],
            offset: [dx1, dy1],
        },
        SimplecticPoint2 {
            cell: [1i64 + math::cast(x_cell), 1i64 + math::cast(y_cell)],
            offset: [dx2, dy2],
        },
    ]
}

#[inline(always)]
fn simplectic3_points<T: Float>(point: &math::Point3<T>) -> [SimplecticPoint3<T>; 6] {
    let layer = (point[2] * inv_simplex_size()).floor();
    let layer_int: i64 = math::cast(layer);

    let point2 = [point[0], point[1]];
    let offset_point2 = [point[0] + layer_offset_x(),
                         point[1] + layer_offset_y()];

    let (layer1_point, layer2_point) = match layer_int % 2 {
        0 => (point2, offset_point2),
        _ => (offset_point2, point2),
    };

    let [p1, p2, p3] = simplectic2_points(&layer1_point);
    let [p4, p5, p6] = simplectic2_points(&layer2_point);

    let z_offset = point[2] - layer * simplex_size();
    [
        p1.to_simplectic_point3(layer_int, z_offset),
        p2.to_simplectic_point3(layer_int, z_offset),
        p3.to_simplectic_point3(layer_int, z_offset),
        p4.to_simplectic_point3(layer_int + 1, z_offset - simplex_size()),
        p5.to_simplectic_point3(layer_int + 1, z_offset - simplex_size()),
        p6.to_simplectic_point3(layer_int + 1, z_offset - simplex_size()),
    ]
}

#[inline(always)]
fn simplectic4_points<T: Float>(point: &math::Point4<T>) -> [SimplecticPoint4<T>; 12] {
    let layer = (point[3] * inv_simplex_size()).floor();
    let layer_int: i64 = math::cast(layer);

    let point3 = [point[0], point[1], point[2]];
    let offset_point3 = [point[0] + layer_offset_x(),
                         point[1] + layer_offset_y(),
                         point[2] + layer_offset_z()];

    let (layer1_point, layer2_point) = match layer_int % 2 {
        0 => (point3, offset_point3),
        _ => (offset_point3, point3),
    };

    let [p1, p2, p3, p4, p5, p6] = simplectic3_points(&layer1_point);
    let [p7, p8, p9, p10, p11, p12] = simplectic3_points(&layer2_point);

    let w_offset = point[3] - layer * simplex_size();
    [
        p1.to_simplectic_point4(layer_int, w_offset),
        p2.to_simplectic_point4(layer_int, w_offset),
        p3.to_simplectic_point4(layer_int, w_offset),
        p4.to_simplectic_point4(layer_int, w_offset),
        p5.to_simplectic_point4(layer_int, w_offset),
        p6.to_simplectic_point4(layer_int, w_offset),
        p7.to_simplectic_point4(layer_int + 1, w_offset - simplex_size()),
        p8.to_simplectic_point4(layer_int + 1, w_offset - simplex_size()),
        p9.to_simplectic_point4(layer_int + 1, w_offset - simplex_size()),
        p10.to_simplectic_point4(layer_int + 1, w_offset - simplex_size()),
        p11.to_simplectic_point4(layer_int + 1, w_offset - simplex_size()),
        p12.to_simplectic_point4(layer_int + 1, w_offset - simplex_size()),
    ]
}

pub fn simplectic2<T: Float>(seed: &Seed, point: &math::Point2<T>) -> T {
    #[inline(always)]
    fn gradient<T: Float>(seed: &Seed, p: &SimplecticPoint2<T>) -> T {
        let attn = simplex_size::<T>() - p.offset[0] * p.offset[0]
                                       - p.offset[1] * p.offset[1];
        if attn > Float::zero() {
            math::pow4(attn) * math::dot2(p.offset, gradient::get2(seed.get2(p.cell)))
        } else {
            Float::zero()
        }
    }

    let [p1, p2, p3] = simplectic2_points(point);

    (gradient(seed, &p1) + gradient(seed, &p2) + gradient(seed, &p3)) * norm2_constant()
}

pub fn simplectic3<T: Float>(seed: &Seed, point: &math::Point3<T>) -> T {
    #[inline(always)]
    fn gradient<T: Float>(seed: &Seed, p: &SimplecticPoint3<T>) -> T {
        let attn = simplex_size::<T>() - p.offset[0] * p.offset[0]
                                       - p.offset[1] * p.offset[1]
                                       - p.offset[2] * p.offset[2];
        if attn > Float::zero() {
            math::pow4(attn) * math::dot3(p.offset, gradient::get3(seed.get3(p.cell)))
        } else {
            Float::zero()
        }
    }

    let [p1, p2, p3, p4, p5, p6] = simplectic3_points(point);

    (
        gradient(seed, &p1) + gradient(seed, &p2) + gradient(seed, &p3) + gradient(seed, &p4) + gradient(seed, &p5) + gradient(seed, &p6)
    ) * norm3_constant()
}

pub fn simplectic4<T: Float>(seed: &Seed, point: &math::Point4<T>) -> T {
    #[inline(always)]
    fn gradient<T: Float>(seed: &Seed, p: &SimplecticPoint4<T>) -> T {
        let attn = simplex_size::<T>() - p.offset[0] * p.offset[0]
                                       - p.offset[1] * p.offset[1]
                                       - p.offset[2] * p.offset[2]
                                       - p.offset[3] * p.offset[3];
        if attn > Float::zero() {
            math::pow4(attn) * math::dot4(p.offset, gradient::get4(seed.get4(p.cell)))
        } else {
            Float::zero()
        }
    }

    let [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12] = simplectic4_points(point);

    (
        gradient(seed, &p1) + gradient(seed, &p2) + gradient(seed, &p3) + gradient(seed, &p4) + gradient(seed, &p5) + gradient(seed, &p6) +
        gradient(seed, &p7) + gradient(seed, &p8) + gradient(seed, &p9) + gradient(seed, &p10) + gradient(seed, &p11) + gradient(seed, &p12)
    ) * norm4_constant()
}
<commit_msg>Add tests that simplectic noise doesn't panic.<commit_after>// Copyright 2013 The noise-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This is a form of gradient noise, similar to Perlin or simplex noise,
//! but using a simplectic honeycomb. The 2D case is functionally identical
//! to simplex noise. The 3D case is a tetrahedral-octohedral honeycomb and
//! the 4D case is a 5-cell honeycomb. See the Wikipedia article on
//! simplectic honeycombs for more info:
//! http://en.wikipedia.org/wiki/Simplectic_honeycomb
//!
//! The virtue of this noise, over the alternatives, is it's algorithmic
//! cleanliness. In any dimension, it can be seen as a series of layers of
//! the noise function from the lower dimension. So for any given point,
//! one can calculate the lower dimensional noise twice, one for the layer
//! below and one for the layer above, to get the relevant set of gradient
//! points. Thus, 3D noise can be composed out of two iterations of 2D
//! noise, and 4D noise can be composed out of two iterations of 3D noise,
//! or four iterations of 2D noise.

use std::num::{cast, Float};

use {gradient, math, Seed};

struct SimplecticPoint2<T: Float> {
    cell: math::Point2<i64>,
    offset: math::Vector2<T>,
}

impl<T: Float> SimplecticPoint2<T> {
    fn to_simplectic_point3(&self, z_cell: i64, z_offset: T) -> SimplecticPoint3<T> {
        SimplecticPoint3 {
            cell: [self.cell[0], self.cell[1], z_cell],
            offset: [self.offset[0], self.offset[1], z_offset],
        }
    }
}

struct SimplecticPoint3<T: Float> {
    cell: math::Point3<i64>,
    offset: math::Vector3<T>,
}

impl<T: Float> SimplecticPoint3<T> {
    fn to_simplectic_point4(&self, w_cell: i64, w_offset: T) -> SimplecticPoint4<T> {
        SimplecticPoint4 {
            cell: [self.cell[0], self.cell[1], self.cell[2], w_cell],
            offset: [self.offset[0], self.offset[1], self.offset[2], w_offset],
        }
    }
}

struct SimplecticPoint4<T: Float> {
    cell: math::Point4<i64>,
    offset: math::Vector4<T>,
}

fn skew_constant<T: Float>() -> T { math::cast(0.36602540378_f64) } // 0.5 * (sqrt(3.0) - 1.0)
fn unskew_constant<T: Float>() -> T { math::cast(0.2113248654_f64) } // (3.0 - sqrt(3.0)) / 6.0

fn simplex_size<T: Float>() -> T { math::cast(0.70710678119_f64) }
fn inv_simplex_size<T: Float>() -> T { math::cast(1.41421356235_f64) } // 1 / simplex_size()
fn layer_offset_x<T: Float>() -> T { math::cast(0.45534180126_f64) } // (2.0 - 3.0 * unskew_constant()) / 3.0
fn layer_offset_y<T: Float>() -> T { math::cast(0.12200846793_f64) } // (1.0 - 3.0 * unskew_constant()) / 3.0
fn layer_offset_z<T: Float>() -> T { math::cast(0.35355339059_f64) } // (1.0 - 3.0 * unskew_constant()) / 3.0

fn norm2_constant<T: Float>() -> T { math::cast(8.0_f64) }
fn norm3_constant<T: Float>() -> T { math::cast(9.0_f64) }
fn norm4_constant<T: Float>() -> T { math::cast(10.0_f64) }

#[inline(always)]
fn simplectic2_points<T: Float>(point: &math::Point2<T>) -> [SimplecticPoint2<T>; 3] {
    let zero: T = math::cast(0u);
    let one: T = math::cast(1u);
    let two: T = math::cast(2u);

    // Skew the input coordinates into the grid to figure out which grid cell we're in
    let skew_offset = (point[0] + point[1]) * skew_constant();
    let x_cell = (point[0] + skew_offset).floor();
    let y_cell = (point[1] + skew_offset).floor();

    // Unskew the floored coordinates to find the real coordinates of the cell's origin
    let unskew_offset = (x_cell + y_cell) * unskew_constant();
    let x_origin = x_cell - unskew_offset;
    let y_origin = y_cell - unskew_offset;

    // Compute the delta from the first point, which is the cell origin
    let dx0 = point[0] - x_origin;
    let dy0 = point[1] - y_origin;

    // Compute the delta from the second point, which depends on which simplex we're in
    let (x1_offset, y1_offset) = if dx0 > dy0 { (one, zero) } else { (zero, one) };
    let dx1 = dx0 - x1_offset + unskew_constant();
    let dy1 = dy0 - y1_offset + unskew_constant();

    // Compute the delta from the third point
    let dx2 = dx0 - one + two * unskew_constant();
    let dy2 = dy0 - one + two * unskew_constant();

    [
        SimplecticPoint2 {
            cell: [math::cast(x_cell), math::cast(y_cell)],
            offset: [dx0, dy0],
        },
        SimplecticPoint2 {
            cell: [math::cast(x_cell + x1_offset), math::cast(y_cell + y1_offset)],
            offset: [dx1, dy1],
        },
        SimplecticPoint2 {
            cell: [1i64 + math::cast(x_cell), 1i64 + math::cast(y_cell)],
            offset: [dx2, dy2],
        },
    ]
}

#[inline(always)]
fn simplectic3_points<T: Float>(point: &math::Point3<T>) -> [SimplecticPoint3<T>; 6] {
    let layer = (point[2] * inv_simplex_size()).floor();
    let layer_int: i64 = math::cast(layer);

    let point2 = [point[0], point[1]];
    let offset_point2 = [point[0] + layer_offset_x(),
                         point[1] + layer_offset_y()];

    let (layer1_point, layer2_point) = match layer_int % 2 {
        0 => (point2, offset_point2),
        _ => (offset_point2, point2),
    };

    let [p1, p2, p3] = simplectic2_points(&layer1_point);
    let [p4, p5, p6] = simplectic2_points(&layer2_point);

    let z_offset = point[2] - layer * simplex_size();
    [
        p1.to_simplectic_point3(layer_int, z_offset),
        p2.to_simplectic_point3(layer_int, z_offset),
        p3.to_simplectic_point3(layer_int, z_offset),
        p4.to_simplectic_point3(layer_int + 1, z_offset - simplex_size()),
        p5.to_simplectic_point3(layer_int + 1, z_offset - simplex_size()),
        p6.to_simplectic_point3(layer_int + 1, z_offset - simplex_size()),
    ]
}

#[inline(always)]
fn simplectic4_points<T: Float>(point: &math::Point4<T>) -> [SimplecticPoint4<T>; 12] {
    let layer = (point[3] * inv_simplex_size()).floor();
    let layer_int: i64 = math::cast(layer);

    let point3 = [point[0], point[1], point[2]];
    let offset_point3 = [point[0] + layer_offset_x(),
                         point[1] + layer_offset_y(),
                         point[2] + layer_offset_z()];

    let (layer1_point, layer2_point) = match layer_int % 2 {
        0 => (point3, offset_point3),
        _ => (offset_point3, point3),
    };

    let [p1, p2, p3, p4, p5, p6] = simplectic3_points(&layer1_point);
    let [p7, p8, p9, p10, p11, p12] = simplectic3_points(&layer2_point);

    let w_offset = point[3] - layer * simplex_size();
    [
        p1.to_simplectic_point4(layer_int, w_offset),
        p2.to_simplectic_point4(layer_int, w_offset),
        p3.to_simplectic_point4(layer_int, w_offset),
        p4.to_simplectic_point4(layer_int, w_offset),
        p5.to_simplectic_point4(layer_int, w_offset),
        p6.to_simplectic_point4(layer_int, w_offset),
        p7.to_simplectic_point4(layer_int + 1, w_offset - simplex_size()),
        p8.to_simplectic_point4(layer_int + 1, w_offset - simplex_size()),
        p9.to_simplectic_point4(layer_int + 1, w_offset - simplex_size()),
        p10.to_simplectic_point4(layer_int + 1, w_offset - simplex_size()),
        p11.to_simplectic_point4(layer_int + 1, w_offset - simplex_size()),
        p12.to_simplectic_point4(layer_int + 1, w_offset - simplex_size()),
    ]
}

pub fn simplectic2<T: Float>(seed: &Seed, point: &math::Point2<T>) -> T {
    #[inline(always)]
    fn gradient<T: Float>(seed: &Seed, p: &SimplecticPoint2<T>) -> T {
        let attn = simplex_size::<T>() - p.offset[0] * p.offset[0]
                                       - p.offset[1] * p.offset[1];
        if attn > Float::zero() {
            math::pow4(attn) * math::dot2(p.offset, gradient::get2(seed.get2(p.cell)))
        } else {
            Float::zero()
        }
    }

    let [p1, p2, p3] = simplectic2_points(point);

    (gradient(seed, &p1) + gradient(seed, &p2) + gradient(seed, &p3)) * norm2_constant()
}

pub fn simplectic3<T: Float>(seed: &Seed, point: &math::Point3<T>) -> T {
    #[inline(always)]
    fn gradient<T: Float>(seed: &Seed, p: &SimplecticPoint3<T>) -> T {
        let attn = simplex_size::<T>() - p.offset[0] * p.offset[0]
                                       - p.offset[1] * p.offset[1]
                                       - p.offset[2] * p.offset[2];
        if attn > Float::zero() {
            math::pow4(attn) * math::dot3(p.offset, gradient::get3(seed.get3(p.cell)))
        } else {
            Float::zero()
        }
    }

    let [p1, p2, p3, p4, p5, p6] = simplectic3_points(point);

    (
        gradient(seed, &p1) + gradient(seed, &p2) + gradient(seed, &p3) + gradient(seed, &p4) + gradient(seed, &p5) + gradient(seed, &p6)
    ) * norm3_constant()
}

pub fn simplectic4<T: Float>(seed: &Seed, point: &math::Point4<T>) -> T {
    #[inline(always)]
    fn gradient<T: Float>(seed: &Seed, p: &SimplecticPoint4<T>) -> T {
        let attn = simplex_size::<T>() - p.offset[0] * p.offset[0]
                                       - p.offset[1] * p.offset[1]
                                       - p.offset[2] * p.offset[2]
                                       - p.offset[3] * p.offset[3];
        if attn > Float::zero() {
            math::pow4(attn) * math::dot4(p.offset, gradient::get4(seed.get4(p.cell)))
        } else {
            Float::zero()
        }
    }

    let [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12] = simplectic4_points(point);

    (
        gradient(seed, &p1) + gradient(seed, &p2) + gradient(seed, &p3) + gradient(seed, &p4) + gradient(seed, &p5) + gradient(seed, &p6) +
        gradient(seed, &p7) + gradient(seed, &p8) + gradient(seed, &p9) + gradient(seed, &p10) + gradient(seed, &p11) + gradient(seed, &p12)
    ) * norm4_constant()
}

mod tests {
    #[test]
    fn test_simplectic2() {
        let _ = ::simplectic2(&::Seed::new(0), &[37.0, 24.0]);
    }

    #[test]
    fn test_simplectic3() {
        let _ = ::simplectic3(&::Seed::new(0), &[37.0, 24.0, 42.0]);
    }

    #[test]
    fn test_simplectic4() {
        let _ = ::simplectic4(&::Seed::new(0), &[37.0, 24.0, 42.0, 128.0]);
    }
}
<|endoftext|>