<commit_before>//! Implements a large hash-table that stores results of previously
//! performed searches ("transposition table").
//!
//! Chess programs, during their brute-force search, encounter the
//! same positions again and again, but from different sequences of
//! moves, which is called a "transposition". When the search
//! encounters a transposition, it is beneficial to "remember" what
//! was determined last time the position was examined, rather than
//! redoing the entire search again. For this reason, chess programs
//! have a transposition table, which is a large hash table storing
//! information about positions previously searched, how deeply they
//! were searched, and what we concluded about them.

use std;
use std::cell::{UnsafeCell, Cell};
use std::mem::transmute;
use basetypes::Value;
use chess_move::MoveDigest;

/// `BOUND_EXACT`, `BOUND_LOWER`, `BOUND_UPPER`, or `BOUND_NONE`.
///
/// For the majority of chess positions our evaluations will be more
/// or less inaccurate, and there is nothing we can do about it. But
/// sometimes we know that a given evaluation is probably inaccurate,
/// and we know the sign of the error. `BoundType` defines the
/// direction of such **known inaccuracies**.
///
/// * `BOUND_EXACT` means that the evaluation is exact (as far as we know).
///
/// * `BOUND_LOWER` means that the real value is greater or equal to
///    the evaluation (as far as we know).
///
/// * `BOUND_UPPER` means that the real value is lesser or equal to
///   the evaluation (as far as we know).
///
/// * `BOUND_NONE` means that the real value might be lesser, equal,
///   or grater than the evaluation.
pub type BoundType = u8;

pub const BOUND_NONE: BoundType = 0;
pub const BOUND_UPPER: BoundType = 0b10;
pub const BOUND_LOWER: BoundType = 0b01;
pub const BOUND_EXACT: BoundType = BOUND_UPPER | BOUND_LOWER;

/// Contains information about a particular position.
#[derive(Copy, Clone)]
pub struct TtEntry {
    move16: MoveDigest,
    value: Value,
    eval_value: Value,
    depth: u8,

    // The transposition table maintains a generation counter for each
    // entry, which is used to implement an efficient replacement
    // strategy. This field stores the entry's generation and the
    // bound type.
    gen_bound: u8,
}

impl TtEntry {
    /// Creates a new instance.
    ///
    /// * `value` -- the value assigned to the position;
    ///
    /// * `bound` -- the accuracy of the assigned `value`;
    ///
    /// * `depth` -- the depth of search;
    ///
    /// * `move16` -- best or refutation move, or `0` if no move is
    ///   available;
    ///
    /// * `eval_value` -- the calculated static evaluation for the
    ///   position.
    pub fn new(value: Value,
               bound: BoundType,
               depth: u8,
               move16: MoveDigest,
               eval_value: Value)
               -> TtEntry {
        assert!(bound <= 0b11);
        assert!(depth < 127);
        TtEntry {
            move16: move16,
            value: value,
            eval_value: eval_value,
            depth: depth,
            gen_bound: bound,
        }
    }

    #[inline(always)]
    pub fn value(&self) -> Value {
        self.value
    }

    #[inline(always)]
    pub fn bound(&self) -> BoundType {
        self.gen_bound & 0b11
    }

    #[inline(always)]
    pub fn depth(&self) -> u8 {
        self.depth
    }

    #[inline(always)]
    pub fn move16(&self) -> MoveDigest {
        self.move16
    }

    #[inline(always)]
    pub fn eval_value(&self) -> Value {
        self.eval_value
    }
}

/// A transposition table.
pub struct Tt {
    generation: Cell<u8>,
    cluster_count: usize,
    table: UnsafeCell<Vec<[Record; 4]>>,
}

impl Tt {
    /// Creates a new transposition table.
    ///
    /// The newly created table has the minimum possible size. Before
    /// using the new table for anything, `resize()` should be called
    /// on it, specifying the desired size.
    pub fn new() -> Tt {
        Tt {
            generation: Cell::new(0),
            cluster_count: 1,
            table: UnsafeCell::new(vec![Default::default()]),
        }
    }

    /// Resizes the transpositon table. All entries in the table will
    /// be lost.
    ///
    /// `size_mb` is the desired new size in Mbytes. If `size_mb` is
    /// not in the form "2**n", the new size of the transposition
    /// table will be as close as possible, but less than `size_mb`.
    pub fn resize(&mut self, size_mb: usize) {
        let requested_cluster_count = (size_mb * 1024 * 1024) / std::mem::size_of::<[Record; 4]>();

        // First, make sure `requested_cluster_count` is exceeded.
        let mut new_cluster_count = 1;
        while requested_cluster_count >= new_cluster_count {
            new_cluster_count <<= 1;
        }

        // Then make one step back, being careful so that the new
        // cluster count is not zero.
        if new_cluster_count > 1 {
            new_cluster_count >>= 1;
        } else {
            new_cluster_count = 1;
        }

        // Finally, reallocate the vector of clusters.
        if new_cluster_count != self.cluster_count {
            self.cluster_count = new_cluster_count;
            self.table = UnsafeCell::new(vec![Default::default(); new_cluster_count]);
        }
    }

    /// Returns the size of the transposition table in Mbytes.
    pub fn size(&self) -> usize {
        unsafe { &*self.table.get() }.len() * std::mem::size_of::<[Record; 4]>() / 1024 / 1024
    }

    /// Signals that a new search is about to begin.
    pub fn new_search(&self) {
        // Note: The lowest 2 bits of the `generation` field are used
        // for the bound type.
        self.generation.set(self.generation.get().wrapping_add(0b100));
        assert_eq!(self.generation.get() & 0b11, 0);
    }

    /// Stores data by a specific key.
    ///
    /// After being stored, the data might be retrieved by
    /// `probe(key)`. This is not guaranteed though, because the entry
    /// might have been overwritten in the meantime.
    pub fn store(&self, key: u64, mut data: TtEntry) {
        // `store` and `probe` jointly implement a clever lock-less
        // hashing strategy. Rather than storing two disjoint items,
        // the key is stored XOR-ed with data, while data is stored
        // additionally as usual.

        // Set the entry's generation.
        data.gen_bound |= self.generation.get();

        // Choose a slot to which to write the data. (Each cluster has
        // 4 slots.)
        let mut cluster = unsafe { self.cluster_mut(key) };
        let mut replace_index = 0;
        let mut replace_score = 0xff;
        for (i, record) in cluster.iter_mut().enumerate() {
            // Check if this is an empty slot, or an old record for
            // the same key. If this this is the case we will use this
            // slot for the new record.
            if record.key == 0 || record.key ^ record.data_u64() == key {
                if data.move16 == 0 {
                    data.move16 = record.data.move16; // Preserve any existing move.
                }
                replace_index = i;
                break;
            }

            // Calculate the score for this record. If we can not find
            // an empty/old slot, the replaced record will be the
            // record with the lowest score.
            let record_score = self.calc_score(record);
            if record_score < replace_score {
                replace_index = i;
                replace_score = record_score;
            }
        }

        // Write the data to the chosen slot.
        unsafe {
            cluster.get_unchecked_mut(replace_index).key = key ^ transmute::<TtEntry, u64>(data);
            cluster.get_unchecked_mut(replace_index).data = data;
        }
    }

    /// Probes for data by a specific key.
    ///
    /// **Note:** This method may write to the transposition table
    /// (for example, to update the generation of the entry).
    #[inline]
    pub fn probe(&self, key: u64) -> Option<TtEntry> {
        let cluster = unsafe { self.cluster_mut(key) };
        for record in cluster.iter_mut() {
            if record.key ^ record.data_u64() == key {
                // If `key` and `data` were written simultaneously by
                // different search instances with different keys,
                // this will yield in a mismatch of the above
                // comparison (except for the rare and inherent key
                // collisions).
                record.update_generation(self.generation.get());
                return Some(record.data);
            }
        }
        None
    }

    /// Peeks for data by a specific key.
    ///
    /// This method does the same as `probe`, except it will never
    /// write to the transposition table. This is useful, for example,
    /// when we want to extract the primary variation from the the
    /// transposition table, without affecting any entries in the
    /// table.
    #[inline]
    pub fn peek(&self, key: u64) -> Option<TtEntry> {
        let cluster = unsafe { self.cluster_mut(key) };
        for record in cluster.iter_mut() {
            if record.key ^ record.data_u64() == key {
                return Some(record.data);
            }
        }
        None
    }

    /// Removes all entries in the table.
    pub fn clear(&self) {
        let table = unsafe { self.table.get().as_mut().unwrap() };
        for cluster in table {
            for record in cluster.iter_mut() {
                *record = Default::default();
            }
        }
        self.generation.set(0);
    }

    // A helper method for `store`. It implements our replacement
    // strategy. It returns higher values for the records that are
    // move likely to save CPU work in the future.
    #[inline(always)]
    fn calc_score(&self, record: &Record) -> u8 {
        // Positions from the current generation are always scored
        // higher than positions from older generations.
        (if record.generation() == self.generation.get() {
            128
        } else {
            0
        })

        // Positions with higher search depth are scored higher.
        + record.data.depth()

        // Positions with exact evaluation are given slight advantage.
        + (if record.data.bound() == BOUND_EXACT {
            1
        } else {
            0
        })
    }

    // A helper method for `probe` and `store`. It returns the cluster
    // for a given key. (Each cluster can store up to 4 records.)
    #[inline]
    unsafe fn cluster_mut(&self, key: u64) -> &mut [Record; 4] {
        let cluster_index = (key & (self.cluster_count - 1) as u64) as usize;
        self.table.get().as_mut().unwrap().get_unchecked_mut(cluster_index)
    }
}

unsafe impl Sync for Tt {}

/// Represents a record in the transposition table.
///
/// It consists of 16 bytes, and is laid out the following way:
///
/// * key        64 bit
/// * move16     16 bit
/// * value      16 bit
/// * eval value 16 bit
/// * depth       8 bit
/// * generation  6 bit
/// * bound type  2 bit
#[derive(Copy, Clone)]
struct Record {
    key: u64,
    data: TtEntry,
}

impl Default for Record {
    fn default() -> Record {
        Record {
            key: 0,
            data: unsafe { transmute(0u64) },
        }
    }
}

impl Record {
    /// Returns the contained data as one `u64` value.
    #[inline(always)]
    fn data_u64(&self) -> u64 {
        unsafe { transmute(self.data) }
    }

    /// Returns record's generation.
    #[inline(always)]
    fn generation(&self) -> u8 {
        self.data.gen_bound & 0b11111100
    }

