extern crate num;
use self::num::traits::{ToPrimitive};
use super::Border;
pub type FlatProbability = u16;
pub type WideProbability = i16;
const BIN_WEIGHT_BITS: usize = 8;
const BIN_WEIGHT_TOTAL: usize = 1<<BIN_WEIGHT_BITS;
const FLAT_BITS: FlatProbability = 12;
const FLAT_TOTAL: isize = 1<<(FLAT_BITS as usize);
const WIDE_BITS: usize = 12;
const WIDE_OFFSET: WideProbability = 1<<(WIDE_BITS-1);
const PORTAL_OFFSET: usize = 1<<(WIDE_BITS-BIN_WEIGHT_BITS-1);
const PORTAL_BINS: usize = 2*PORTAL_OFFSET + 1;
#[derive(Copy, Clone)]
pub struct Bit(FlatProbability);
impl Bit {
#[inline]
pub fn new_equal() -> Bit {
Bit(FLAT_TOTAL as FlatProbability >> 1)
}
#[inline]
pub fn to_flat(&self) -> FlatProbability {
let Bit(fp) = *self;
fp
}
#[inline]
pub fn to_wide(&self) -> WideProbability {
let p = (self.to_flat() as f32) / (FLAT_TOTAL as f32);
let d = (p / (1.0-p)).ln();
let wp = (d * WIDE_OFFSET as f32).to_i16().unwrap();
wp
}
#[inline]
pub fn from_flat(fp: FlatProbability) -> Bit {
Bit(fp)
}
#[inline]
pub fn from_wide(wp: WideProbability) -> Bit {
let d = (wp as f32) / (WIDE_OFFSET as f32);
let p = 1.0 / (1.0 + (-d).exp());
let fp = (p * FLAT_TOTAL as f32).to_u16().unwrap();
Bit(fp)
}
pub fn update_zero(&mut self, rate: isize, bias: isize) {
let &mut Bit(ref mut fp) = self;
let one = FLAT_TOTAL - bias - (*fp as isize);
*fp += (one >> (rate as usize)) as FlatProbability;
}
pub fn update_one(&mut self, rate: isize, bias: isize) {
let &mut Bit(ref mut fp) = self;
let zero = (*fp as isize) - bias;
*fp -= (zero >> (rate as usize)) as FlatProbability;
}
#[inline]
pub fn update(&mut self, value: bool, rate: isize, bias: isize) {
if !value {
self.update_zero(rate, bias)
}else {
self.update_one(rate, bias)
}
}
}
impl super::Model<bool> for Bit {
fn get_range(&self, value: bool) -> (Border,Border) {
let fp = self.to_flat() as Border;
if !value {
(0, fp)
}else {
(fp, FLAT_TOTAL as Border)
}
}
fn find_value(&self, offset: Border) -> (bool,Border,Border) {
assert!(offset < FLAT_TOTAL as Border,
"Invalid bit offset {} requested", offset);
let fp = self.to_flat() as Border;
if offset < fp {
(false, 0, fp)
}else {
(true, fp, FLAT_TOTAL as Border)
}
}
fn get_denominator(&self) -> Border {
FLAT_TOTAL as Border
}
}
pub struct Gate {
map: [Bit; PORTAL_BINS],
}
pub type BinCoords = (usize, usize);
impl Gate {
pub fn new() -> Gate {
let mut g = Gate {
map: [Bit::new_equal(); PORTAL_BINS],
};
for (i,bit) in g.map.iter_mut().enumerate() {
let rp = (i as f32)/(PORTAL_OFFSET as f32) - 1.0;
let wp = (rp * (WIDE_OFFSET as f32)).to_i16().unwrap();
*bit = Bit::from_wide(wp);
}
g
}
#[inline]
pub fn pass(&self, bit: &Bit) -> (Bit, BinCoords) {
let (fp, index) = self.pass_wide(bit.to_wide());
(Bit::from_flat(fp), index)
}
pub fn pass_wide(&self, wp: WideProbability) -> (FlatProbability, BinCoords) {
let index = ((wp + WIDE_OFFSET) >> BIN_WEIGHT_BITS) as usize;
let weight = wp as usize & (BIN_WEIGHT_TOTAL-1);
let z = [
self.map[index+0].to_flat() as usize,
self.map[index+1].to_flat() as usize];
let sum = z[0]*(BIN_WEIGHT_TOTAL-weight) + z[1]*weight;
let fp = (sum >> BIN_WEIGHT_BITS) as FlatProbability;
(fp, (index, weight))
}
pub fn update_zero(&mut self, bc: BinCoords, rate: isize, bias: isize) {
let (index, _) = bc;
self.map[index+0].update_zero(rate, bias);
self.map[index+1].update_zero(rate, bias);
}
pub fn update_one(&mut self, bc: BinCoords, rate: isize, bias: isize) {
let (index, _) = bc;
self.map[index+0].update_one(rate, bias);
self.map[index+1].update_one(rate, bias);
}
#[inline]
pub fn update(&mut self, value: bool, bc: BinCoords, rate: isize, bias: isize) {
if !value {
self.update_zero(bc, rate, bias)
}else {
self.update_one(bc, rate, bias)
}
}
}