    /// Updates record's generation.
    #[inline(always)]
    fn update_generation(&mut self, generation: u8) {
        assert_eq!(generation & 0b11, 0);

        // Since the `key` is saved XOR-ed with the data, when we
        // change the data, we have to change the stored `key` as
        // well.
        let old_data_u64 = self.data_u64();
        self.data.gen_bound = generation | self.data.bound();
        self.key ^= old_data_u64 ^ self.data_u64();
    }
}

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

    #[test]
    fn test_cluster_size() {
        assert_eq!(std::mem::size_of::<[Record; 4]>(), 64);
        assert_eq!(std::mem::size_of::<Record>(), 16);
    }

    #[test]
    fn test_tt_resize() {
        let mut tt = Tt::new();
        assert_eq!(unsafe { &*tt.table.get() }.capacity(), 1);
        tt.resize(1);
        assert_eq!(tt.size(), 1);
        tt.clear();
    }

    #[test]
    fn test_store_and_probe() {
        let tt = Tt::new();
        assert!(tt.probe(1).is_none());
        let data = TtEntry::new(0, 0, 100, 666, 0);
        assert_eq!(data.depth(), 100);
        assert_eq!(data.move16(), 666);
        tt.store(1, data);
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        tt.store(1, TtEntry::new(0, 0, 100, 666, 0));
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        assert_eq!(tt.probe(1).unwrap().move16(), 666);
        for i in 2..100 {
            tt.store(i, TtEntry::new(i as i16, 0, i as u8, i as u16, i as i16));
        }
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        assert_eq!(tt.probe(99).unwrap().depth(), 99);
        assert_eq!(tt.probe(98).unwrap().depth(), 98);
        assert_eq!(tt.probe(97).unwrap().depth(), 97);
        tt.clear();
        assert!(tt.probe(1).is_none());
        tt.store(1, data);
        tt.new_search();
        tt.probe(1);
        assert!(tt.probe(1).is_some());
    }

    #[test]
    fn test_new_search() {
        let tt = Tt::new();
        assert_eq!(tt.generation.get(), 0 << 2);
        tt.new_search();
        assert_eq!(tt.generation.get(), 1 << 2);
        for _ in 0..64 {
            tt.new_search();
        }
        assert_eq!(tt.generation.get(), 1 << 2);
    }
}
<commit_msg>empty line<commit_after>//! Implements a large hash-table that stores results of previously
//! performed searches ("transposition table").
//!
//! Chess programs, during their brute-force search, encounter the
//! same positions again and again, but from different sequences of
//! moves, which is called a "transposition". When the search
//! encounters a transposition, it is beneficial to "remember" what
//! was determined last time the position was examined, rather than
//! redoing the entire search again. For this reason, chess programs
//! have a transposition table, which is a large hash table storing
//! information about positions previously searched, how deeply they
//! were searched, and what we concluded about them.

use std;
use std::cell::{UnsafeCell, Cell};
use std::mem::transmute;
use basetypes::Value;
use chess_move::MoveDigest;

/// `BOUND_EXACT`, `BOUND_LOWER`, `BOUND_UPPER`, or `BOUND_NONE`.
///
/// For the majority of chess positions our evaluations will be more
/// or less inaccurate, and there is nothing we can do about it. But
/// sometimes we know that a given evaluation is probably inaccurate,
/// and we know the sign of the error. `BoundType` defines the
/// direction of such **known inaccuracies**.
///
/// * `BOUND_EXACT` means that the evaluation is exact (as far as we know).
///
/// * `BOUND_LOWER` means that the real value is greater or equal to
///    the evaluation (as far as we know).
///
/// * `BOUND_UPPER` means that the real value is lesser or equal to
///   the evaluation (as far as we know).
///
/// * `BOUND_NONE` means that the real value might be lesser, equal,
///   or grater than the evaluation.
pub type BoundType = u8;

pub const BOUND_NONE: BoundType = 0;
pub const BOUND_UPPER: BoundType = 0b10;
pub const BOUND_LOWER: BoundType = 0b01;
pub const BOUND_EXACT: BoundType = BOUND_UPPER | BOUND_LOWER;

/// Contains information about a particular position.
#[derive(Copy, Clone)]
pub struct TtEntry {
    move16: MoveDigest,
    value: Value,
    eval_value: Value,
    depth: u8,

    // The transposition table maintains a generation counter for each
    // entry, which is used to implement an efficient replacement
    // strategy. This field stores the entry's generation and the
    // bound type.
    gen_bound: u8,
}

impl TtEntry {
    /// Creates a new instance.
    ///
    /// * `value` -- the value assigned to the position;
    ///
    /// * `bound` -- the accuracy of the assigned `value`;
    ///
    /// * `depth` -- the depth of search;
    ///
    /// * `move16` -- best or refutation move, or `0` if no move is
    ///   available;
    ///
    /// * `eval_value` -- the calculated static evaluation for the
    ///   position.
    pub fn new(value: Value,
               bound: BoundType,
               depth: u8,
               move16: MoveDigest,
               eval_value: Value)
               -> TtEntry {
        assert!(bound <= 0b11);
        assert!(depth < 127);
        TtEntry {
            move16: move16,
            value: value,
            eval_value: eval_value,
            depth: depth,
            gen_bound: bound,
        }
    }

    #[inline(always)]
    pub fn value(&self) -> Value {
        self.value
    }

    #[inline(always)]
    pub fn bound(&self) -> BoundType {
        self.gen_bound & 0b11
    }

    #[inline(always)]
    pub fn depth(&self) -> u8 {
        self.depth
    }

    #[inline(always)]
    pub fn move16(&self) -> MoveDigest {
        self.move16
    }

    #[inline(always)]
    pub fn eval_value(&self) -> Value {
        self.eval_value
    }
}

/// A transposition table.
pub struct Tt {
    generation: Cell<u8>,
    cluster_count: usize,
    table: UnsafeCell<Vec<[Record; 4]>>,
}

impl Tt {
    /// Creates a new transposition table.
    ///
    /// The newly created table has the minimum possible size. Before
    /// using the new table for anything, `resize()` should be called
    /// on it, specifying the desired size.
    pub fn new() -> Tt {
        Tt {
            generation: Cell::new(0),
            cluster_count: 1,
            table: UnsafeCell::new(vec![Default::default()]),
        }
    }

    /// Resizes the transpositon table. All entries in the table will
    /// be lost.
    ///
    /// `size_mb` is the desired new size in Mbytes. If `size_mb` is
    /// not in the form "2**n", the new size of the transposition
    /// table will be as close as possible, but less than `size_mb`.
    pub fn resize(&mut self, size_mb: usize) {
        let requested_cluster_count = (size_mb * 1024 * 1024) / std::mem::size_of::<[Record; 4]>();

        // First, make sure `requested_cluster_count` is exceeded.
        let mut new_cluster_count = 1;
        while requested_cluster_count >= new_cluster_count {
            new_cluster_count <<= 1;
        }

        // Then make one step back, being careful so that the new
        // cluster count is not zero.
        if new_cluster_count > 1 {
            new_cluster_count >>= 1;
        } else {
            new_cluster_count = 1;
        }

        // Finally, reallocate the vector of clusters.
        if new_cluster_count != self.cluster_count {
            self.cluster_count = new_cluster_count;
            self.table = UnsafeCell::new(vec![Default::default(); new_cluster_count]);
        }
    }

    /// Returns the size of the transposition table in Mbytes.
    pub fn size(&self) -> usize {
        unsafe { &*self.table.get() }.len() * std::mem::size_of::<[Record; 4]>() / 1024 / 1024
    }

    /// Signals that a new search is about to begin.
    pub fn new_search(&self) {
        // Note: The lowest 2 bits of the `generation` field are used
        // for the bound type.
        self.generation.set(self.generation.get().wrapping_add(0b100));
        assert_eq!(self.generation.get() & 0b11, 0);
    }

    /// Stores data by a specific key.
    ///
    /// After being stored, the data might be retrieved by
    /// `probe(key)`. This is not guaranteed though, because the entry
    /// might have been overwritten in the meantime.
    pub fn store(&self, key: u64, mut data: TtEntry) {
        // `store` and `probe` jointly implement a clever lock-less
        // hashing strategy. Rather than storing two disjoint items,
        // the key is stored XOR-ed with data, while data is stored
        // additionally as usual.

        // Set the entry's generation.
        data.gen_bound |= self.generation.get();

        // Choose a slot to which to write the data. (Each cluster has
        // 4 slots.)
        let mut cluster = unsafe { self.cluster_mut(key) };
        let mut replace_index = 0;
        let mut replace_score = 0xff;
        for (i, record) in cluster.iter_mut().enumerate() {
            // Check if this is an empty slot, or an old record for
            // the same key. If this this is the case we will use this
            // slot for the new record.
            if record.key == 0 || record.key ^ record.data_u64() == key {
                if data.move16 == 0 {
                    data.move16 = record.data.move16; // Preserve any existing move.
                }
                replace_index = i;
                break;
            }

            // Calculate the score for this record. If we can not find
            // an empty/old slot, the replaced record will be the
            // record with the lowest score.
            let record_score = self.calc_score(record);
            if record_score < replace_score {
                replace_index = i;
                replace_score = record_score;
            }
        }

        // Write the data to the chosen slot.
        unsafe {
            cluster.get_unchecked_mut(replace_index).key = key ^ transmute::<TtEntry, u64>(data);
            cluster.get_unchecked_mut(replace_index).data = data;
        }
    }

    /// Probes for data by a specific key.
    ///
    /// **Note:** This method may write to the transposition table
    /// (for example, to update the generation of the entry).
    #[inline]
    pub fn probe(&self, key: u64) -> Option<TtEntry> {
        let cluster = unsafe { self.cluster_mut(key) };
        for record in cluster.iter_mut() {
            if record.key ^ record.data_u64() == key {
                // If `key` and `data` were written simultaneously by
                // different search instances with different keys,
                // this will yield in a mismatch of the above
                // comparison (except for the rare and inherent key
                // collisions).
                record.update_generation(self.generation.get());
                return Some(record.data);
            }
        }
        None
    }

    /// Peeks for data by a specific key.
    ///
    /// This method does the same as `probe`, except it will never
    /// write to the transposition table. This is useful, for example,
    /// when we want to extract the primary variation from the the
    /// transposition table, without affecting any entries in the
    /// table.
    #[inline]
    pub fn peek(&self, key: u64) -> Option<TtEntry> {
        let cluster = unsafe { self.cluster_mut(key) };
        for record in cluster.iter_mut() {
            if record.key ^ record.data_u64() == key {
                return Some(record.data);
            }
        }
        None
    }

    /// Removes all entries in the table.
    pub fn clear(&self) {
        let table = unsafe { self.table.get().as_mut().unwrap() };
        for cluster in table {
            for record in cluster.iter_mut() {
                *record = Default::default();
            }
        }
        self.generation.set(0);
    }

    // A helper method for `store`. It implements our replacement
    // strategy. It returns higher values for the records that are
    // move likely to save CPU work in the future.
    #[inline(always)]
    fn calc_score(&self, record: &Record) -> u8 {
        // Positions from the current generation are always scored
        // higher than positions from older generations.
        (if record.generation() == self.generation.get() {
            128
        } else {
            0
        })

        // Positions with higher search depth are scored higher.
        + record.data.depth()

        // Positions with exact evaluation are given slight advantage.
        + (if record.data.bound() == BOUND_EXACT {
            1
        } else {
            0
        })
    }

    // A helper method for `probe` and `store`. It returns the cluster
    // for a given key. (Each cluster can store up to 4 records.)
    #[inline]
    unsafe fn cluster_mut(&self, key: u64) -> &mut [Record; 4] {
        let cluster_index = (key & (self.cluster_count - 1) as u64) as usize;
        self.table.get().as_mut().unwrap().get_unchecked_mut(cluster_index)
    }
}

unsafe impl Sync for Tt {}

/// Represents a record in the transposition table.
///
/// It consists of 16 bytes, and is laid out the following way:
///
/// * key        64 bit
/// * move16     16 bit
/// * value      16 bit
/// * eval value 16 bit
/// * depth       8 bit
/// * generation  6 bit
/// * bound type  2 bit
#[derive(Copy, Clone)]
struct Record {
    key: u64,
    data: TtEntry,
}

impl Default for Record {
    fn default() -> Record {
        Record {
            key: 0,
            data: unsafe { transmute(0u64) },
        }
    }
}

impl Record {
    /// Returns the contained data as one `u64` value.
    #[inline(always)]
    fn data_u64(&self) -> u64 {
        unsafe { transmute(self.data) }
    }

    /// Returns record's generation.
    #[inline(always)]
    fn generation(&self) -> u8 {
        self.data.gen_bound & 0b11111100
    }

    /// Updates record's generation.
    #[inline(always)]
    fn update_generation(&mut self, generation: u8) {
        assert_eq!(generation & 0b11, 0);

        // Since the `key` is saved XOR-ed with the data, when we
        // change the data, we have to change the stored `key` as
        // well.
        let old_data_u64 = self.data_u64();
        self.data.gen_bound = generation | self.data.bound();
        self.key ^= old_data_u64 ^ self.data_u64();
    }
}

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

    #[test]
    fn test_cluster_size() {
        assert_eq!(std::mem::size_of::<[Record; 4]>(), 64);
        assert_eq!(std::mem::size_of::<Record>(), 16);
    }

    #[test]
    fn test_tt_resize() {
        let mut tt = Tt::new();
        assert_eq!(unsafe { &*tt.table.get() }.capacity(), 1);
        tt.resize(1);
        assert_eq!(tt.size(), 1);
        tt.clear();
    }

    #[test]
    fn test_store_and_probe() {
        let tt = Tt::new();
        assert!(tt.probe(1).is_none());
        let data = TtEntry::new(0, 0, 100, 666, 0);
        assert_eq!(data.depth(), 100);
        assert_eq!(data.move16(), 666);
        tt.store(1, data);
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        tt.store(1, TtEntry::new(0, 0, 100, 666, 0));
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        assert_eq!(tt.probe(1).unwrap().move16(), 666);
        for i in 2..100 {
            tt.store(i, TtEntry::new(i as i16, 0, i as u8, i as u16, i as i16));
        }
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        assert_eq!(tt.probe(99).unwrap().depth(), 99);
        assert_eq!(tt.probe(98).unwrap().depth(), 98);
        assert_eq!(tt.probe(97).unwrap().depth(), 97);
        tt.clear();
        assert!(tt.probe(1).is_none());
        tt.store(1, data);
        tt.new_search();
        tt.probe(1);
        assert!(tt.probe(1).is_some());
    }

    #[test]
    fn test_new_search() {
        let tt = Tt::new();
        assert_eq!(tt.generation.get(), 0 << 2);
        tt.new_search();
        assert_eq!(tt.generation.get(), 1 << 2);
        for _ in 0..64 {
            tt.new_search();
        }
        assert_eq!(tt.generation.get(), 1 << 2);
    }
}
<|endoftext|>


<commit_before>//! Implements a database that stores results of previously performed
//! searches.
//!
//! Using such a database (called "transposition table") is a way to
//! greatly reduce the search space of a chess tree with little
//! negative impact. Chess programs, during their brute-force search,
//! encounter the same positions again and again, but from different
//! sequences of moves, which is called a transposition.
//!
//! When the search encounters a transposition, it is beneficial to
//! "remember" what was determined last time the position was
//! examined, rather than redoing the entire search again. For this
//! reason, chess programs have a transposition table, which is a
//! large hash table storing information about positions previously
//! searched, how deeply they were searched, and what we concluded
//! about them.

use std;
use std::cell::{UnsafeCell, Cell};
use std::mem::transmute;
use basetypes::Value;

/// `BOUND_EXACT`, `BOUND_LOWER`, `BOUND_UPPER`, or `BOUND_NONE`.
///
/// * `BOUND_EXACT` means that the evaluation is exact.
///
/// * `BOUND_LOWER` means that the real value is greater or equal to
///    the evaluation.
///
/// * `BOUND_UPPER` means that the real value is lesser or equal to
///   the evaluation.
///
/// * `BOUND_NONE` means that the real value might be lesser, equal,
///   or grater than the evaluation.
pub type BoundType = u8;

/// The evaluation is not bounded.
pub const BOUND_NONE: BoundType = 0;

/// The evaluation is an upper bound.
pub const BOUND_UPPER: BoundType = 0b10;

/// The evaluation is a lower bound.
pub const BOUND_LOWER: BoundType = 0b01;

/// The evaluation is exact.
pub const BOUND_EXACT: BoundType = BOUND_UPPER | BOUND_LOWER;

/// Stores information about a particular position.
#[derive(Copy, Clone)]
pub struct EntryData {
    move16: u16,
    value: i16,
    eval_value: i16,
    gen_bound: u8,
    depth: u8,
}

impl EntryData {
    /// Creates a new instance.
    ///
    /// * `value` -- the value assigned to the position,
    ///
    /// * `bound` -- the meaning of the assigned value,
    ///
    /// * `depth` -- the depth of search,
    ///
    /// * `move16` -- best or refutation move (`0` if no move is
    ///   available).
    ///
    ///   These are the least significant 16 bits of the corresponding
    ///   `Move`. They contain the whole information about the played
    ///   move itself.  The only missing information is the move
    ///   ordering information and the information stored so as to be
    ///   able undo the move.
    ///
    /// * `eval_value` -- the calculated static evaluation for the
    ///   position.
    pub fn new(value: Value,
               bound: BoundType,
               depth: u8,
               move16: u16,
               eval_value: Value)
               -> EntryData {
        assert!(bound <= 0b11);
        assert!(depth < 128);
        EntryData {
            move16: move16,
            value: value,
            eval_value: eval_value,
            gen_bound: bound, // Stores the entry's generation and the bound.
            depth: depth,
        }
    }

    #[inline(always)]
    pub fn move16(&self) -> u16 {
        self.move16
    }

    #[inline(always)]
    pub fn value(&self) -> Value {
        self.value
    }

    #[inline(always)]
    pub fn eval_value(&self) -> Value {
        self.eval_value
    }

    #[inline(always)]
    pub fn bound(&self) -> BoundType {
        self.gen_bound & 0b11
    }

    #[inline(always)]
    pub fn depth(&self) -> u8 {
        self.depth
    }
}

// Represents transposition table entry.
//
// It is 16 bytes, defined as below:
//
// * key        64 bit
// * move16     16 bit
// * value      16 bit
// * eval value 16 bit
// * generation  6 bit
// * bound type  2 bit
// * depth       8 bit
#[derive(Copy, Clone)]
struct Entry {
    key: u64,
    data: EntryData,
}

impl Default for Entry {
    fn default() -> Entry {
        Entry {
            key: 0,
            data: unsafe { transmute(0u64) },
        }
    }
}

impl Entry {
    // Returns the whole contained data as one `u64` value.
    //
    // This is needed for implementing the lock-less probing and
    // storing.
    #[inline(always)]
    fn data_u64(&self) -> u64 {
        unsafe { transmute(self.data) }
    }

    // Returns entry's generation.
    #[inline(always)]
    fn generation(&self) -> u8 {
        self.data.gen_bound & 0b11111100
    }

    // Updates entry's generation.
    //
    // Since the `key` is saved xored with the data, when we change
    // the data, we have to change the stored `key` as well.
    #[inline(always)]
    fn update_generation(&mut self, generation: u8) {
        assert_eq!(generation & 0b11, 0);
        let old_data_u64 = self.data_u64();
        self.data.gen_bound = generation | self.data.bound();
        self.key ^= old_data_u64 ^ self.data_u64();
    }
}

/// A large hash-table that stores results of previously performed
/// searches.
pub struct TranspositionTable {
    generation: Cell<u8>,
    cluster_count: usize,
    table: UnsafeCell<Vec<[Entry; 4]>>,
}

impl TranspositionTable {
    /// Creates a new transposition table.
    ///
    /// The newly created table has the minimum possible size. Before
    /// using the new table for anything, `resize()` should be called
    /// on it, specifying the desired size.
    pub fn new() -> TranspositionTable {
        TranspositionTable {
            generation: Cell::new(0),
            cluster_count: 1,
            table: UnsafeCell::new(vec![Default::default()]),
        }
    }

    /// Resizes the transpositon table.
    ///
    /// `size_mb` is the desired new size in Mbytes. All entries in
    /// the table will be lost.
    pub fn resize(&mut self, size_mb: usize) {
        // The cluster count should be in the form "2**n", so the best
        // we can do is to ensure that the new cluster count will be
        // as close as possible but no greater than the requested one.
        let requested_cluster_count = (size_mb * 1024 * 1024) / std::mem::size_of::<[Entry; 4]>();

        // First, make sure `requested_cluster_count` is exceeded.
        let mut new_cluster_count = 1;
        while requested_cluster_count >= new_cluster_count {
            new_cluster_count <<= 1;
        }

        // Then make one step back, being careful so that the new
        // cluster count is not zero.
        if new_cluster_count > 1 {
            new_cluster_count >>= 1;
        } else {
            new_cluster_count = 1;
        }

        // Finally, reallocate the vector of clusters.
        if new_cluster_count != self.cluster_count {
            self.cluster_count = new_cluster_count;
            self.table = UnsafeCell::new(vec![Default::default(); new_cluster_count]);
        }
    }

    /// Clears the transpositon table.
    ///
    /// All remaining entries in the table will be removed.
    pub fn clear(&mut self) {
        self.table = UnsafeCell::new(vec![Default::default(); self.cluster_count]);
    }

    /// Signals that a new search is about to begin.
    ///
    /// Internally, the transposition table maintains a generation
    /// counter that is used to implement an efficient replacement
    /// strategy. This method increases this counter.
    pub fn new_search(&self) {
        self.generation.set(self.generation.get() + 0b100);  // Lower 2 bits are used by bound type
        assert_eq!(self.generation.get() & 0b11, 0);
    }

    /// Probes for data by a specific key.
    #[inline]
    pub fn probe(&self, key: u64) -> Option<EntryData> {
        let cluster = unsafe { self.cluster_mut(key) };
        for entry in cluster.iter_mut() {
            if entry.key ^ entry.data_u64() == key {
                // If `key` and `data` were written simultaneously by
                // different search instances with different keys,
                // this will yield in a mismatch of the above
                // comparison (except for the rare and inherent key
                // collisions).
                entry.update_generation(self.generation.get());
                return Some(entry.data);
            }
        }
        None
    }

    /// Stores data by a specific key.
    ///
    /// After being stored, the data might be retrieved by
    /// `probe(key)`. This is not guaranteed though, because in the
    /// meantime it might have been overwritten.
    #[inline]
    pub fn store(&self, key: u64, mut data: EntryData) {
        // `store` and `probe` jointly implement a clever lock-less
        // hashing method. Rather than to store two disjoint items,
        // the key is stored xored with data, while data is stored
        // additionally as usual.

        data.gen_bound |= self.generation.get();  // Sets the generation.
        let mut cluster = unsafe { self.cluster_mut(key) };
        let mut replace_index = 0;
        let mut replace_score = 0xff;
        for (i, entry) in cluster.iter_mut().enumerate() {
            // Check if this is an empty slot, or an old entry for the
            // same key. If this this is the case we will use this
            // slot for the new entry.
            if entry.key == 0 || entry.key ^ entry.data_u64() == key {
                if data.move16 == 0 {
                    data.move16 = entry.data.move16;  // Preserve any existing move.
                }
                replace_index = i;
                break;
            }
            // If we can not find empty/old slot, the replaced entry
            // will be the entry with the lowest score.
            let entry_score = self.calc_score(entry);
            if entry_score < replace_score {
                replace_index = i;
                replace_score = entry_score;
            }
        }
        unsafe {
            cluster.get_unchecked_mut(replace_index).key = key ^ transmute::<EntryData, u64>(data);
            cluster.get_unchecked_mut(replace_index).data = data;
        }
    }

    // A helper method for `store`.
    //
    // Implements our replacement strategy. Should return higher
    // values for the entries that are move likely to save CPU work in
    // the future.
    #[inline]
    fn calc_score(&self, entry: &Entry) -> u8 {
        (if entry.generation() == self.generation.get() {
            128
        } else {
            0
        }) + entry.data.depth
    }

    // A helper method for `probe` and `store`.
    #[inline]
    unsafe fn cluster_mut(&self, key: u64) -> &mut [Entry; 4] {
        let cluster_index = (key & (self.cluster_count - 1) as u64) as usize;
        self.table.get().as_mut().unwrap().get_unchecked_mut(cluster_index)
    }
}

unsafe impl Sync for TranspositionTable {}

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

    #[test]
    fn test_cluster_size() {
        assert_eq!(std::mem::size_of::<[Entry; 4]>(), 64);
        assert_eq!(std::mem::size_of::<Entry>(), 16);
    }

    #[test]
    fn test_tt_resize() {
        let mut tt = TranspositionTable::new();
        assert_eq!(unsafe { &*tt.table.get() }.capacity(), 1);
        tt.resize(1);
        assert_eq!(unsafe { &*tt.table.get() }.capacity(),
                   1024 * 1024 / std::mem::size_of::<[Entry; 4]>());
        tt.clear();
    }

    #[test]
    fn test_store_and_probe() {
        let mut tt = TranspositionTable::new();
        assert!(tt.probe(1).is_none());
        let data = EntryData::new(0, 0, 100, 666, 0);
        assert_eq!(data.depth(), 100);
        assert_eq!(data.move16(), 666);
        tt.store(1, data);
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        tt.store(1, EntryData::new(0, 0, 100, 666, 0));
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        assert_eq!(tt.probe(1).unwrap().move16(), 666);
        for i in 2..100 {
            tt.store(i, EntryData::new(i as i16, 0, i as u8, i as u16, i as i16));
        }
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        assert_eq!(tt.probe(99).unwrap().depth(), 99);
        assert_eq!(tt.probe(98).unwrap().depth(), 98);
        assert_eq!(tt.probe(97).unwrap().depth(), 97);
        tt.clear();
        assert!(tt.probe(1).is_none());
        tt.store(1, data);
        tt.new_search();
        tt.probe(1);
        assert!(tt.probe(1).is_some());
    }
}
<commit_msg>fixed generation overflow bug<commit_after>//! Implements a database that stores results of previously performed
//! searches.
//!
//! Using such a database (called "transposition table") is a way to
//! greatly reduce the search space of a chess tree with little
//! negative impact. Chess programs, during their brute-force search,
//! encounter the same positions again and again, but from different
//! sequences of moves, which is called a transposition.
//!
//! When the search encounters a transposition, it is beneficial to
//! "remember" what was determined last time the position was
//! examined, rather than redoing the entire search again. For this
//! reason, chess programs have a transposition table, which is a
//! large hash table storing information about positions previously
//! searched, how deeply they were searched, and what we concluded
//! about them.

use std;
use std::cell::{UnsafeCell, Cell};
use std::mem::transmute;
use std::num::Wrapping;
use basetypes::Value;

/// `BOUND_EXACT`, `BOUND_LOWER`, `BOUND_UPPER`, or `BOUND_NONE`.
///
/// * `BOUND_EXACT` means that the evaluation is exact.
///
/// * `BOUND_LOWER` means that the real value is greater or equal to
///    the evaluation.
///
/// * `BOUND_UPPER` means that the real value is lesser or equal to
///   the evaluation.
///
/// * `BOUND_NONE` means that the real value might be lesser, equal,
///   or grater than the evaluation.
pub type BoundType = u8;

/// The evaluation is not bounded.
pub const BOUND_NONE: BoundType = 0;

/// The evaluation is an upper bound.
pub const BOUND_UPPER: BoundType = 0b10;

/// The evaluation is a lower bound.
pub const BOUND_LOWER: BoundType = 0b01;

/// The evaluation is exact.
pub const BOUND_EXACT: BoundType = BOUND_UPPER | BOUND_LOWER;

/// Stores information about a particular position.
#[derive(Copy, Clone)]
pub struct EntryData {
    move16: u16,
    value: i16,
    eval_value: i16,
    gen_bound: u8,
    depth: u8,
}

impl EntryData {
    /// Creates a new instance.
    ///
    /// * `value` -- the value assigned to the position,
    ///
    /// * `bound` -- the meaning of the assigned value,
    ///
    /// * `depth` -- the depth of search,
    ///
    /// * `move16` -- best or refutation move (`0` if no move is
    ///   available).
    ///
    ///   These are the least significant 16 bits of the corresponding
    ///   `Move`. They contain the whole information about the played
    ///   move itself.  The only missing information is the move
    ///   ordering information and the information stored so as to be
    ///   able undo the move.
    ///
    /// * `eval_value` -- the calculated static evaluation for the
    ///   position.
    pub fn new(value: Value,
               bound: BoundType,
               depth: u8,
               move16: u16,
               eval_value: Value)
               -> EntryData {
        assert!(bound <= 0b11);
        assert!(depth < 128);
        EntryData {
            move16: move16,
            value: value,
            eval_value: eval_value,
            gen_bound: bound, // Stores the entry's generation and the bound.
            depth: depth,
        }
    }

    #[inline(always)]
    pub fn move16(&self) -> u16 {
        self.move16
    }

    #[inline(always)]
    pub fn value(&self) -> Value {
        self.value
    }

    #[inline(always)]
    pub fn eval_value(&self) -> Value {
        self.eval_value
    }

    #[inline(always)]
    pub fn bound(&self) -> BoundType {
        self.gen_bound & 0b11
    }

    #[inline(always)]
    pub fn depth(&self) -> u8 {
        self.depth
    }
}

// Represents transposition table entry.
//
// It is 16 bytes, defined as below:
//
// * key        64 bit
// * move16     16 bit
// * value      16 bit
// * eval value 16 bit
// * generation  6 bit
// * bound type  2 bit
// * depth       8 bit
#[derive(Copy, Clone)]
struct Entry {
    key: u64,
    data: EntryData,
}

impl Default for Entry {
    fn default() -> Entry {
        Entry {
            key: 0,
            data: unsafe { transmute(0u64) },
        }
    }
}

impl Entry {
    // Returns the whole contained data as one `u64` value.
    //
    // This is needed for implementing the lock-less probing and
    // storing.
    #[inline(always)]
    fn data_u64(&self) -> u64 {
        unsafe { transmute(self.data) }
    }

    // Returns entry's generation.
    #[inline(always)]
    fn generation(&self) -> u8 {
        self.data.gen_bound & 0b11111100
    }

    // Updates entry's generation.
    //
    // Since the `key` is saved xored with the data, when we change
    // the data, we have to change the stored `key` as well.
    #[inline(always)]
    fn update_generation(&mut self, generation: u8) {
        assert_eq!(generation & 0b11, 0);
        let old_data_u64 = self.data_u64();
        self.data.gen_bound = generation | self.data.bound();
        self.key ^= old_data_u64 ^ self.data_u64();
    }
}

/// A large hash-table that stores results of previously performed
/// searches.
pub struct TranspositionTable {
    generation: Cell<u8>,
    cluster_count: usize,
    table: UnsafeCell<Vec<[Entry; 4]>>,
}

impl TranspositionTable {
    /// Creates a new transposition table.
    ///
    /// The newly created table has the minimum possible size. Before
    /// using the new table for anything, `resize()` should be called
    /// on it, specifying the desired size.
    pub fn new() -> TranspositionTable {
        TranspositionTable {
            generation: Cell::new(0),
            cluster_count: 1,
            table: UnsafeCell::new(vec![Default::default()]),
        }
    }

    /// Resizes the transpositon table.
    ///
    /// `size_mb` is the desired new size in Mbytes. All entries in
    /// the table will be lost.
    pub fn resize(&mut self, size_mb: usize) {
        // The cluster count should be in the form "2**n", so the best
        // we can do is to ensure that the new cluster count will be
        // as close as possible but no greater than the requested one.
        let requested_cluster_count = (size_mb * 1024 * 1024) / std::mem::size_of::<[Entry; 4]>();

        // First, make sure `requested_cluster_count` is exceeded.
        let mut new_cluster_count = 1;
        while requested_cluster_count >= new_cluster_count {
            new_cluster_count <<= 1;
        }

        // Then make one step back, being careful so that the new
        // cluster count is not zero.
        if new_cluster_count > 1 {
            new_cluster_count >>= 1;
        } else {
            new_cluster_count = 1;
        }

        // Finally, reallocate the vector of clusters.
        if new_cluster_count != self.cluster_count {
            self.cluster_count = new_cluster_count;
            self.table = UnsafeCell::new(vec![Default::default(); new_cluster_count]);
        }
    }

    /// Clears the transpositon table.
    ///
    /// All remaining entries in the table will be removed.
    pub fn clear(&mut self) {
        self.table = UnsafeCell::new(vec![Default::default(); self.cluster_count]);
    }

    /// Signals that a new search is about to begin.
    ///
    /// Internally, the transposition table maintains a generation
    /// counter that is used to implement an efficient replacement
    /// strategy. This method increases this counter.
    pub fn new_search(&self) {
        // The lower 2 bits of the `generation` field are used by
        // bound type.
        self.generation.set((Wrapping(self.generation.get()) + Wrapping(0b100)).0);
        assert_eq!(self.generation.get() & 0b11, 0);
    }

    /// Probes for data by a specific key.
    #[inline]
    pub fn probe(&self, key: u64) -> Option<EntryData> {
        let cluster = unsafe { self.cluster_mut(key) };
        for entry in cluster.iter_mut() {
            if entry.key ^ entry.data_u64() == key {
                // If `key` and `data` were written simultaneously by
                // different search instances with different keys,
                // this will yield in a mismatch of the above
                // comparison (except for the rare and inherent key
                // collisions).
                entry.update_generation(self.generation.get());
                return Some(entry.data);
            }
        }
        None
    }

    /// Stores data by a specific key.
    ///
    /// After being stored, the data might be retrieved by
    /// `probe(key)`. This is not guaranteed though, because in the
    /// meantime it might have been overwritten.
    #[inline]
    pub fn store(&self, key: u64, mut data: EntryData) {
        // `store` and `probe` jointly implement a clever lock-less
        // hashing method. Rather than to store two disjoint items,
        // the key is stored xored with data, while data is stored
        // additionally as usual.

        data.gen_bound |= self.generation.get();  // Sets the generation.
        let mut cluster = unsafe { self.cluster_mut(key) };
        let mut replace_index = 0;
        let mut replace_score = 0xff;
        for (i, entry) in cluster.iter_mut().enumerate() {
            // Check if this is an empty slot, or an old entry for the
            // same key. If this this is the case we will use this
            // slot for the new entry.
            if entry.key == 0 || entry.key ^ entry.data_u64() == key {
                if data.move16 == 0 {
                    data.move16 = entry.data.move16;  // Preserve any existing move.
                }
                replace_index = i;
                break;
            }
            // If we can not find empty/old slot, the replaced entry
            // will be the entry with the lowest score.
            let entry_score = self.calc_score(entry);
            if entry_score < replace_score {
                replace_index = i;
                replace_score = entry_score;
            }
        }
        unsafe {
            cluster.get_unchecked_mut(replace_index).key = key ^ transmute::<EntryData, u64>(data);
            cluster.get_unchecked_mut(replace_index).data = data;
        }
    }

    // A helper method for `store`.
    //
    // Implements our replacement strategy. Should return higher
    // values for the entries that are move likely to save CPU work in
    // the future.
    #[inline]
    fn calc_score(&self, entry: &Entry) -> u8 {
        (if entry.generation() == self.generation.get() {
            128
        } else {
            0
        }) + entry.data.depth
    }

    // A helper method for `probe` and `store`.
    #[inline]
    unsafe fn cluster_mut(&self, key: u64) -> &mut [Entry; 4] {
        let cluster_index = (key & (self.cluster_count - 1) as u64) as usize;
        self.table.get().as_mut().unwrap().get_unchecked_mut(cluster_index)
    }
}

unsafe impl Sync for TranspositionTable {}

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

    #[test]
    fn test_cluster_size() {
        assert_eq!(std::mem::size_of::<[Entry; 4]>(), 64);
        assert_eq!(std::mem::size_of::<Entry>(), 16);
    }

    #[test]
    fn test_tt_resize() {
        let mut tt = TranspositionTable::new();
        assert_eq!(unsafe { &*tt.table.get() }.capacity(), 1);
        tt.resize(1);
        assert_eq!(unsafe { &*tt.table.get() }.capacity(),
                   1024 * 1024 / std::mem::size_of::<[Entry; 4]>());
        tt.clear();
    }

    #[test]
    fn test_store_and_probe() {
        let mut tt = TranspositionTable::new();
        assert!(tt.probe(1).is_none());
        let data = EntryData::new(0, 0, 100, 666, 0);
        assert_eq!(data.depth(), 100);
        assert_eq!(data.move16(), 666);
        tt.store(1, data);
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        tt.store(1, EntryData::new(0, 0, 100, 666, 0));
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        assert_eq!(tt.probe(1).unwrap().move16(), 666);
        for i in 2..100 {
            tt.store(i, EntryData::new(i as i16, 0, i as u8, i as u16, i as i16));
        }
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        assert_eq!(tt.probe(99).unwrap().depth(), 99);
        assert_eq!(tt.probe(98).unwrap().depth(), 98);
        assert_eq!(tt.probe(97).unwrap().depth(), 97);
        tt.clear();
        assert!(tt.probe(1).is_none());
        tt.store(1, data);
        tt.new_search();
        tt.probe(1);
        assert!(tt.probe(1).is_some());
    }

    #[test]
    fn test_new_search() {
        let tt = TranspositionTable::new();
        assert_eq!(tt.generation.get(), 0 << 2);
        tt.new_search();
        assert_eq!(tt.generation.get(), 1 << 2);
        for _ in 0..64 {
            tt.new_search();
        }
        assert_eq!(tt.generation.get(), 1 << 2);
    }
}
<|endoftext|>


<commit_before>use std::f32;
use std::u32;

use crate::utils::*;
use crate::graph::*;
use crate::sim::{Io, TestPacket, RoutingAlgorithm};

/*
fn get_local_error(pos: Vec3, neighbors: &Vec<Neighbor>) -> f32 {
	/*
	let mut mean = Vec3::new0();
	for v in neighbors {
		mean += v.pos;
	}

	pos.distance(&mean)
	*/
	1.0
}*/

#[derive(Clone)]
struct Neighbor {
	id: ID,
	pos: Vec3,
	error: f32,
	last_updated: u32
}

impl PartialEq for Neighbor {
	fn eq(&self, other: &Neighbor) -> bool {
		self.id == other.id
	}
}

#[derive(Clone)]
struct Node {
	pos: Vec3,
	error: f32,
	pos_old: Vec3,
	neighbors: Vec<Neighbor>,
}

impl Node {
	fn new() -> Self {
		Self {
			pos: Vec3::new0(),
			error: 0.0,
			pos_old: Vec3::new0(),
			neighbors: vec![],
		}
	}

	fn reset(&mut self) {
		self.pos = Vec3::new0();
		self.error = 0.0;
		self.pos_old = Vec3::new0();
		self.neighbors.clear();
	}

	fn timeout_entries(&mut self, time: u32) {
		vec_filter(&mut self.neighbors, |ref e| (e.last_updated + 5) >= time);
	}

	fn route(&self, packet: &TestPacket, dst_pos: &Vec3) -> Option<ID> {
		let mut d_next = f32::INFINITY;
		let mut n_next = None;

		for v in &self.neighbors {
			let d = v.pos.distance(dst_pos);
			if d < d_next {
				d_next = d;
				n_next = Some(v.id);
			}
		}

		n_next
	}

	fn update(&mut self, from_id: ID, from_pos: Vec3, from_error: f32, time: u32, rtt: f32) {
		vec_add_entry(&mut self.neighbors,
			&Neighbor {
				id: from_id,
				pos: from_pos,
				error: from_error,
				last_updated: time
			}
		);

		self.vivaldi_update(&from_pos, from_error, rtt);
	}

	// Vivaldi algorithm
	fn vivaldi_update(&mut self, pos: &Vec3, error: f32, rtt: f32) {
		//let rtt = self.rtt;
		let ce = 0.25;
		let cc = 0.25;

		// w = e_i / (e_i + e_j)
		let w = if (self.error > 0.0) && (error > 0.0) {
			self.error / (self.error + error)
		} else {
			1.0
		};

		// x_i - x_j
		let ab = self.pos - *pos;

		// rtt - |x_i - x_j|
		let re = rtt - ab.length();

		// e_s = ||x_i - x_j| - rtt| / rtt
		let es = re.abs() / rtt;

		// e_i = e_s * c_e * w + e_i * (1 - c_e * w)
		self.error = es * ce * w + self.error * (1.0 - ce * w);

		// ∂ = c_c * w
		let d = cc * w;

		// Choose random direction if both positions are identical
		let direction = if ab.is_near_null(0.01) {
			//println!("random direction");
			Vec3::random_unit()
		} else {
			ab
		};

		//println!("old pos: {}, {} {} {}", self.pos, direction, w, re);

		// x_i = x_i + ∂ * (rtt - |x_i - x_j|) * u(x_i - x_j)
		self.pos = self.pos + direction * (d * re);
		//println!("new pos: {}", self.pos);
	}
}

pub struct VivaldiRouting {
	nodes: Vec<Node>,
	time: u32,
	rtt: f32
}

//https://pdos.csail.mit.edu/papers/vivaldi:sigcomm/paper.pdf
impl VivaldiRouting {
	pub fn new() -> Self {
		Self {
			nodes: vec![],
			time: 0,
			rtt: 1.5
		}
	}

	// get median distance change
	pub fn get_convergence(&self) -> f32 {
		let mut d = 0.0;
		let mut c = 0.0;
		for node in &self.nodes {
			d += node.pos_old.distance(&node.pos);
			c += 1.0;
		}
		d / c
	}

}

impl RoutingAlgorithm for VivaldiRouting
{
	fn reset(&mut self, len: usize) {
		self.nodes = vec![Node::new(); len];
		self.time = 0;
	}

	fn get_node(&self, id: ID, key: &str, out: &mut std::fmt::Write) {
		match key {
			"label" => {
				let pos = self.nodes[id as usize].pos;
				write!(out, "{:.1}/{:.1}/{:.1}", pos.x(), pos.y(), pos.z()).unwrap();
			},
			"name" => {
				write!(out, "");
			},
			_ => {}
		}
	}

	fn get(&self, key: &str, out: &mut std::fmt::Write) {
		match key {
			"rtt" => {
				write!(out, "{}", self.rtt);
			},
			"name" => {
				write!(out, "Vivaldi");
			},
			"description" => {
				write!(out, "Use Vivaldi coordinates to allow routing.");
			},
			_ => {}
		}
	}

	fn set(&mut self, key: &str, value: &str) {
		match key {
			"rtt" => {
				if let Ok(rtt) = value.parse() {
					self.rtt = rtt;
				} else {
					println!("invalid rtt value");
				}
			},
			_ => {}
		}
	}

	fn step(&mut self, io: &mut Io) {
		self.time += 1;

		// fade out old entries
		for node in &mut self.nodes {
			node.pos_old = node.pos;
			node.timeout_entries(self.time);
		}

		// simulate broadcast traffic
		for (from, to) in io.link_iter() {
			let pos_old = self.nodes[from as usize].pos_old;
			self.nodes[to as usize].update(from, pos_old, 1.0, self.time, self.rtt);
		}
	}

	fn route(&self, packet: &TestPacket) -> Option<ID> {
		// we pretend to know the destination locator instead of the id
		let dst_pos = &self.nodes[packet.destination as usize].pos;
		self.nodes[packet.receiver as usize].route(packet, dst_pos)
	}
}
<commit_msg>switch label/name for vivaldi<commit_after>use std::f32;
use std::u32;

use crate::utils::*;
use crate::graph::*;
use crate::sim::{Io, TestPacket, RoutingAlgorithm};

/*
fn get_local_error(pos: Vec3, neighbors: &Vec<Neighbor>) -> f32 {
	/*
	let mut mean = Vec3::new0();
	for v in neighbors {
		mean += v.pos;
	}

	pos.distance(&mean)
	*/
	1.0
}*/

#[derive(Clone)]
struct Neighbor {
	id: ID,
	pos: Vec3,
	error: f32,
	last_updated: u32
}

impl PartialEq for Neighbor {
	fn eq(&self, other: &Neighbor) -> bool {
		self.id == other.id
	}
}

#[derive(Clone)]
struct Node {
	pos: Vec3,
	error: f32,
	pos_old: Vec3,
	neighbors: Vec<Neighbor>,
}

impl Node {
	fn new() -> Self {
		Self {
			pos: Vec3::new0(),
			error: 0.0,
			pos_old: Vec3::new0(),
			neighbors: vec![],
		}
	}

	fn reset(&mut self) {
		self.pos = Vec3::new0();
		self.error = 0.0;
		self.pos_old = Vec3::new0();
		self.neighbors.clear();
	}

	fn timeout_entries(&mut self, time: u32) {
		vec_filter(&mut self.neighbors, |ref e| (e.last_updated + 5) >= time);
	}

	fn route(&self, packet: &TestPacket, dst_pos: &Vec3) -> Option<ID> {
		let mut d_next = f32::INFINITY;
		let mut n_next = None;

		for v in &self.neighbors {
			let d = v.pos.distance(dst_pos);
			if d < d_next {
				d_next = d;
				n_next = Some(v.id);
			}
		}

		n_next
	}

	fn update(&mut self, from_id: ID, from_pos: Vec3, from_error: f32, time: u32, rtt: f32) {
		vec_add_entry(&mut self.neighbors,
			&Neighbor {
				id: from_id,
				pos: from_pos,
				error: from_error,
				last_updated: time
			}
		);

		self.vivaldi_update(&from_pos, from_error, rtt);
	}

	// Vivaldi algorithm
	fn vivaldi_update(&mut self, pos: &Vec3, error: f32, rtt: f32) {
		//let rtt = self.rtt;
		let ce = 0.25;
		let cc = 0.25;

		// w = e_i / (e_i + e_j)
		let w = if (self.error > 0.0) && (error > 0.0) {
			self.error / (self.error + error)
		} else {
			1.0
		};

		// x_i - x_j
		let ab = self.pos - *pos;

		// rtt - |x_i - x_j|
		let re = rtt - ab.length();

		// e_s = ||x_i - x_j| - rtt| / rtt
		let es = re.abs() / rtt;

		// e_i = e_s * c_e * w + e_i * (1 - c_e * w)
		self.error = es * ce * w + self.error * (1.0 - ce * w);

		// ∂ = c_c * w
		let d = cc * w;

		// Choose random direction if both positions are identical
		let direction = if ab.is_near_null(0.01) {
			//println!("random direction");
			Vec3::random_unit()
		} else {
			ab
		};

		//println!("old pos: {}, {} {} {}", self.pos, direction, w, re);

		// x_i = x_i + ∂ * (rtt - |x_i - x_j|) * u(x_i - x_j)
		self.pos = self.pos + direction * (d * re);
		//println!("new pos: {}", self.pos);
	}
}

pub struct VivaldiRouting {
	nodes: Vec<Node>,
	time: u32,
	rtt: f32
}

//https://pdos.csail.mit.edu/papers/vivaldi:sigcomm/paper.pdf
impl VivaldiRouting {
	pub fn new() -> Self {
		Self {
			nodes: vec![],
			time: 0,
			rtt: 1.5
		}
	}

	// get median distance change
	pub fn get_convergence(&self) -> f32 {
		let mut d = 0.0;
		let mut c = 0.0;
		for node in &self.nodes {
			d += node.pos_old.distance(&node.pos);
			c += 1.0;
		}
		d / c
	}

}

impl RoutingAlgorithm for VivaldiRouting
{
	fn reset(&mut self, len: usize) {
		self.nodes = vec![Node::new(); len];
		self.time = 0;
	}

	fn get_node(&self, id: ID, key: &str, out: &mut std::fmt::Write) {
		match key {
			"name" => {
				let pos = self.nodes[id as usize].pos;
				write!(out, "{:.1}/{:.1}/{:.1}", pos.x(), pos.y(), pos.z()).unwrap();
			},
			"label" => {
				write!(out, "");
			},
			_ => {}
		}
	}

	fn get(&self, key: &str, out: &mut std::fmt::Write) {
		match key {
			"rtt" => {
				write!(out, "{}", self.rtt);
			},
			"name" => {
				write!(out, "Vivaldi");
			},
			"description" => {
				write!(out, "Use Vivaldi coordinates to allow routing.");
			},
			_ => {}
		}
	}

	fn set(&mut self, key: &str, value: &str) {
		match key {
			"rtt" => {
				if let Ok(rtt) = value.parse() {
					self.rtt = rtt;
				} else {
					println!("invalid rtt value");
				}
			},
			_ => {}
		}
	}

	fn step(&mut self, io: &mut Io) {
		self.time += 1;

		// fade out old entries
		for node in &mut self.nodes {
			node.pos_old = node.pos;
			node.timeout_entries(self.time);
		}

		// simulate broadcast traffic
		for (from, to) in io.link_iter() {
			let pos_old = self.nodes[from as usize].pos_old;
			self.nodes[to as usize].update(from, pos_old, 1.0, self.time, self.rtt);
		}
	}

	fn route(&self, packet: &TestPacket) -> Option<ID> {
		// we pretend to know the destination locator instead of the id
		let dst_pos = &self.nodes[packet.destination as usize].pos;
		self.nodes[packet.receiver as usize].route(packet, dst_pos)
	}
}
<|endoftext|>


<commit_before>use freetype::{Face};
use event::{Event, RenderEvent, PressEvent};
use opengl_graphics::{Gl};
use input::Button::{Keyboard};
use input::keyboard::{Key};

use std::os::{num_cpus};
use std::path::{Path};
use std::sync::atomic::{AtomicUsize, AtomicIsize, Ordering, ATOMIC_USIZE_INIT, ATOMIC_ISIZE_INIT};

use chapter2::celloption::{CellOptions, CellOption, Tile, Item, Occupant};
use chapter2::dungeon::{Dungeon, DungeonCells};
use chapter2::genotype::{Genotype};
use chapter2::random_seed::{RandomSeed};
use chapter2::list_of_walls::{ListOfWalls};
use chapter2::wall_patterns::{WallPatterns};
use chapter2::desirable_properties::{DesirableProperties};
use chapter2::mu_lambda::{MuLambda};
use chapter2::evaluation::{EvaluationFn, check_1x1_rooms, has_entrance_exit, doors_are_useful, rooms_are_accessible};
use chapter2::phenotype::{Seed};
use chapter2::statistics::{Statistic};

use util::spritesheet::{SpriteSheet};
use util::sprite::{Sprite};
use util::text::{render_text};
use util::config::{Config};

static FRAME: AtomicUsize = ATOMIC_USIZE_INIT;
static CHOICE: AtomicIsize = ATOMIC_ISIZE_INIT;

pub fn chapter2_entry(config: &Config) -> Box<Fn(&mut Gl, &mut Face, Event) -> ()> {

    // load a whole bunch of configurable options
    let vars = config.get_table(None, "main");
    let tile_width = config.get_integer(vars, "tile_width") as i32;
    let tile_height = config.get_integer(vars, "tile_height") as i32;
    let tiles_width = config.get_default(vars, "tiles_width", 50);
    let tiles_height = config.get_default(vars, "tiles_height", 50);
    let animation_speed = config.get_default(vars, "animation_speed", 10);
    let threads = config.get_default(vars, "threads", num_cpus() * 2);

    let spritesheet_name = config.get_string(vars, "spritesheet");
    let spritesheets = config.get_table(None, "spritesheets");
    let spritesheet_config = config.get_table(Some(spritesheets), spritesheet_name);
    let spritesheet_location = config.get_string(spritesheet_config, "path");

    let cell_data = config.get_table(Some(spritesheet_config), "cells");
    let tiles: Vec<String> = config.get_array(cell_data, "tiles");
    let items: Vec<String> = config.get_array(cell_data, "items");
    let occupants: Vec<String> = config.get_array(cell_data, "occupants");
    let cell_tiles: CellOptions<Tile> = CellOptions::new(tiles.as_slice());
    let cell_items: CellOptions<Item> = CellOptions::new(items.as_slice());
    let cell_occupants: CellOptions<Occupant> = CellOptions::new(occupants.as_slice());
    let occupant_chance = config.get_float(spritesheet_config, "occupant_chance");

    let mulambda_vars = config.get_table(None, "mu-lambda");
    let mu = config.get_default(mulambda_vars, "mu", 100);
    let lambda = config.get_default(mulambda_vars, "lambda", 100);
    let mutation = config.get_default(mulambda_vars, "mutation", 0.33);
    let iterations = config.get_default(mulambda_vars, "iterations", 100);
    let strategy = config.get_string(mulambda_vars, "strategy");
    let evaluations: Vec<String> = config.get_array(mulambda_vars, "evaluations");
    let evaluation_fns: Vec<EvaluationFn> = evaluations.iter().map(|eval| {
        match eval.as_slice() {
            "check_1x1_rooms" => box check_1x1_rooms as EvaluationFn,
            "has_entrance_exit" => box has_entrance_exit as EvaluationFn,
            "doors_are_useful" => box doors_are_useful as EvaluationFn,
            "rooms_are_accessible" => box rooms_are_accessible as EvaluationFn,
            _ => panic!("Evaluation function {} could not be found.", eval)
        }
    }).collect();
    let evaluation_weights: Vec<f64> = config.get_array(mulambda_vars, "evaluation_weights");

    let seed = Seed::new(tiles_width, tiles_height, cell_tiles, cell_items, cell_occupants, occupant_chance);

    let spritesheet_path = Path::new(spritesheet_location);
    let spritesheet = SpriteSheet::new(&spritesheet_path);

    // We cannot have trait objects that implement Clone or use
    // generic parameters. Instead, we use macros to make this section
    // a bit cleaner.
    macro_rules! mu_lambda_run (
        ($genotype:expr) => {{
            let mut mulambda = MuLambda::new(threads,
                                             iterations,
                                             mu,
                                             lambda,
                                             mutation,
                                             $genotype.clone(),
                                             evaluation_fns,
                                             evaluation_weights);
            let result = mulambda.run();
            result.into_iter().map(|(individual, statistic)| (individual.generate(), statistic)).collect()
        }}
        );
    let winners: Vec<(Dungeon, Statistic)> = match strategy {
        "RandomSeed" => {
            let genotype = RandomSeed::new(&seed);
            mu_lambda_run!(genotype)
        }
        "ListOfWalls" => {
            let genotype = ListOfWalls::new(&config, &seed);
            mu_lambda_run!(genotype)
        }
        "WallPatterns" => {
            let genotype = WallPatterns::new(&config, &seed);
            mu_lambda_run!(genotype)
        }
        "DesirableProperties" => {
            let genotype = DesirableProperties::new(&config, &seed);
            mu_lambda_run!(genotype)
        }
        _ => panic!("Strategy {} could not be found.", strategy)
    };

    box move |gl: &mut Gl, face: &mut Face, e: Event| {
        let choice = CHOICE.load(Ordering::Relaxed);
        let frame = FRAME.load(Ordering::Relaxed);

        let ref current = winners[choice as usize];
        let &(ref dungeon, ref statistic) = current;
        let seconds = frame / animation_speed;
        e.render(|_| {
            let dc = DungeonCells::new(&dungeon);
            for cell in dc {
                let x = cell.x as i32 * tile_width;
                let y = cell.y as i32 * tile_height;
                match cell.tile {
                    Some(ref val) => {
                        let sprite = spritesheet.sprites.get(&val.name()).unwrap();
                        sprite.draw(gl, x, y, seconds);
                    }
                    None => {
                        Sprite::missing(gl, x, y, tile_width, tile_height);
                    }
                }
                match cell.occupant {
                    Some(ref val) => {
                        let sprite = spritesheet.sprites.get(&val.name()).unwrap();
                        sprite.draw(gl, x, y, seconds);
                    }
                    None => ()
                }
            }
            let info = format!("Dungeon no. #{} (born on iteration {}, ranking {})",
                               choice,
                               statistic.iteration,
                               statistic.fitness);
            render_text(face, gl, 10.0, 10.0, info.as_slice());
        });

        if let Some(Keyboard(key)) = e.press_args() {
            let n = winners.len() as isize;
            if key == Key::Left {
                CHOICE.fetch_sub(1, Ordering::Relaxed);
                if choice < 0 {
                    CHOICE.store(n - 1, Ordering::Relaxed);
                    FRAME.store(0, Ordering::Relaxed);
                }
            }
            else if key == Key::Right {
                CHOICE.fetch_add(1, Ordering::Relaxed);
                CHOICE.store(choice % n, Ordering::Relaxed);
                FRAME.store(0, Ordering::Relaxed);
            }
        };

        FRAME.fetch_add(1, Ordering::Relaxed);
    }
}
<commit_msg>Quick fix for keypresses.<commit_after>use freetype::{Face};
use event::{Event, RenderEvent, PressEvent};
use opengl_graphics::{Gl};
use input::Button::{Keyboard};
use input::keyboard::{Key};

use std::os::{num_cpus};
use std::path::{Path};
use std::sync::atomic::{AtomicUsize, AtomicIsize, Ordering, ATOMIC_USIZE_INIT, ATOMIC_ISIZE_INIT};

use chapter2::celloption::{CellOptions, CellOption, Tile, Item, Occupant};
use chapter2::dungeon::{Dungeon, DungeonCells};
use chapter2::genotype::{Genotype};
use chapter2::random_seed::{RandomSeed};
use chapter2::list_of_walls::{ListOfWalls};
use chapter2::wall_patterns::{WallPatterns};
use chapter2::desirable_properties::{DesirableProperties};
use chapter2::mu_lambda::{MuLambda};
use chapter2::evaluation::{EvaluationFn, check_1x1_rooms, has_entrance_exit, doors_are_useful, rooms_are_accessible};
use chapter2::phenotype::{Seed};
use chapter2::statistics::{Statistic};

use util::spritesheet::{SpriteSheet};
use util::sprite::{Sprite};
use util::text::{render_text};
use util::config::{Config};

static FRAME: AtomicUsize = ATOMIC_USIZE_INIT;
static CHOICE: AtomicIsize = ATOMIC_ISIZE_INIT;

pub fn chapter2_entry(config: &Config) -> Box<Fn(&mut Gl, &mut Face, Event) -> ()> {

    // load a whole bunch of configurable options
    let vars = config.get_table(None, "main");
    let tile_width = config.get_integer(vars, "tile_width") as i32;
    let tile_height = config.get_integer(vars, "tile_height") as i32;
    let tiles_width = config.get_default(vars, "tiles_width", 50);
    let tiles_height = config.get_default(vars, "tiles_height", 50);
    let animation_speed = config.get_default(vars, "animation_speed", 10);
    let threads = config.get_default(vars, "threads", num_cpus() * 2);

    let spritesheet_name = config.get_string(vars, "spritesheet");
    let spritesheets = config.get_table(None, "spritesheets");
    let spritesheet_config = config.get_table(Some(spritesheets), spritesheet_name);
    let spritesheet_location = config.get_string(spritesheet_config, "path");

    let cell_data = config.get_table(Some(spritesheet_config), "cells");
    let tiles: Vec<String> = config.get_array(cell_data, "tiles");
    let items: Vec<String> = config.get_array(cell_data, "items");
    let occupants: Vec<String> = config.get_array(cell_data, "occupants");
    let cell_tiles: CellOptions<Tile> = CellOptions::new(tiles.as_slice());
    let cell_items: CellOptions<Item> = CellOptions::new(items.as_slice());
    let cell_occupants: CellOptions<Occupant> = CellOptions::new(occupants.as_slice());
    let occupant_chance = config.get_float(spritesheet_config, "occupant_chance");

    let mulambda_vars = config.get_table(None, "mu-lambda");
    let mu = config.get_default(mulambda_vars, "mu", 100);
    let lambda = config.get_default(mulambda_vars, "lambda", 100);
    let mutation = config.get_default(mulambda_vars, "mutation", 0.33);
    let iterations = config.get_default(mulambda_vars, "iterations", 100);
    let strategy = config.get_string(mulambda_vars, "strategy");
    let evaluations: Vec<String> = config.get_array(mulambda_vars, "evaluations");
    let evaluation_fns: Vec<EvaluationFn> = evaluations.iter().map(|eval| {
        match eval.as_slice() {
            "check_1x1_rooms" => box check_1x1_rooms as EvaluationFn,
            "has_entrance_exit" => box has_entrance_exit as EvaluationFn,
            "doors_are_useful" => box doors_are_useful as EvaluationFn,
            "rooms_are_accessible" => box rooms_are_accessible as EvaluationFn,
            _ => panic!("Evaluation function {} could not be found.", eval)
        }
    }).collect();
    let evaluation_weights: Vec<f64> = config.get_array(mulambda_vars, "evaluation_weights");

    let seed = Seed::new(tiles_width, tiles_height, cell_tiles, cell_items, cell_occupants, occupant_chance);

    let spritesheet_path = Path::new(spritesheet_location);
    let spritesheet = SpriteSheet::new(&spritesheet_path);

    // We cannot have trait objects that implement Clone or use
    // generic parameters. Instead, we use macros to make this section
    // a bit cleaner.
    macro_rules! mu_lambda_run (
        ($genotype:expr) => {{
            let mut mulambda = MuLambda::new(threads,
                                             iterations,
                                             mu,
                                             lambda,
                                             mutation,
                                             $genotype.clone(),
                                             evaluation_fns,
                                             evaluation_weights);
            let result = mulambda.run();
            result.into_iter().map(|(individual, statistic)| (individual.generate(), statistic)).collect()
        }}
        );
    let winners: Vec<(Dungeon, Statistic)> = match strategy {
        "RandomSeed" => {
            let genotype = RandomSeed::new(&seed);
            mu_lambda_run!(genotype)
        }
        "ListOfWalls" => {
            let genotype = ListOfWalls::new(&config, &seed);
            mu_lambda_run!(genotype)
        }
        "WallPatterns" => {
            let genotype = WallPatterns::new(&config, &seed);
            mu_lambda_run!(genotype)
        }
        "DesirableProperties" => {
            let genotype = DesirableProperties::new(&config, &seed);
            mu_lambda_run!(genotype)
        }
        _ => panic!("Strategy {} could not be found.", strategy)
    };

    box move |gl: &mut Gl, face: &mut Face, e: Event| {
        let choice = CHOICE.load(Ordering::Relaxed);
        let frame = FRAME.load(Ordering::Relaxed);

        let ref current = winners[choice as usize];
        let &(ref dungeon, ref statistic) = current;
        let seconds = frame / animation_speed;
        e.render(|_| {
            let dc = DungeonCells::new(&dungeon);
            for cell in dc {
                let x = cell.x as i32 * tile_width;
                let y = cell.y as i32 * tile_height;
                match cell.tile {
                    Some(ref val) => {
                        let sprite = spritesheet.sprites.get(&val.name()).unwrap();
                        sprite.draw(gl, x, y, seconds);
                    }
                    None => {
                        Sprite::missing(gl, x, y, tile_width, tile_height);
                    }
                }
                match cell.occupant {
                    Some(ref val) => {
                        let sprite = spritesheet.sprites.get(&val.name()).unwrap();
                        sprite.draw(gl, x, y, seconds);
                    }
                    None => ()
                }
            }
            let info = format!("Dungeon no. #{} (born on iteration {}, ranking {})",
                               choice,
                               statistic.iteration,
                               statistic.fitness);
            render_text(face, gl, 10.0, 10.0, info.as_slice());
        });

        if let Some(Keyboard(key)) = e.press_args() {
            let n = winners.len() as isize;
            if key == Key::Left {
                CHOICE.fetch_sub(1, Ordering::Relaxed);
                let new_choice = CHOICE.load(Ordering::Relaxed);
                if new_choice < 0 {
                    CHOICE.store(n - 1, Ordering::Relaxed);
                    FRAME.store(0, Ordering::Relaxed);
                }
            }
            else if key == Key::Right {
                CHOICE.fetch_add(1, Ordering::Relaxed);
                let new_choice = CHOICE.load(Ordering::Relaxed);
                CHOICE.store(new_choice % n, Ordering::Relaxed);
                FRAME.store(0, Ordering::Relaxed);
            }
        };

        FRAME.fetch_add(1, Ordering::Relaxed);
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Read;
use command::Command;

type Cell = u8;

pub struct VM {
    cells: [Cell; 30_000],
    data_pointer: usize,
}

impl VM {
    pub fn new() -> VM {
        VM { cells: [0; 30_000], data_pointer: 0 }
    }

    pub fn output(&self) {
        print!("{}", self.cells[self.data_pointer] as char);
    }

    pub fn input(&mut self) {
        match io::stdin().bytes().next() {
            Some(res) => match res {
                Ok(value) => self.cells[self.data_pointer] = value,
                Err(error) => panic!(error),
            },
            None => {}
        }
        println!("");
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] + 1;
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] - 1;
    }

    pub fn right_shift(&mut self) {
        self.data_pointer = self.data_pointer + 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer = self.data_pointer - 1;
    }

    pub fn apply(&mut self, command: Command) {
        match command {
            Command::Output => self.output(),
            Command::Input => self.input(),
            Command::Increment => self.increment(),
            Command::Decrement => self.decrement(),
            Command::RightShift => self.right_shift(),
            Command::LeftShift => self.left_shift(),
            _ => {},
        }
    }

    pub fn apply_many(&mut self, commands: &[Command]) {
        for command in commands {
            self.apply(*command)
        }
    }
}
<commit_msg>Remove vm.apply_many(&mut self, &[Command])<commit_after>use std::io;
use std::io::Read;
use command::Command;

type Cell = u8;

pub struct VM {
    cells: [Cell; 30_000],
    data_pointer: usize,
}

impl VM {
    pub fn new() -> VM {
        VM { cells: [0; 30_000], data_pointer: 0 }
    }

    pub fn output(&self) {
        print!("{}", self.cells[self.data_pointer] as char);
    }

    pub fn input(&mut self) {
        match io::stdin().bytes().next() {
            Some(res) => match res {
                Ok(value) => self.cells[self.data_pointer] = value,
                Err(error) => panic!(error),
            },
            None => {}
        }
        println!("");
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] + 1;
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] - 1;
    }

    pub fn right_shift(&mut self) {
        self.data_pointer = self.data_pointer + 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer = self.data_pointer - 1;
    }

    pub fn apply(&mut self, command: Command) {
        match command {
            Command::Output => self.output(),
            Command::Input => self.input(),
            Command::Increment => self.increment(),
            Command::Decrement => self.decrement(),
            Command::RightShift => self.right_shift(),
            Command::LeftShift => self.left_shift(),
            _ => {},
        }
    }
}
<|endoftext|>


<commit_before>use ffi;
use std::os::raw::c_int;
use std::ptr;
use types::*;
use ffi::MaybeError;
use device::DeviceInfo;

// Input
// -----
/// Representation of an input midi port
#[allow(missing_copy_implementations)]
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}

impl InputPort {
    /// Construct a new `InputPort` for `input_device`
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
        if device.is_output() {
            return Err(Error::NotAnInputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenInput(&raw_stream as *const *const _,
                              device.id(),
                              ptr::null(), // *inputDriverInfo, not needed for normal operation
                              buffer_size as c_int,
                              ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                              ptr::null()) // time_info, a pointer passed to the time procedure
        }));

        Ok(InputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    pub fn read_n(&mut self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > self.buffer_size {
            self.buffer_size as c_int
        } else {
            cnt as c_int
        };
        let mut event_buffer = vec![ffi::PmEvent::default(); self.buffer_size];
        let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
        if res < 0 {
            let err = ffi::PmError::try_from(res).unwrap();
            // TODO: Return the error
            println!("error: {:?}", err);
            return Ok(None);
        } else if res == 0 {
            Ok(None)
        } else {
            // remove mutability and replace return value
            let events = (0..res as usize)
                             .map(|i| MidiEvent::from(event_buffer[i].clone()))
                             .collect::<Vec<MidiEvent>>();
            Ok(Some(events))
        }
    }

    /// Reads a single `MidiEvent` if one is avaible
    ///
    /// A `Result` of `None` means no event was available.
    ///
    /// See the PortMidi documentation for information on how it deals with input
    /// overflows
    /// TODO: call `read_n`
    pub fn read(&mut self) -> Result<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// `poll` tests if there is input available, either returing a bool or an error
    pub fn poll(&self) -> Result<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            err @ _ => Err(Error::PortMidi(err)),
        }
    }
}
impl Drop for InputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}

// Output
// ------
/// Representation of an output midi port
///
#[allow(missing_copy_implementations)]
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl OutputPort {
    /// Construct a new `OutputPort` for `input_device`
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<OutputPort> {
        if device.is_input() {
            return Err(Error::NotAnOutputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenOutput(&raw_stream as *const *const _,
                               device.id(),
                               ptr::null(), // *inputDriverInfo, not needed for normal operation
                               buffer_size as c_int,
                               ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                               ptr::null(), // time_info, a pointer passed to the time procedure
                               0) //latency
        }));

        Ok(OutputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Terminates outgoing messages immediately
    ///
    /// The caller should immediately close the output port, this may
    /// result in transmission of a partial midi message. Note, not all platforms
    /// support abort.
    pub fn abort(&mut self) -> Result<()> {
        Result::from(unsafe { ffi::Pm_Abort(self.stream) })
    }

    /// Write a single `MidiEvent`
    pub fn write_event(&mut self, midi_event: MidiEvent) -> Result<()> {
        let event = midi_event.into();
        Result::from(unsafe { ffi::Pm_Write(self.stream, &event, 1) })
    }

    /// Write a single `MidiMessage` immediately
    pub fn write_message(&mut self, midi_message: MidiMessage) -> Result<()> {
        let message = midi_message.into();
        Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, message) })
    }
}
impl Drop for OutputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}
<commit_msg>Use match and avoid busy-wait<commit_after>use ffi;
use std::os::raw::c_int;
use std::ptr;
use types::*;
use ffi::MaybeError;
use device::DeviceInfo;

// Input
// -----
/// Representation of an input midi port
#[allow(missing_copy_implementations)]
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}

impl InputPort {
    /// Construct a new `InputPort` for `input_device`
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
        if device.is_output() {
            return Err(Error::NotAnInputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenInput(&raw_stream as *const *const _,
                              device.id(),
                              ptr::null(), // *inputDriverInfo, not needed for normal operation
                              buffer_size as c_int,
                              ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                              ptr::null()) // time_info, a pointer passed to the time procedure
        }));

        Ok(InputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    pub fn read_n(&mut self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > self.buffer_size {
            self.buffer_size as c_int
        } else {
            cnt as c_int
        };
        let mut event_buffer = vec![ffi::PmEvent::default(); self.buffer_size];
        let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
        ::std::thread::sleep_ms(20);
        match ffi::PmError::try_from(res) {
            Ok(event_cnt) => {
                let events = (0..event_cnt as usize)
                                 .map(|i| MidiEvent::from(event_buffer[i].clone()))
                                 .collect::<Vec<MidiEvent>>();
                Ok(Some(events))
            }
            err @ Err(ffi::PmError::PmNoError) => Ok(None),
            Err(err) => return Err(Error::PortMidi(err)),
        }
    }

    /// Reads a single `MidiEvent` if one is avaible
    ///
    /// A `Result` of `None` means no event was available.
    ///
    /// See the PortMidi documentation for information on how it deals with input
    /// overflows
    /// TODO: call `read_n`
    pub fn read(&mut self) -> Result<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// `poll` tests if there is input available, either returing a bool or an error
    pub fn poll(&self) -> Result<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            err @ _ => Err(Error::PortMidi(err)),
        }
    }
}
impl Drop for InputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}

// Output
// ------
/// Representation of an output midi port
///
#[allow(missing_copy_implementations)]
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl OutputPort {
    /// Construct a new `OutputPort` for `input_device`
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<OutputPort> {
        if device.is_input() {
            return Err(Error::NotAnOutputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenOutput(&raw_stream as *const *const _,
                               device.id(),
                               ptr::null(), // *inputDriverInfo, not needed for normal operation
                               buffer_size as c_int,
                               ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                               ptr::null(), // time_info, a pointer passed to the time procedure
                               0) //latency
        }));

        Ok(OutputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Terminates outgoing messages immediately
    ///
    /// The caller should immediately close the output port, this may
    /// result in transmission of a partial midi message. Note, not all platforms
    /// support abort.
    pub fn abort(&mut self) -> Result<()> {
        Result::from(unsafe { ffi::Pm_Abort(self.stream) })
    }

    /// Write a single `MidiEvent`
    pub fn write_event(&mut self, midi_event: MidiEvent) -> Result<()> {
        let event = midi_event.into();
        Result::from(unsafe { ffi::Pm_Write(self.stream, &event, 1) })
    }

    /// Write a single `MidiMessage` immediately
    pub fn write_message(&mut self, midi_message: MidiMessage) -> Result<()> {
        let message = midi_message.into();
        Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, message) })
    }
}
impl Drop for OutputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Extensions to the standard I/O utilities.
//!
//! This module essentially provides useful, RRG-specific utilities that are not
//! available in `std::io`, mostly operating on the standard `Read` and `Write`
//! traits.

use std::io::{Read, Write, Result};

// The same as in the Rust's standard library.
const DEFAULT_BUF_SIZE: usize = 8 * 1024;

/// Copies contents of one buffer into the other until a condition is met.
///
/// This function should behave similarly to the standard `std::io::copy` with
/// the difference that it can be given a condition when copying should stop.
///
/// Note that the predicate is not checked after each copied byte. Therefore,
/// there are not guarantees about when exactly and how often it will be called.
/// In particular, the input stream can finish even before the predicate is
/// called at all.
///
/// # Errors
///
/// The errors is reported immediately if there is an error when reading from
/// the input or writing to the output.
///
/// Like `std::io::copy`, this function will retry instances of `Interrupted`
/// errors.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
///
/// let mut rand = File::open("/dev/random").unwrap();
/// let mut buf = vec!();
///
/// rrg::io::copy_until(&mut rand, &mut buf, |_, writer| writer.len() >= 1024);
///
/// println!("random bytes: {:?}", buf);
/// ```
pub fn copy_until<R, W, P>(reader: &mut R, writer: &mut W, mut pred: P)
    -> Result<()>
where
    R: Read,
    W: Write,
    P: FnMut(&R, &W) -> bool,
{
    let mut buf = [0; DEFAULT_BUF_SIZE];
    loop {
        use std::io::ErrorKind::*;
        let len = match reader.read(&mut buf[..]) {
            Ok(0) => break,
            Ok(len) => len,
            Err(ref error) if error.kind() == Interrupted => continue,
            Err(error) => return Err(error),
        };

        writer.write_all(&buf[..len])?;
        if pred(reader, writer) {
            break;
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_copy_until_with_empty_buffer() {
        let mut reader: &[u8] = b"";
        let mut writer = vec!();

        assert!(copy_until(&mut reader, &mut writer, |_, _| false).is_ok());
        assert_eq!(writer, b"");
    }

    #[test]
    fn test_copy_until_end() {
        let mut reader: &[u8] = b"foobar";
        let mut writer = vec!();

        assert!(copy_until(&mut reader, &mut writer, |_, _| false).is_ok());
        assert_eq!(writer, b"foobar");
    }

    #[test]
    fn test_copy_until_specific_size() {
        let limit = 4 * 1024 * 1024;

        // An infinite stream of zeros (see explanation below).
        struct Null;

        impl std::io::Read for Null {

            fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
                // TODO: Rewriter with `slice::fill` once it stabilizes.
                for item in buf.iter_mut() {
                    *item = 0;
                }

                Ok(buf.len() as usize)
            }
        }

        let mut reader = Null;
        let mut writer = vec!();

        // This should verify that copying eventually stops after the condition
        // is met since the reader is inifite.
        assert! {
            copy_until(&mut reader, &mut writer, |_, writer| {
                writer.len() > limit
            }).is_ok()
        }

        assert!(writer.iter().all(|item| *item == 0));
        assert!(writer.len() > limit);
    }
}
<commit_msg>Adjust logic of conditional buffer copying.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Extensions to the standard I/O utilities.
//!
//! This module essentially provides useful, RRG-specific utilities that are not
//! available in `std::io`, mostly operating on the standard `Read` and `Write`
//! traits.

use std::io::{Read, Write, Result};

// The same as in the Rust's standard library.
const DEFAULT_BUF_SIZE: usize = 8 * 1024;

/// Copies contents of one buffer into the other until a condition is met.
///
/// This function should behave similarly to the standard `std::io::copy` with
/// the difference that it can be given a condition when copying should stop.
///
/// Note that the predicate is not checked after each copied byte. Therefore,
/// there are no guarantees about when exactly and how often it will be called.
///
/// # Errors
///
/// The errors is reported immediately if there is an error when reading from
/// the input or writing to the output.
///
/// Like `std::io::copy`, this function will retry instances of `Interrupted`
/// errors.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
///
/// let mut rand = File::open("/dev/random").unwrap();
/// let mut buf = vec!();
///
/// rrg::io::copy_until(&mut rand, &mut buf, |_, writer| writer.len() >= 1024);
///
/// println!("random bytes: {:?}", buf);
/// ```
pub fn copy_until<R, W, P>(reader: &mut R, writer: &mut W, mut pred: P)
    -> Result<()>
where
    R: Read,
    W: Write,
    P: FnMut(&R, &W) -> bool,
{
    let mut buf = [0; DEFAULT_BUF_SIZE];
    loop {
        if pred(reader, writer) {
            break;
        }

        use std::io::ErrorKind::*;
        let len = match reader.read(&mut buf[..]) {
            Ok(0) => break,
            Ok(len) => len,
            Err(ref error) if error.kind() == Interrupted => continue,
            Err(error) => return Err(error),
        };

        writer.write_all(&buf[..len])?;
    }

    Ok(())
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_copy_until_with_empty_buffer() {
        let mut reader: &[u8] = b"";
        let mut writer = vec!();

        assert!(copy_until(&mut reader, &mut writer, |_, _| false).is_ok());
        assert_eq!(writer, b"");
    }

    #[test]
    fn test_copy_until_begin() {
        let mut reader: &[u8] = b"foobar";
        let mut writer = vec!();

        assert!(copy_until(&mut reader, &mut writer, |_, _| true).is_ok());
        assert_eq!(writer, b"");
    }

    #[test]
    fn test_copy_until_end() {
        let mut reader: &[u8] = b"foobar";
        let mut writer = vec!();

        assert!(copy_until(&mut reader, &mut writer, |_, _| false).is_ok());
        assert_eq!(writer, b"foobar");
    }

    #[test]
    fn test_copy_until_specific_size() {
        let limit = 4 * 1024 * 1024;

        // An infinite stream of zeros (see explanation below).
        struct Null;

        impl std::io::Read for Null {

            fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
                // TODO: Rewriter with `slice::fill` once it stabilizes.
                for item in buf.iter_mut() {
                    *item = 0;
                }

                Ok(buf.len() as usize)
            }
        }

        let mut reader = Null;
        let mut writer = vec!();

        // This should verify that copying eventually stops after the condition
        // is met since the reader is inifite.
        assert! {
            copy_until(&mut reader, &mut writer, |_, writer| {
                writer.len() > limit
            }).is_ok()
        }

        assert!(writer.iter().all(|item| *item == 0));
        assert!(writer.len() > limit);
    }
}
<|endoftext|>