<commit_before>use math::*;
use phloem::Blob;
use shared_memory::*;
use layers::sigmoid_layer::SigmoidLayer;

pub struct Layer<'a> {
    // pub config: Box<LayerConfig>,
    pub config: Box<&'a LayerConfig>,
    pub worker: Box<ILayer>,

    /// The vector that indicates whether each top blob has a non-zero weight in
    /// the objective function.
    loss: Vec<f32>,

    /// The vector that stores shared references to the parameters in the form of blobs.
    pub blobs: Vec<ArcLock<HeapBlob>>,

    /// Vector indicating whether to compute the diff of each param blob. */
    param_propagate_down: Vec<bool>,
}

impl<'a> Layer<'a> {
    pub fn from_config(config: &'a LayerConfig) -> Layer {
        // let ref cl = config.clone();
        let cl = config.clone();
        let cfg = Box::<&'a LayerConfig>::new(cl);
        Layer {
            loss: Vec::new(),
            // top: Vec::new(),
            blobs: Vec::new(),

            param_propagate_down: Vec::new(),

            worker: Layer::worker_from_config(&cfg),
            config: cfg,
        }
    }

    fn worker_from_config(config: &LayerConfig) -> Box<ILayer> {
        match config.layer_type {
            LayerType::SigmoidLayer => Box::new(SigmoidLayer),
        }
    }

    /// Sets whether the layer should compute gradients w.r.t. a
    /// parameter at a particular index given by param_id.
    pub fn set_param_propagate_down(&mut self, param_id: usize, value: bool) {
        if self.param_propagate_down.len() <= param_id {
            self.param_propagate_down.resize(param_id + 1, true);
        }
        self.param_propagate_down[param_id] = value;

    }

    pub fn loss(&self, id: usize) -> Option<&f32> {
        self.loss.get(id)
    }
}

/// A Layer in a Neural Network that can handle forward and backward of a computation step.
pub trait ILayer {
    /// Compute the layer output.
    /// Uses the CPU.
    fn forward_cpu(&self, bottom: &[HeapBlob], top: &mut Vec<HeapBlob>);
    /// Compute the gradients for the bottom blobs
    /// if the corresponding value of propagate_down is true.
    /// Uses the CPU.
    fn backward_cpu(&self, top: &[HeapBlob], propagate_down: &[bool], bottom: &mut Vec<HeapBlob>);

    /// Compute the layer output using the currently set computation method (CPU).
    fn forward(&self, bottom: &[HeapBlob], top: &mut Vec<HeapBlob>) -> f32 {
        // Lock();
        // Reshape(bottom, top); // Reshape the layer to fit top & bottom blob
        let mut loss = 0f32;

        self.forward_cpu(bottom, top);

        for top_layer in top {
            // if (!this->loss(top_id)) { continue; } // Caffe
            // if !self.loss(top_layer) { continue; }
            // let count = (**top_layer).len();
            let data = top_layer.cpu_data();
            let loss_weights = top_layer.cpu_diff();

            loss += leaf_cpu_dot(data, loss_weights);
            // loss += leaf_cpu_dot(count, data, loss_weights);
        }

        // Unlock();

        loss
    }

    /// Return whether "anonymous" top blobs are created automatically for the layer.
    ///
    /// If this method returns true, Network::init will create enough "anonymous" top
    /// blobs to fulfill the requirement specified by exact_num_top_blobs() or
    /// min_top_blobs().
    fn auto_top_blobs(&self) -> bool {
        false
    }
    /// Returns the minimum number of top blobs required by the layer,
    /// or 0 if no minimum number is required.
    ///
    /// This method should be overridden to return a positive value if your
    /// layer expects some minimum number of top blobs.
    fn min_top_blobs(&self) -> usize {
        0
    }
    /// Returns the exact number of top blobs required by the layer,
    /// or 0 if no exact number is required.
    ///
    /// This method should be overridden to return a positive value if your
    /// layer expects some exact number of top blobs.
    fn exact_num_top_blobs(&self) -> usize {
        0
    }
    /// Returns the exact number of bottom blobs required by the layer,
    /// or 0 if no exact number is required.
    ///
    /// This method should be overridden to return a positive value if your
    /// layer expects some exact number of bottom blobs.
    fn exact_num_bottom_blobs(&self) -> usize {
        0
    }
    /// Return whether to allow force_backward for a given bottom blob index.
    ///
    /// If AllowForceBackward(i) == false, we will ignore the force_backward
    /// setting and backpropagate to blob i only if it needs gradient information
    /// (as is done when force_backward == false).
    fn allow_force_backward(&self, bottom_id: usize) -> bool {
        true
    }
}

pub struct LayerConfig {
    pub name: String, // the layer name
    layer_type: LayerType, // the layer type

    tops: Vec<String>, // the name of each top blob
    bottoms: Vec<String>, // the name of each bottom blob

    /// Specifies training parameters (multipliers on global learning constants,
    /// and the name and other settings used for weight sharing).
    params: Vec<ParamConfig>,

    /// Specifies on which bottoms the backpropagation should be skipped.
    /// The size must be either 0 or equal to the number of bottoms.
    pub propagate_down: Vec<bool>,

    // minimal, a lot of Caffe not ported yet
}

pub enum LayerType {
    SigmoidLayer,
}

impl LayerConfig {
    pub fn new(name: String, layer_type: LayerType) -> LayerConfig {
        LayerConfig {
            name: name,
            layer_type: layer_type,

            tops: Vec::new(),
            bottoms: Vec::new(),

            params: Vec::new(),
            propagate_down: Vec::new(),
        }
    }

    pub fn top(&self, top_id: usize) -> Option<&String> {
        self.tops.get(top_id)
    }
    pub fn tops_len(&self) -> usize {
        self.tops.len()
    }
    pub fn bottom(&self, bottom_id: usize) -> Option<&String> {
        self.bottoms.get(bottom_id)
    }
    pub fn bottoms_len(&self) -> usize {
        self.bottoms.len()
    }

    pub fn param(&self, param_id: usize) -> Option<&ParamConfig> {
        self.params.get(param_id)
    }
    pub fn params_len(&self) -> usize {
        self.params.len()
    }

    pub fn check_propagate_down_len(&self) -> bool {
        self.propagate_down.is_empty() || self.propagate_down.len() == self.bottoms.len()
    }
}

/// Specifies training parameters (multipliers on global learning constants,
/// and the name and other settings used for weight sharing).
pub struct ParamConfig {
    /// The names of the parameter blobs -- useful for sharing parameters among
    /// layers, but never required otherwise.  To share a parameter between two
    /// layers, give it a (non-empty) name.
    ///
    /// Default: ""
    pub name: String,
    /// Whether to require shared weights to have the same shape, or just the same
    /// count
    ///
    /// Default: DimCheckMode::Strict
    pub share_mode: DimCheckMode,

    /// The multiplier on the global learning rate for this parameter.
    ///
    /// Default: 1.0f32
    pub lr_mult: Option<f32>,

    /// The multiplier on the global weight decay for this parameter.
    ///
    /// Default: 1.0f32
    pub decay_mult: Option<f32>,
}

impl Default for ParamConfig {
    fn default() -> ParamConfig {
        ParamConfig {
            name: "".to_owned(),
            share_mode: DimCheckMode::Strict,
            lr_mult: None,
            decay_mult: None,
        }
    }
}

impl ParamConfig {
    /// Checks dimensions of two blobs according to the share_mode.
    /// Logs an error if there is a count/shape mismatch.
    pub fn check_dimensions<T>(&self, blob_one: &Blob<T>, blob_two: &Blob<T>, param_name: String, owner_name: String, layer_name: String) -> Result<(), String> {
        match self.share_mode {
            // Permissive dimension checking -- only check counts are the same.
            DimCheckMode::Permissive => {
                // TODO: needs capacity of blob instead of len; needs to be exposed in phloem
                if blob_one.len() != blob_two.len() {
                    return Err(format!("Cannot share param '{}' owned by layer '{}' with layer '{}';
                                count mismatch.
                                Owner layer param shape is {};
                                Sharing layer param shape is {}",
                                param_name,
                                owner_name,
                                layer_name,
                                blob_two.shape_string(),
                                blob_one.shape_string()));
                }
            },
            // Strict dimension checking -- all dims must be the same.
            DimCheckMode::Strict => {
                // TODO: check shape instead of shape_string; needs to be exposed in phloem
                if blob_one.shape_string() != blob_two.shape_string() {
                    return Err(format!("Cannot share param '{}' owned by layer '{}' with layer '{}';
                                shape mismatch.
                                Owner layer param shape is {};
                                Sharing layer expects param shape {}",
                                param_name,
                                owner_name,
                                layer_name,
                                blob_two.shape_string(),
                                blob_one.shape_string()));
                }
            },
        }
        Ok(())
    }

    /// The multiplier on the global learning rate for this parameter.
    pub fn lr_mult(&self) -> f32 {
        match self.lr_mult {
            Some(val) => val,
            None => 1.0f32,
        }
    }

    /// The multiplier on the global weight decay for this parameter.
    pub fn decay_mult(&self) -> f32 {
        match self.decay_mult {
            Some(val) => val,
            None => 1.0f32,
        }
    }
}

pub enum DimCheckMode {
    /// Strict requires that shapes match.
    Strict,
    /// Permissive requires only the count of weights to match.
    Permissive,
}

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

    fn new_layer_config() -> LayerConfig {
        LayerConfig::new("foo".to_owned(), LayerType::SigmoidLayer)
    }

    #[test]
    fn new_layer() {
        let cfg = new_layer_config();
        let layer = Layer::from_config(&cfg);
    }

    #[test]
    fn dim_check_strict() {
        let cfg = ParamConfig { share_mode: DimCheckMode::Strict, .. ParamConfig::default()};
        let blob_one = Blob::<f32>::of_shape(vec![2, 3, 3]);
        let blob_two = Blob::<f32>::of_shape(vec![3, 2, 3]);
        let param_name = "foo".to_owned();
        let owner_name = "owner".to_owned();
        let layer_name = "layer".to_owned();

        assert!(cfg.check_dimensions(&blob_one, &blob_one, param_name.clone(), owner_name.clone(), layer_name.clone()).is_ok());
        assert!(cfg.check_dimensions(&blob_one, &blob_two, param_name.clone(), owner_name.clone(), layer_name.clone()).is_err());
    }

    // #[test]
    fn dim_check_permissive() {
        let cfg = ParamConfig { share_mode: DimCheckMode::Permissive, .. ParamConfig::default()};
        let blob_one = Blob::<f32>::of_shape(vec![2, 3, 3]);
        let blob_two = Blob::<f32>::of_shape(vec![3, 2, 3]);
        let blob_three = Blob::<f32>::of_shape(vec![3, 10, 3]);
        let param_name = "foo".to_owned();
        let owner_name = "owner".to_owned();
        let layer_name = "layer".to_owned();

        assert!(cfg.check_dimensions(&blob_one, &blob_one, param_name.clone(), owner_name.clone(), layer_name.clone()).is_ok());
        assert!(cfg.check_dimensions(&blob_one, &blob_two, param_name.clone(), owner_name.clone(), layer_name.clone()).is_ok());
        assert!(cfg.check_dimensions(&blob_one, &blob_three, param_name.clone(), owner_name.clone(), layer_name.clone()).is_err());
        assert!(cfg.check_dimensions(&blob_two, &blob_three, param_name.clone(), owner_name.clone(), layer_name.clone()).is_err());
    }
}
<commit_msg>fix(dim_check): fixed layer dimension checking based on the new interface of phloem<commit_after>use math::*;
use phloem::{Numeric, Blob};
use shared_memory::*;
use layers::sigmoid_layer::SigmoidLayer;

pub struct Layer<'a> {
    pub config: Box<&'a LayerConfig>,
    pub worker: Box<ILayer>,

    /// The vector that indicates whether each top blob has a non-zero weight in
    /// the objective function.
    loss: Vec<f32>,

    /// The vector that stores shared references to the parameters in the form of blobs.
    pub blobs: Vec<ArcLock<HeapBlob>>,

    /// Vector indicating whether to compute the diff of each param blob. */
    param_propagate_down: Vec<bool>,
}

impl<'a> Layer<'a> {
    pub fn from_config(config: &'a LayerConfig) -> Layer {
        // let ref cl = config.clone();
        let cl = config.clone();
        let cfg = Box::<&'a LayerConfig>::new(cl);
        Layer {
            loss: Vec::new(),
            // top: Vec::new(),
            blobs: Vec::new(),

            param_propagate_down: Vec::new(),

            worker: Layer::worker_from_config(&cfg),
            config: cfg,
        }
    }

    fn worker_from_config(config: &LayerConfig) -> Box<ILayer> {
        match config.layer_type {
            LayerType::SigmoidLayer => Box::new(SigmoidLayer),
        }
    }

    /// Sets whether the layer should compute gradients w.r.t. a
    /// parameter at a particular index given by param_id.
    pub fn set_param_propagate_down(&mut self, param_id: usize, value: bool) {
        if self.param_propagate_down.len() <= param_id {
            self.param_propagate_down.resize(param_id + 1, true);
        }
        self.param_propagate_down[param_id] = value;

    }

    pub fn loss(&self, id: usize) -> Option<&f32> {
        self.loss.get(id)
    }
}

/// A Layer in a Neural Network that can handle forward and backward of a computation step.
pub trait ILayer {
    /// Compute the layer output.
    /// Uses the CPU.
    fn forward_cpu(&self, bottom: &[HeapBlob], top: &mut Vec<HeapBlob>);
    /// Compute the gradients for the bottom blobs
    /// if the corresponding value of propagate_down is true.
    /// Uses the CPU.
    fn backward_cpu(&self, top: &[HeapBlob], propagate_down: &[bool], bottom: &mut Vec<HeapBlob>);

    /// Compute the layer output using the currently set computation method (CPU).
    fn forward(&self, bottom: &[HeapBlob], top: &mut Vec<HeapBlob>) -> f32 {
        // Lock();
        // Reshape(bottom, top); // Reshape the layer to fit top & bottom blob
        let mut loss = 0f32;

        self.forward_cpu(bottom, top);

        for top_layer in top {
            // if (!this->loss(top_id)) { continue; } // Caffe
            // if !self.loss(top_layer) { continue; }
            // let count = (**top_layer).len();
            let data = top_layer.cpu_data();
            let loss_weights = top_layer.cpu_diff();

            loss += leaf_cpu_dot(data, loss_weights);
            // loss += leaf_cpu_dot(count, data, loss_weights);
        }

        // Unlock();

        loss
    }

    /// Return whether "anonymous" top blobs are created automatically for the layer.
    ///
    /// If this method returns true, Network::init will create enough "anonymous" top
    /// blobs to fulfill the requirement specified by exact_num_top_blobs() or
    /// min_top_blobs().
    fn auto_top_blobs(&self) -> bool {
        false
    }
    /// Returns the minimum number of top blobs required by the layer,
    /// or 0 if no minimum number is required.
    ///
    /// This method should be overridden to return a positive value if your
    /// layer expects some minimum number of top blobs.
    fn min_top_blobs(&self) -> usize {
        0
    }
    /// Returns the exact number of top blobs required by the layer,
    /// or 0 if no exact number is required.
    ///
    /// This method should be overridden to return a positive value if your
    /// layer expects some exact number of top blobs.
    fn exact_num_top_blobs(&self) -> usize {
        0
    }
    /// Returns the exact number of bottom blobs required by the layer,
    /// or 0 if no exact number is required.
    ///
    /// This method should be overridden to return a positive value if your
    /// layer expects some exact number of bottom blobs.
    fn exact_num_bottom_blobs(&self) -> usize {
        0
    }
    /// Return whether to allow force_backward for a given bottom blob index.
    ///
    /// If AllowForceBackward(i) == false, we will ignore the force_backward
    /// setting and backpropagate to blob i only if it needs gradient information
    /// (as is done when force_backward == false).
    fn allow_force_backward(&self, bottom_id: usize) -> bool {
        true
    }
}

pub struct LayerConfig {
    pub name: String, // the layer name
    layer_type: LayerType, // the layer type

    tops: Vec<String>, // the name of each top blob
    bottoms: Vec<String>, // the name of each bottom blob

    /// Specifies training parameters (multipliers on global learning constants,
    /// and the name and other settings used for weight sharing).
    params: Vec<ParamConfig>,

    /// Specifies on which bottoms the backpropagation should be skipped.
    /// The size must be either 0 or equal to the number of bottoms.
    pub propagate_down: Vec<bool>,

    // minimal, a lot of Caffe not ported yet
}

pub enum LayerType {
    SigmoidLayer,
}

impl LayerConfig {
    pub fn new(name: String, layer_type: LayerType) -> LayerConfig {
        LayerConfig {
            name: name,
            layer_type: layer_type,

            tops: Vec::new(),
            bottoms: Vec::new(),

            params: Vec::new(),
            propagate_down: Vec::new(),
        }
    }

    pub fn top(&self, top_id: usize) -> Option<&String> {
        self.tops.get(top_id)
    }
    pub fn tops_len(&self) -> usize {
        self.tops.len()
    }
    pub fn bottom(&self, bottom_id: usize) -> Option<&String> {
        self.bottoms.get(bottom_id)
    }
    pub fn bottoms_len(&self) -> usize {
        self.bottoms.len()
    }

    pub fn param(&self, param_id: usize) -> Option<&ParamConfig> {
        self.params.get(param_id)
    }
    pub fn params_len(&self) -> usize {
        self.params.len()
    }

    pub fn check_propagate_down_len(&self) -> bool {
        self.propagate_down.is_empty() || self.propagate_down.len() == self.bottoms.len()
    }
}

/// Specifies training parameters (multipliers on global learning constants,
/// and the name and other settings used for weight sharing).
pub struct ParamConfig {
    /// The names of the parameter blobs -- useful for sharing parameters among
    /// layers, but never required otherwise.  To share a parameter between two
    /// layers, give it a (non-empty) name.
    ///
    /// Default: ""
    pub name: String,
    /// Whether to require shared weights to have the same shape, or just the same
    /// count
    ///
    /// Default: DimCheckMode::Strict
    pub share_mode: DimCheckMode,

    /// The multiplier on the global learning rate for this parameter.
    ///
    /// Default: 1.0f32
    pub lr_mult: Option<f32>,

    /// The multiplier on the global weight decay for this parameter.
    ///
    /// Default: 1.0f32
    pub decay_mult: Option<f32>,
}

impl Default for ParamConfig {
    fn default() -> ParamConfig {
        ParamConfig {
            name: "".to_owned(),
            share_mode: DimCheckMode::Strict,
            lr_mult: None,
            decay_mult: None,
        }
    }
}

impl ParamConfig {
    /// Checks dimensions of two blobs according to the share_mode.
    /// Logs an error if there is a count/shape mismatch.
    pub fn check_dimensions<T: Numeric>(&self, blob_one: &Blob<T>, blob_two: &Blob<T>, param_name: String, owner_name: String, layer_name: String) -> Result<(), String> {
        match self.share_mode {
            // Permissive dimension checking -- only check counts are the same.
            DimCheckMode::Permissive => {
                if blob_one.capacity() != blob_two.capacity() {
                    return Err(format!("Cannot share param '{}' owned by layer '{}' with layer '{}';
                                count mismatch.
                                Owner layer param shape is {};
                                Sharing layer param shape is {}",
                                param_name,
                                owner_name,
                                layer_name,
                                blob_two.shape_string(),
                                blob_one.shape_string()));
                }
            },
            // Strict dimension checking -- all dims must be the same.
            DimCheckMode::Strict => {
                if blob_one.shape() != blob_two.shape() {
                    return Err(format!("Cannot share param '{}' owned by layer '{}' with layer '{}';
                                shape mismatch.
                                Owner layer param shape is {};
                                Sharing layer expects param shape {}",
                                param_name,
                                owner_name,
                                layer_name,
                                blob_two.shape_string(),
                                blob_one.shape_string()));
                }
            },
        }
        Ok(())
    }

    /// The multiplier on the global learning rate for this parameter.
    pub fn lr_mult(&self) -> f32 {
        match self.lr_mult {
            Some(val) => val,
            None => 1.0f32,
        }
    }

    /// The multiplier on the global weight decay for this parameter.
    pub fn decay_mult(&self) -> f32 {
        match self.decay_mult {
            Some(val) => val,
            None => 1.0f32,
        }
    }
}

pub enum DimCheckMode {
    /// Strict requires that shapes match.
    Strict,
    /// Permissive requires only the count of weights to match.
    Permissive,
}

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

    fn new_layer_config() -> LayerConfig {
        LayerConfig::new("foo".to_owned(), LayerType::SigmoidLayer)
    }

    #[test]
    fn new_layer() {
        let cfg = new_layer_config();
        let layer = Layer::from_config(&cfg);
    }

    #[test]
    fn dim_check_strict() {
        let cfg = ParamConfig { share_mode: DimCheckMode::Strict, .. ParamConfig::default()};
        let blob_one = Blob::<f32>::of_shape(vec![2, 3, 3]);
        let blob_two = Blob::<f32>::of_shape(vec![3, 2, 3]);
        let param_name = "foo".to_owned();
        let owner_name = "owner".to_owned();
        let layer_name = "layer".to_owned();

        assert!(cfg.check_dimensions(&blob_one, &blob_one, param_name.clone(), owner_name.clone(), layer_name.clone()).is_ok());
        assert!(cfg.check_dimensions(&blob_one, &blob_two, param_name.clone(), owner_name.clone(), layer_name.clone()).is_err());
    }

    #[test]
    fn dim_check_permissive() {
        let cfg = ParamConfig { share_mode: DimCheckMode::Permissive, .. ParamConfig::default()};
        let blob_one = Blob::<f32>::of_shape(vec![2, 3, 3]);
        let blob_two = Blob::<f32>::of_shape(vec![3, 2, 3]);
        let blob_three = Blob::<f32>::of_shape(vec![3, 10, 3]);
        let param_name = "foo".to_owned();
        let owner_name = "owner".to_owned();
        let layer_name = "layer".to_owned();

        assert!(cfg.check_dimensions(&blob_one, &blob_one, param_name.clone(), owner_name.clone(), layer_name.clone()).is_ok());
        assert!(cfg.check_dimensions(&blob_one, &blob_two, param_name.clone(), owner_name.clone(), layer_name.clone()).is_ok());
        assert!(cfg.check_dimensions(&blob_one, &blob_three, param_name.clone(), owner_name.clone(), layer_name.clone()).is_err());
        assert!(cfg.check_dimensions(&blob_two, &blob_three, param_name.clone(), owner_name.clone(), layer_name.clone()).is_err());
    }
}
<|endoftext|>


<commit_before>// mrusty. mruby bindings for Rust
// Copyright (C) 2016  Dragoș Tiselice
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use super::mruby_ffi::*;

/// A safe `struct` for the mruby API.
///
/// # Examples
///
/// ```
/// # use mrusty::MRuby;
/// let mruby = MRuby::new();
/// let result = mruby.run("2 + 2 == 5").unwrap();
///
/// assert_eq!(result.to_bool().unwrap(), false);
/// ```
#[derive(Debug)]
pub struct MRuby {
    mrb: *mut MRState,
    ctx: *mut MRContext
}

impl MRuby {
    /// Creates an mruby state and context stored in a `struct`.
    ///
    /// # Example
    ///
    /// ```
    /// # use mrusty::MRuby;
    /// let mruby = MRuby::new();
    /// ```
    pub fn new() -> MRuby {
        unsafe {
            let mrb = mrb_open();

            MRuby {
                mrb: mrb,
                ctx: mrbc_context_new(mrb)
            }
        }
    }

    fn close(&self) {
        unsafe {
            mrb_close(self.mrb);
        }
    }

    /// Runs mruby `script` on a state and context and returns a `Value` in an `Ok`
    /// or an `Err` containing an mruby exception.
    ///
    /// # Examples
    ///
    /// ```
    /// # use mrusty::MRuby;
    /// let mruby = MRuby::new();
    /// let result = mruby.run("true").unwrap();
    ///
    /// assert_eq!(result.to_bool().unwrap(), true);
    /// ```
    ///
    /// ```
    /// # use mrusty::MRuby;
    /// let mruby = MRuby::new();
    /// let result = mruby.run("'' + 1");
    ///
    /// assert_eq!(result, Err("TypeError: expected String"));
    /// ```
    pub fn run(&self, script: &str) -> Result<Value, &str> {
        unsafe {
            let value = mrb_load_string_cxt(self.mrb, (script.to_string() + "\0").as_ptr(), self.ctx);
            let exc = mrb_ext_get_exc(self.mrb);

            match exc.typ {
                MRType::MRB_TT_STRING => Err(exc.to_str(self.mrb).unwrap()),
                _                     => Ok(Value::new(self.mrb, value))
            }
        }
    }
}

impl Drop for MRuby {
    fn drop(&mut self) {
        self.close();
    }
}

#[derive(Clone, Copy, Debug, Eq)]
pub struct Value {
    mrb: *mut MRState,
    value: MRValue
}

impl Value {
    fn new(mrb: *mut MRState, value: MRValue) -> Value {
        Value {
            mrb: mrb,
            value: value
        }
    }

    /// Casts a `Value` and returns a `bool` in an `Ok` or an `Err` if the types mismatch.
    ///
    /// # Example
    ///
    /// ```
    /// # use mrusty::MRuby;
    /// let mruby = MRuby::new();
    /// let result = mruby.run("
    ///   def pos(n)
    ///     n > 0
    ///   end
    ///
    ///   pos 1
    /// ").unwrap();
    ///
    /// assert_eq!(result.to_bool().unwrap(), true);
    /// ```
    pub fn to_bool(&self) -> Result<bool, &str> {
        unsafe {
            self.value.to_bool()
        }
    }

    /// Casts a `Value` and returns an `i32` in an `Ok` or an `Err` if the types mismatch.
    ///
    /// # Example
    ///
    /// ```
    /// # use mrusty::MRuby;
    /// let mruby = MRuby::new();
    /// let result = mruby.run("
    ///   def fact(n)
    ///     n > 1 ? fact(n - 1) * n : 1
    ///   end
    ///
    ///   fact 5
    /// ").unwrap();
    ///
    /// assert_eq!(result.to_i32().unwrap(), 120);
    /// ```
    pub fn to_i32(&self) -> Result<i32, &str> {
        unsafe {
            self.value.to_i32()
        }
    }
}

impl PartialEq<Value> for Value {
    fn eq(&self, other: &Value) -> bool {
        self.value.eq(&other.value)
    }
}
<commit_msg>Added f64 and &str casting.<commit_after>// mrusty. mruby bindings for Rust
// Copyright (C) 2016  Dragoș Tiselice
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use super::mruby_ffi::*;

/// A safe `struct` for the mruby API.
///
/// # Examples
///
/// ```
/// # use mrusty::MRuby;
/// let mruby = MRuby::new();
/// let result = mruby.run("2 + 2 == 5").unwrap();
///
/// assert_eq!(result.to_bool().unwrap(), false);
/// ```
#[derive(Debug)]
pub struct MRuby {
    mrb: *mut MRState,
    ctx: *mut MRContext
}

impl MRuby {
    /// Creates an mruby state and context stored in a `struct`.
    ///
    /// # Example
    ///
    /// ```
    /// # use mrusty::MRuby;
    /// let mruby = MRuby::new();
    /// ```
    pub fn new() -> MRuby {
        unsafe {
            let mrb = mrb_open();

            MRuby {
                mrb: mrb,
                ctx: mrbc_context_new(mrb)
            }
        }
    }

    fn close(&self) {
        unsafe {
            mrb_close(self.mrb);
        }
    }

    /// Runs mruby `script` on a state and context and returns a `Value` in an `Ok`
    /// or an `Err` containing an mruby exception.
    ///
    /// # Examples
    ///
    /// ```
    /// # use mrusty::MRuby;
    /// let mruby = MRuby::new();
    /// let result = mruby.run("true").unwrap();
    ///
    /// assert_eq!(result.to_bool().unwrap(), true);
    /// ```
    ///
    /// ```
    /// # use mrusty::MRuby;
    /// let mruby = MRuby::new();
    /// let result = mruby.run("'' + 1");
    ///
    /// assert_eq!(result, Err("TypeError: expected String"));
    /// ```
    pub fn run(&self, script: &str) -> Result<Value, &str> {
        unsafe {
            let value = mrb_load_string_cxt(self.mrb, (script.to_string() + "\0").as_ptr(), self.ctx);
            let exc = mrb_ext_get_exc(self.mrb);

            match exc.typ {
                MRType::MRB_TT_STRING => Err(exc.to_str(self.mrb).unwrap()),
                _                     => Ok(Value::new(self.mrb, value))
            }
        }
    }
}

impl Drop for MRuby {
    fn drop(&mut self) {
        self.close();
    }
}

#[derive(Clone, Copy, Debug, Eq)]
pub struct Value {
    mrb: *mut MRState,
    value: MRValue
}

impl Value {
    fn new(mrb: *mut MRState, value: MRValue) -> Value {
        Value {
            mrb: mrb,
            value: value
        }
    }

    /// Casts a `Value` and returns a `bool` in an `Ok` or an `Err` if the types mismatch.
    ///
    /// # Example
    ///
    /// ```
    /// # use mrusty::MRuby;
    /// let mruby = MRuby::new();
    /// let result = mruby.run("
    ///   def pos(n)
    ///     n > 0
    ///   end
    ///
    ///   pos 1
    /// ").unwrap();
    ///
    /// assert_eq!(result.to_bool().unwrap(), true);
    /// ```
    pub fn to_bool(&self) -> Result<bool, &str> {
        unsafe {
            self.value.to_bool()
        }
    }

    /// Casts a `Value` and returns an `i32` in an `Ok` or an `Err` if the types mismatch.
    ///
    /// # Example
    ///
    /// ```
    /// # use mrusty::MRuby;
    /// let mruby = MRuby::new();
    /// let result = mruby.run("
    ///   def fact(n)
    ///     n > 1 ? fact(n - 1) * n : 1
    ///   end
    ///
    ///   fact 5
    /// ").unwrap();
    ///
    /// assert_eq!(result.to_i32().unwrap(), 120);
    /// ```
    pub fn to_i32(&self) -> Result<i32, &str> {
        unsafe {
            self.value.to_i32()
        }
    }

    /// Casts a `Value` and returns an `f64` in an `Ok` or an `Err` if the types mismatch.
    ///
    /// # Example
    ///
    /// ```
    /// # use mrusty::MRuby;
    /// let mruby = MRuby::new();
    /// let result = mruby.run("
    ///   3 / 2.0
    /// ").unwrap();
    ///
    /// assert_eq!(result.to_f64().unwrap(), 1.5);
    /// ```
    pub fn to_f64(&self) -> Result<f64, &str> {
        unsafe {
            self.value.to_f64()
        }
    }

    /// Casts a `Value` and returns a `&str` in an `Ok` or an `Err` if the types mismatch.
    ///
    /// # Example
    ///
    /// ```
    /// # use mrusty::MRuby;
    /// let mruby = MRuby::new();
    /// let result = mruby.run("
    ///   [1, 2, 3].map(&:to_s).join
    /// ").unwrap();
    ///
    /// assert_eq!(result.to_str().unwrap(), "123");
    /// ```
    pub fn to_str<'a>(&self) -> Result<&'a str, &str> {
        unsafe {
            self.value.to_str(self.mrb)
        }
    }
}

impl PartialEq<Value> for Value {
    fn eq(&self, other: &Value) -> bool {
        self.value.eq(&other.value)
    }
}
<|endoftext|>


<commit_before>use std::cmp::{self, Ordering};
use std::f32;
use std::convert::From;
use rand::Rng;
use std::ops::Sub;
use super::selection::tournament_selection_fast;

pub trait Mate<T> {
    fn mate<R: Rng>(&mut self, rng: &mut R, p1: &T, p2: &T) -> T;
}

pub trait Dominate<Rhs=Self> {
    fn dominates(&self, other: &Rhs) -> bool;
}

fn dominates_slices<T: Sized + PartialOrd>(sa: &[T], sb: &[T]) -> bool {
    assert!(sa.len() == sb.len());
    assert!(sa.len() > 0);

    let mut less_cnt = 0;
    for (a, b) in sa.iter().zip(sb.iter()) {
        if a > b {
            return false;
        } else if a < b {
            less_cnt += 1;
        }
    }

    return less_cnt > 0;
}

pub trait MultiObjective {
    fn num_objectives() -> usize;

    fn cmp_objective(&self, other: &Self, objective: usize) -> Ordering;

    // Distance between self and other
    fn dist_objective(&self, other: &Self, objective: usize) -> f32;
}

#[derive(Debug, Clone)]
pub struct MultiObjective2<T>
    where T: Sized + PartialOrd + Copy + Clone
{
    pub objectives: [T; 2],
}

impl<T:Sized+PartialOrd+Copy+Clone> From<(T, T)> for MultiObjective2<T> {
    fn from(t: (T, T)) -> MultiObjective2<T> {
        MultiObjective2 { objectives: [t.0, t.1] }
    }
}

impl<T,R> MultiObjective for MultiObjective2<T>
where T: Copy + PartialOrd + Sub<Output=R>,
      R: Into<f32> {
    fn num_objectives() -> usize {
        2
    }
    fn cmp_objective(&self, other: &Self, objective: usize) -> Ordering {
        self.objectives[objective].partial_cmp(&other.objectives[objective]).unwrap()
    }
    fn dist_objective(&self, other: &Self, objective: usize) -> f32 {
        (self.objectives[objective] - other.objectives[objective]).into()
    }
}

impl<T:Sized+PartialOrd+Copy> Dominate for MultiObjective2<T> {
    fn dominates(&self, other: &Self) -> bool {
        dominates_slices(&self.objectives[..], &other.objectives[..])
    }
}

#[derive(Debug, Clone)]
pub struct MultiObjective3<T>
    where T: Sized + PartialOrd + Copy + Clone
{
    pub objectives: [T; 3],
}

impl<T:Sized+PartialOrd+Copy+Clone> From<(T, T, T)> for MultiObjective3<T> {
    fn from(t: (T, T, T)) -> MultiObjective3<T> {
        MultiObjective3 { objectives: [t.0, t.1, t.2] }
    }
}

impl<T,R> MultiObjective for MultiObjective3<T>
where T: Copy + PartialOrd + Sub<Output=R>,
      R: Into<f32> {
    fn num_objectives() -> usize {
        3
    }
    fn cmp_objective(&self, other: &Self, objective: usize) -> Ordering {
        self.objectives[objective].partial_cmp(&other.objectives[objective]).unwrap()
    }
    fn dist_objective(&self, other: &Self, objective: usize) -> f32 {
        (self.objectives[objective] - other.objectives[objective]).into()
    }
}

impl<T:Sized+PartialOrd+Copy> Dominate for MultiObjective3<T> {
    fn dominates(&self, other: &Self) -> bool {
        dominates_slices(&self.objectives[..], &other.objectives[..])
    }
}

/// Stop after we have found `n` solutions (we include the whole pareto front, so it are probably more solutions).
fn fast_non_dominated_sort<P: Dominate>(solutions: &[P], n: usize) -> Vec<Vec<usize>> {
    let mut fronts: Vec<Vec<usize>> = Vec::new();
    let mut current_front = Vec::new();

    let mut domination_count: Vec<usize> = (0..solutions.len()).map(|_| 0).collect();
    let mut dominated_solutions: Vec<Vec<usize>> = (0..solutions.len())
                                                       .map(|_| Vec::new())
                                                       .collect();
    let mut found_solutions: usize = 0;

    for (i, p) in solutions.iter().enumerate() {
        for (j, q) in solutions.iter().enumerate() {
            if i == j {
                continue;
            }
            if p.dominates(q) {
                // Add `q` to the set of solutions dominated by `p`.
                dominated_solutions[i].push(j);
            } else if q.dominates(p) {
                // Increment domination counter of `p`.
                domination_count[i] += 1;
            }
        }

        if domination_count[i] == 0 {
            // `p` belongs to the first front as it is not dominated by any
            // other solution.
            current_front.push(i);
        }
    }

    while !current_front.is_empty() {
        found_solutions += current_front.len();
        if found_solutions >= n {
            fronts.push(current_front);
            break;
        } else {
            // we haven't found enough solutions yet.
            let mut next_front = Vec::new();
            for &p_i in current_front.iter() {
                for &q_i in dominated_solutions[p_i].iter() {
                    domination_count[q_i] -= 1;
                    if domination_count[q_i] == 0 {
                        // q belongs to the next front
                        next_front.push(q_i);
                    }
                }
            }
            fronts.push(current_front);
            current_front = next_front;
        }
    }

    return fronts;
}

#[derive(Debug)]
pub struct SolutionRankDist {
    pub idx: usize,
    pub rank: u32,
    pub dist: f32,
}

impl PartialEq for SolutionRankDist {
    #[inline]
    fn eq(&self, other: &SolutionRankDist) -> bool {
        self.rank == other.rank && self.dist == other.dist
    }
}

// Implement the crowding-distance comparison operator.
impl PartialOrd for SolutionRankDist {
    #[inline]
    // compare on rank first (ASC), then on dist (DESC)
    fn partial_cmp(&self, other: &SolutionRankDist) -> Option<Ordering> {
        match self.rank.partial_cmp(&other.rank) {
            Some(Ordering::Equal) => {
                // first criterion equal, second criterion decides
                // reverse ordering
                self.dist.partial_cmp(&other.dist).map(|i| i.reverse())
            }
            other => {
                other
            }
        }
    }
}

fn crowding_distance_assignment<P: MultiObjective>(solutions: &[P],
                                                   common_rank: u32,
                                                   individuals_idx: &[usize])
                                                   -> Vec<SolutionRankDist> {
    let l = individuals_idx.len();
    let mut distance: Vec<f32> = (0..l).map(|_| 0.0).collect();
    let mut indices: Vec<usize> = (0..l).map(|i| i).collect();

    for m in 0..P::num_objectives() {
        // sort using objective `m`
        indices.sort_by(|&a, &b| {
            solutions[individuals_idx[a]].cmp_objective(&solutions[individuals_idx[b]], m)
        });
        distance[indices[0]] = f32::INFINITY;
        distance[indices[l - 1]] = f32::INFINITY;

        let min_idx = individuals_idx[indices[0]];
        let max_idx = individuals_idx[indices[l - 1]];

        let dist_max_min = solutions[max_idx].dist_objective(&solutions[min_idx], m);
        if dist_max_min != 0.0 {
            let norm = P::num_objectives() as f32 * dist_max_min;
            debug_assert!(norm != 0.0);
            for i in 1..(l - 1) {
                let next_idx = individuals_idx[indices[i + 1]];
                let prev_idx = individuals_idx[indices[i - 1]];
                distance[indices[i]] += solutions[next_idx]
                                            .dist_objective(&solutions[prev_idx], m) /
                                        norm;
            }
        }
    }

    return indices.iter()
                  .map(|&i| {
                      SolutionRankDist {
                          idx: individuals_idx[i],
                          rank: common_rank,
                          dist: distance[i],
                      }
                  })
                  .collect();
}

/// Select `n` out of the `solutions`, assigning rank and distance.
pub fn select<P: Dominate + MultiObjective>(solutions: &[P], n: usize) -> Vec<SolutionRankDist> {
    let mut selection = Vec::with_capacity(cmp::min(solutions.len(), n));

    let pareto_fronts = fast_non_dominated_sort(solutions, n);

    for (rank, front) in pareto_fronts.iter().enumerate() {
        if selection.len() >= n {
            break;
        }
        let missing: usize = n - selection.len();

        let mut solution_rank_dist = crowding_distance_assignment(solutions,
                                                                  rank as u32,
                                                                  &front[..]);
        if solution_rank_dist.len() <= missing {
            // whole front fits into result.
            selection.extend(solution_rank_dist);
            assert!(selection.len() <= n);
        } else {
            // choose only best from this front, according to the crowding distance.
            solution_rank_dist.sort_by(|a, b| {
                debug_assert!(a.rank == b.rank);
                a.partial_cmp(b).unwrap()
            });
            selection.extend(solution_rank_dist.into_iter().take(missing));
            assert!(selection.len() == n);
            break;
        }
    }

    return selection;
}

pub trait FitnessEval<I, F:Dominate+MultiObjective+Clone> {
    fn fitness(&mut self, &[I]) -> Vec<F>;
}

pub fn iterate<R: Rng,
               I: Clone,
               M: Mate<I>,
               F: Dominate + MultiObjective + Clone,
               E: FitnessEval<I, F>>
    (rng: &mut R,
     population: Vec<I>,
     fitness: Vec<F>,
     fitness_eval: &mut E,
     pop_size: usize,
     offspring_size: usize,
     tournament_k: usize,
     mating: &mut M)
     -> (Vec<I>, Vec<F>) {
    assert!(tournament_k > 0);
    assert!(population.len() == fitness.len());

    // evaluate rank and crowding distance (using select()).
    let rank_dist = select(&fitness[..], pop_size);
    assert!(rank_dist.len() == pop_size);

    // create `offspring_size` new offspring using k-tournament (
    // select the best individual out of k randomly choosen individuals)
    let offspring: Vec<_> = (0..offspring_size)
                                .map(|_| {

                                    // first parent. k candidates
                                    let p1 = tournament_selection_fast(rng,
                                                                       |i1, i2| {
                                                                           rank_dist[i1] <
                                                                           rank_dist[i2]
                                                                       },
                                                                       rank_dist.len(),
                                                                       tournament_k);

                                    // second parent. k candidates
                                    let p2 = tournament_selection_fast(rng,
                                                                       |i1, i2| {
                                                                           rank_dist[i1] <
                                                                           rank_dist[i2]
                                                                       },
                                                                       rank_dist.len(),
                                                                       tournament_k);

                                    // cross-over the two parents and produce one child (throw away
                                    // second child)
                                    mating.mate(rng, &population[p1], &population[p2])
                                })
                                .collect();

    assert!(offspring.len() == offspring_size);

    // evaluate fitness of offspring
    let fitness_offspring = fitness_eval.fitness(&offspring[..]);
    assert!(fitness_offspring.len() == offspring.len());

    // merge population and offspring, then select
    let mut new_pop = Vec::with_capacity(rank_dist.len() + offspring.len());
    let mut new_fit = Vec::with_capacity(rank_dist.len() + offspring.len());
    for rd in rank_dist {
        new_pop.push(population[rd.idx].clone());
        new_fit.push(fitness[rd.idx].clone());
    }

    new_pop.extend(offspring);
    new_fit.extend(fitness_offspring);

    assert!(new_pop.len() == pop_size + offspring_size);
    assert!(new_fit.len() == pop_size + offspring_size);

    return (new_pop, new_fit);
}

#[test]
fn test_dominates() {
    let a = MultiObjective2 { objectives: [1.0, 0.1] };
    let b = MultiObjective2 { objectives: [0.1, 0.1] };
    let c = MultiObjective2 { objectives: [0.1, 1.0] };

    assert_eq!(false, a.dominates(&a));
    assert_eq!(false, a.dominates(&b));
    assert_eq!(false, a.dominates(&c));

    assert_eq!(true, b.dominates(&a));
    assert_eq!(false, b.dominates(&b));
    assert_eq!(true, b.dominates(&c));

    assert_eq!(false, c.dominates(&a));
    assert_eq!(false, c.dominates(&b));
    assert_eq!(false, c.dominates(&c));
}

#[test]
fn test_abc() {
    let mut solutions: Vec<MultiObjective2<f32>> = Vec::new();
    solutions.push(MultiObjective2 { objectives: [1.0, 0.1] });
    solutions.push(MultiObjective2 { objectives: [0.1, 0.1] });
    solutions.push(MultiObjective2 { objectives: [0.1, 1.0] });
    solutions.push(MultiObjective2 { objectives: [0.5, 0.5] });
    solutions.push(MultiObjective2 { objectives: [0.5, 0.5] });

    println!("solutions: {:?}", solutions);
    let selection = select(&solutions[..], 5);
    println!("selection: {:?}", selection);

    let fronts = fast_non_dominated_sort(&solutions[..], 10);
    println!("solutions: {:?}", solutions);
    println!("fronts: {:?}", fronts);

    for (rank, front) in fronts.iter().enumerate() {
        let distances = crowding_distance_assignment(&solutions[..], rank as u32, &front[..]);
        println!("front: {:?}", front);
        println!("distances: {:?}", distances);
    }
}
<commit_msg>Pass the potentially dominating individual as first parameter to mate()<commit_after>use std::cmp::{self, Ordering};
use std::f32;
use std::convert::From;
use rand::Rng;
use std::ops::Sub;
use super::selection::tournament_selection_fast;

pub trait Mate<T> {
    fn mate<R: Rng>(&mut self, rng: &mut R, p1: &T, p2: &T) -> T;
}

pub trait Dominate<Rhs=Self> {
    fn dominates(&self, other: &Rhs) -> bool;
}

fn dominates_slices<T: Sized + PartialOrd>(sa: &[T], sb: &[T]) -> bool {
    assert!(sa.len() == sb.len());
    assert!(sa.len() > 0);

    let mut less_cnt = 0;
    for (a, b) in sa.iter().zip(sb.iter()) {
        if a > b {
            return false;
        } else if a < b {
            less_cnt += 1;
        }
    }

    return less_cnt > 0;
}

pub trait MultiObjective {
    fn num_objectives() -> usize;

    fn cmp_objective(&self, other: &Self, objective: usize) -> Ordering;

    // Distance between self and other
    fn dist_objective(&self, other: &Self, objective: usize) -> f32;
}

#[derive(Debug, Clone)]
pub struct MultiObjective2<T>
    where T: Sized + PartialOrd + Copy + Clone
{
    pub objectives: [T; 2],
}

impl<T:Sized+PartialOrd+Copy+Clone> From<(T, T)> for MultiObjective2<T> {
    fn from(t: (T, T)) -> MultiObjective2<T> {
        MultiObjective2 { objectives: [t.0, t.1] }
    }
}

impl<T,R> MultiObjective for MultiObjective2<T>
where T: Copy + PartialOrd + Sub<Output=R>,
      R: Into<f32> {
    fn num_objectives() -> usize {
        2
    }
    fn cmp_objective(&self, other: &Self, objective: usize) -> Ordering {
        self.objectives[objective].partial_cmp(&other.objectives[objective]).unwrap()
    }
    fn dist_objective(&self, other: &Self, objective: usize) -> f32 {
        (self.objectives[objective] - other.objectives[objective]).into()
    }
}

impl<T:Sized+PartialOrd+Copy> Dominate for MultiObjective2<T> {
    fn dominates(&self, other: &Self) -> bool {
        dominates_slices(&self.objectives[..], &other.objectives[..])
    }
}

#[derive(Debug, Clone)]
pub struct MultiObjective3<T>
    where T: Sized + PartialOrd + Copy + Clone
{
    pub objectives: [T; 3],
}

impl<T:Sized+PartialOrd+Copy+Clone> From<(T, T, T)> for MultiObjective3<T> {
    fn from(t: (T, T, T)) -> MultiObjective3<T> {
        MultiObjective3 { objectives: [t.0, t.1, t.2] }
    }
}

impl<T,R> MultiObjective for MultiObjective3<T>
where T: Copy + PartialOrd + Sub<Output=R>,
      R: Into<f32> {
    fn num_objectives() -> usize {
        3
    }
    fn cmp_objective(&self, other: &Self, objective: usize) -> Ordering {
        self.objectives[objective].partial_cmp(&other.objectives[objective]).unwrap()
    }
    fn dist_objective(&self, other: &Self, objective: usize) -> f32 {
        (self.objectives[objective] - other.objectives[objective]).into()
    }
}

impl<T:Sized+PartialOrd+Copy> Dominate for MultiObjective3<T> {
    fn dominates(&self, other: &Self) -> bool {
        dominates_slices(&self.objectives[..], &other.objectives[..])
    }
}

/// Stop after we have found `n` solutions (we include the whole pareto front, so it are probably more solutions).
fn fast_non_dominated_sort<P: Dominate>(solutions: &[P], n: usize) -> Vec<Vec<usize>> {
    let mut fronts: Vec<Vec<usize>> = Vec::new();
    let mut current_front = Vec::new();

    let mut domination_count: Vec<usize> = (0..solutions.len()).map(|_| 0).collect();
    let mut dominated_solutions: Vec<Vec<usize>> = (0..solutions.len())
                                                       .map(|_| Vec::new())
                                                       .collect();
    let mut found_solutions: usize = 0;

    for (i, p) in solutions.iter().enumerate() {
        for (j, q) in solutions.iter().enumerate() {
            if i == j {
                continue;
            }
            if p.dominates(q) {
                // Add `q` to the set of solutions dominated by `p`.
                dominated_solutions[i].push(j);
            } else if q.dominates(p) {
                // Increment domination counter of `p`.
                domination_count[i] += 1;
            }
        }

        if domination_count[i] == 0 {
            // `p` belongs to the first front as it is not dominated by any
            // other solution.
            current_front.push(i);
        }
    }

    while !current_front.is_empty() {
        found_solutions += current_front.len();
        if found_solutions >= n {
            fronts.push(current_front);
            break;
        } else {
            // we haven't found enough solutions yet.
            let mut next_front = Vec::new();
            for &p_i in current_front.iter() {
                for &q_i in dominated_solutions[p_i].iter() {
                    domination_count[q_i] -= 1;
                    if domination_count[q_i] == 0 {
                        // q belongs to the next front
                        next_front.push(q_i);
                    }
                }
            }
            fronts.push(current_front);
            current_front = next_front;
        }
    }

    return fronts;
}

#[derive(Debug)]
pub struct SolutionRankDist {
    pub idx: usize,
    pub rank: u32,
    pub dist: f32,
}

impl PartialEq for SolutionRankDist {
    #[inline]
    fn eq(&self, other: &SolutionRankDist) -> bool {
        self.rank == other.rank && self.dist == other.dist
    }
}

// Implement the crowding-distance comparison operator.
impl PartialOrd for SolutionRankDist {
    #[inline]
    // compare on rank first (ASC), then on dist (DESC)
    fn partial_cmp(&self, other: &SolutionRankDist) -> Option<Ordering> {
        match self.rank.partial_cmp(&other.rank) {
            Some(Ordering::Equal) => {
                // first criterion equal, second criterion decides
                // reverse ordering
                self.dist.partial_cmp(&other.dist).map(|i| i.reverse())
            }
            other => {
                other
            }
        }
    }
}

fn crowding_distance_assignment<P: MultiObjective>(solutions: &[P],
                                                   common_rank: u32,
                                                   individuals_idx: &[usize])
                                                   -> Vec<SolutionRankDist> {
    let l = individuals_idx.len();
    let mut distance: Vec<f32> = (0..l).map(|_| 0.0).collect();
    let mut indices: Vec<usize> = (0..l).map(|i| i).collect();

    for m in 0..P::num_objectives() {
        // sort using objective `m`
        indices.sort_by(|&a, &b| {
            solutions[individuals_idx[a]].cmp_objective(&solutions[individuals_idx[b]], m)
        });
        distance[indices[0]] = f32::INFINITY;
        distance[indices[l - 1]] = f32::INFINITY;

        let min_idx = individuals_idx[indices[0]];
        let max_idx = individuals_idx[indices[l - 1]];

        let dist_max_min = solutions[max_idx].dist_objective(&solutions[min_idx], m);
        if dist_max_min != 0.0 {
            let norm = P::num_objectives() as f32 * dist_max_min;
            debug_assert!(norm != 0.0);
            for i in 1..(l - 1) {
                let next_idx = individuals_idx[indices[i + 1]];
                let prev_idx = individuals_idx[indices[i - 1]];
                distance[indices[i]] += solutions[next_idx]
                                            .dist_objective(&solutions[prev_idx], m) /
                                        norm;
            }
        }
    }

    return indices.iter()
                  .map(|&i| {
                      SolutionRankDist {
                          idx: individuals_idx[i],
                          rank: common_rank,
                          dist: distance[i],
                      }
                  })
                  .collect();
}

/// Select `n` out of the `solutions`, assigning rank and distance.
pub fn select<P: Dominate + MultiObjective>(solutions: &[P], n: usize) -> Vec<SolutionRankDist> {
    let mut selection = Vec::with_capacity(cmp::min(solutions.len(), n));

    let pareto_fronts = fast_non_dominated_sort(solutions, n);

    for (rank, front) in pareto_fronts.iter().enumerate() {
        if selection.len() >= n {
            break;
        }
        let missing: usize = n - selection.len();

        let mut solution_rank_dist = crowding_distance_assignment(solutions,
                                                                  rank as u32,
                                                                  &front[..]);
        if solution_rank_dist.len() <= missing {
            // whole front fits into result.
            selection.extend(solution_rank_dist);
            assert!(selection.len() <= n);
        } else {
            // choose only best from this front, according to the crowding distance.
            solution_rank_dist.sort_by(|a, b| {
                debug_assert!(a.rank == b.rank);
                a.partial_cmp(b).unwrap()
            });
            selection.extend(solution_rank_dist.into_iter().take(missing));
            assert!(selection.len() == n);
            break;
        }
    }

    return selection;
}

pub trait FitnessEval<I, F:Dominate+MultiObjective+Clone> {
    fn fitness(&mut self, &[I]) -> Vec<F>;
}

pub fn iterate<R: Rng,
               I: Clone,
               M: Mate<I>,
               F: Dominate + MultiObjective + Clone,
               E: FitnessEval<I, F>>
    (rng: &mut R,
     population: Vec<I>,
     fitness: Vec<F>,
     fitness_eval: &mut E,
     pop_size: usize,
     offspring_size: usize,
     tournament_k: usize,
     mating: &mut M)
     -> (Vec<I>, Vec<F>) {
    assert!(tournament_k > 0);
    assert!(population.len() == fitness.len());

    // evaluate rank and crowding distance (using select()).
    let rank_dist = select(&fitness[..], pop_size);
    assert!(rank_dist.len() == pop_size);

    // create `offspring_size` new offspring using k-tournament (
    // select the best individual out of k randomly choosen individuals)
    let offspring: Vec<_> = (0..offspring_size)
                                .map(|_| {

                                    // first parent. k candidates
                                    let p1 = tournament_selection_fast(rng,
                                                                       |i1, i2| {
                                                                           rank_dist[i1] <
                                                                           rank_dist[i2]
                                                                       },
                                                                       rank_dist.len(),
                                                                       tournament_k);

                                    // second parent. k candidates
                                    let p2 = tournament_selection_fast(rng,
                                                                       |i1, i2| {
                                                                           rank_dist[i1] <
                                                                           rank_dist[i2]
                                                                       },
                                                                       rank_dist.len(),
                                                                       tournament_k);

                                    // cross-over the two parents and produce one child (throw away
                                    // second child XXX)

                                    // The potentially dominating individual is gives as first
                                    // parameter.
                                    let (p1, p2) = if rank_dist[p1] < rank_dist[p2] {
                                        (p1, p2)
                                    } else if rank_dist[p2] < rank_dist[p1] {
                                        (p2, p1)
                                    } else {
                                        (p1, p2)
                                    };

                                    mating.mate(rng, &population[p1], &population[p2])
                                })
                                .collect();

    assert!(offspring.len() == offspring_size);

    // evaluate fitness of offspring
    let fitness_offspring = fitness_eval.fitness(&offspring[..]);
    assert!(fitness_offspring.len() == offspring.len());

    // merge population and offspring, then select
    let mut new_pop = Vec::with_capacity(rank_dist.len() + offspring.len());
    let mut new_fit = Vec::with_capacity(rank_dist.len() + offspring.len());
    for rd in rank_dist {
        new_pop.push(population[rd.idx].clone());
        new_fit.push(fitness[rd.idx].clone());
    }

    new_pop.extend(offspring);
    new_fit.extend(fitness_offspring);

    assert!(new_pop.len() == pop_size + offspring_size);
    assert!(new_fit.len() == pop_size + offspring_size);

    return (new_pop, new_fit);
}

#[test]
fn test_dominates() {
    let a = MultiObjective2 { objectives: [1.0, 0.1] };
    let b = MultiObjective2 { objectives: [0.1, 0.1] };
    let c = MultiObjective2 { objectives: [0.1, 1.0] };

    assert_eq!(false, a.dominates(&a));
    assert_eq!(false, a.dominates(&b));
    assert_eq!(false, a.dominates(&c));

    assert_eq!(true, b.dominates(&a));
    assert_eq!(false, b.dominates(&b));
    assert_eq!(true, b.dominates(&c));

    assert_eq!(false, c.dominates(&a));
    assert_eq!(false, c.dominates(&b));
    assert_eq!(false, c.dominates(&c));
}

#[test]
fn test_abc() {
    let mut solutions: Vec<MultiObjective2<f32>> = Vec::new();
    solutions.push(MultiObjective2 { objectives: [1.0, 0.1] });
    solutions.push(MultiObjective2 { objectives: [0.1, 0.1] });
    solutions.push(MultiObjective2 { objectives: [0.1, 1.0] });
    solutions.push(MultiObjective2 { objectives: [0.5, 0.5] });
    solutions.push(MultiObjective2 { objectives: [0.5, 0.5] });

    println!("solutions: {:?}", solutions);
    let selection = select(&solutions[..], 5);
    println!("selection: {:?}", selection);

    let fronts = fast_non_dominated_sort(&solutions[..], 10);
    println!("solutions: {:?}", solutions);
    println!("fronts: {:?}", fronts);

    for (rank, front) in fronts.iter().enumerate() {
        let distances = crowding_distance_assignment(&solutions[..], rank as u32, &front[..]);
        println!("front: {:?}", front);
        println!("distances: {:?}", distances);
    }
}
<|endoftext|>


<commit_before>#[derive(Default)]
pub struct Query {
    query: Vec<char>,
    pub index: usize,
    pub pos: usize,
}

impl Query {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn new_with_query(query: &str) -> Self {
        let mut ret = Query::new();
        for ch in query.chars() {
            ret.add_char(ch);
        }
        ret
    }

    pub fn get_query(&self) -> String {
        self.query.iter().cloned().collect::<String>()
    }

    pub fn add_char (&mut self, ch: char) -> bool {
        self.query.insert(self.index, ch);
        self.index += 1;
        self.pos += if ch.len_utf8() > 1 {2} else {1};
        true
    }

    pub fn backward_delete_char(&mut self) -> bool{
        if self.index == 0 { return false; }

        let ch = self.query.remove(self.index-1);
        self.index -= 1;
        self.pos -= if ch.len_utf8() > 1 {2} else {1};
        true
    }

    pub fn backward_char(&mut self) {
        if let Some(ch) = self.query.get(self.index-1) {
            self.index -= 1;
            self.pos -= if ch.len_utf8() > 1 {2} else {1};
        }
    }

    pub fn backward_kill_word(&mut self) -> bool {
        let mut modified = false;
        // skip whitespace
        while self.index > 0 {
            if let Some(&' ') = self.query.get(self.index-1) {
                modified = self.backward_delete_char() || modified;
            } else {
                break;
            }
        }

        while self.index > 0 {
            match self.query.get(self.index-1) {
                Some(&ch) if ch != ' ' => {
                    modified = self.backward_delete_char() || modified;
                }
                Some(_) | None => {break;}
            }
        }
        modified
    }

    pub fn backward_word(&mut self) -> bool {
        // skip whitespace
        while self.index > 0 {
            if let Some(&' ') = self.query.get(self.index-1) {
                self.backward_char();
            } else {
                break;
            }
        }

        while self.index > 0 {
            match self.query.get(self.index-1) {
                Some(&ch) if ch != ' ' => { self.backward_char(); }
                Some(_) | None => {break;}
            }
        }
        false
    }

    pub fn beginning_of_line(&mut self) -> bool {
        self.index = 0;
        self.pos = 0;
        false
    }

    // delete char forward
    pub fn delete_char(&mut self) -> bool {
        if self.index == self.query.len() { return false; }

        let _ = self.query.remove(self.index);
        true
    }

    pub fn forward_char(&mut self) {
        if let Some(ch) = self.query.get(self.index) {
            self.index += 1;
            self.pos += if ch.len_utf8() > 1 {2} else {1};
        }
    }

    pub fn forward_word(&mut self) {
        // skip whitespace
        while let Some(_) = self.query.get(self.index) {
            self.forward_char();
        }

        loop {
            match self.query.get(self.index) {
                Some(&ch) if ch != ' ' => self.forward_char(),
                Some(_) | None => break
            }
        }
    }

    pub fn kill_word(&mut self) -> bool {
        let len = self.query.len();
        let mut modified = false;
        // skip whitespace
        while self.index < len {
            if let Some(&' ') = self.query.get(self.index) {
                modified = self.delete_char() || modified;
            } else {
                break;
            }
        }

        while self.index < len {
            match self.query.get(self.index) {
                Some(&ch) if ch != ' ' => { modified = self.delete_char() || modified; }
                Some(_) | None => {break;}
            }
        }
        modified
    }

    pub fn end_of_line(&mut self) -> bool {
        let len = self.query.len();
        while self.index < len {
            self.forward_char();
        }
        false
    }

    pub fn kill_line(&mut self) -> bool {
        if self.index == self.query.len() {return false}
        while self.query.len() > self.index {
            let _ = self.query.pop();
        }
        true
    }

    pub fn line_discard(&mut self) -> bool {
        let mut modified = false;
        while self.index > 0 {
            modified = self.backward_delete_char() || modified;
        }
        modified
    }
}
<commit_msg>fix bug introduced by refactoring and add test<commit_after>#[derive(Default)]
pub struct Query {
    query: Vec<char>,
    pub index: usize,
    pub pos: usize,
}

impl Query {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn new_with_query(query: &str) -> Self {
        let mut ret = Query::new();
        for ch in query.chars() {
            ret.add_char(ch);
        }
        ret
    }

    pub fn get_query(&self) -> String {
        self.query.iter().cloned().collect::<String>()
    }

    pub fn add_char (&mut self, ch: char) -> bool {
        self.query.insert(self.index, ch);
        self.index += 1;
        self.pos += if ch.len_utf8() > 1 {2} else {1};
        true
    }

    pub fn backward_delete_char(&mut self) -> bool{
        if self.index == 0 { return false; }

        let ch = self.query.remove(self.index-1);
        self.index -= 1;
        self.pos -= if ch.len_utf8() > 1 {2} else {1};
        true
    }

    pub fn backward_char(&mut self) {
        if self.index == 0 { return; }
        if let Some(ch) = self.query.get(self.index-1) {
            self.index -= 1;
            self.pos -= if ch.len_utf8() > 1 {2} else {1};
        }
    }

    pub fn backward_kill_word(&mut self) -> bool {
        let mut modified = false;
        // skip whitespace
        while self.index > 0 {
            if let Some(&' ') = self.query.get(self.index-1) {
                modified = self.backward_delete_char() || modified;
            } else {
                break;
            }
        }

        while self.index > 0 {
            match self.query.get(self.index-1) {
                Some(&ch) if ch != ' ' => {
                    modified = self.backward_delete_char() || modified;
                }
                Some(_) | None => {break;}
            }
        }
        modified
    }

    pub fn backward_word(&mut self) -> bool {
        // skip whitespace
        while self.index > 0 {
            if let Some(&' ') = self.query.get(self.index-1) {
                self.backward_char();
            } else {
                break;
            }
        }

        while self.index > 0 {
            match self.query.get(self.index-1) {
                Some(&ch) if ch != ' ' => { self.backward_char(); }
                Some(_) | None => {break;}
            }
        }
        false
    }

    pub fn beginning_of_line(&mut self) -> bool {
        self.index = 0;
        self.pos = 0;
        false
    }

    // delete char forward
    pub fn delete_char(&mut self) -> bool {
        if self.index == self.query.len() { return false; }

        let _ = self.query.remove(self.index);
        true
    }

    pub fn forward_char(&mut self) {
        if let Some(ch) = self.query.get(self.index) {
            self.index += 1;
            self.pos += if ch.len_utf8() > 1 {2} else {1};
        }
    }

    pub fn forward_word(&mut self) {
        // skip whitespace
        while let Some(_) = self.query.get(self.index) {
            self.forward_char();
        }

        loop {
            match self.query.get(self.index) {
                Some(&ch) if ch != ' ' => self.forward_char(),
                Some(_) | None => break
            }
        }
    }

    pub fn kill_word(&mut self) -> bool {
        let len = self.query.len();
        let mut modified = false;
        // skip whitespace
        while self.index < len {
            if let Some(&' ') = self.query.get(self.index) {
                modified = self.delete_char() || modified;
            } else {
                break;
            }
        }

        while self.index < len {
            match self.query.get(self.index) {
                Some(&ch) if ch != ' ' => { modified = self.delete_char() || modified; }
                Some(_) | None => {break;}
            }
        }
        modified
    }

    pub fn end_of_line(&mut self) -> bool {
        let len = self.query.len();
        while self.index < len {
            self.forward_char();
        }
        false
    }

    pub fn kill_line(&mut self) -> bool {
        if self.index == self.query.len() {return false}
        while self.query.len() > self.index {
            let _ = self.query.pop();
        }
        true
    }

    pub fn line_discard(&mut self) -> bool {
        let mut modified = false;
        while self.index > 0 {
            modified = self.backward_delete_char() || modified;
        }
        modified
    }
}

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

    #[test]
    fn test_backward_char() {
        // Test that going back from zero does not overflow.
        Query::new().backward_char();
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A type-checked scaling factor between units.

use crate::num::One;

use crate::{Point2D, Rect, Size2D, Vector2D};
use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use core::ops::{Add, Div, Mul, Sub};
use num_traits::NumCast;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// A scaling factor between two different units of measurement.
///
/// This is effectively a type-safe float, intended to be used in combination with other types like
/// `length::Length` to enforce conversion between systems of measurement at compile time.
///
/// `Src` and `Dst` represent the units before and after multiplying a value by a `Scale`. They
/// may be types without values, such as empty enums.  For example:
///
/// ```rust
/// use euclid::Scale;
/// use euclid::Length;
/// enum Mm {};
/// enum Inch {};
///
/// let mm_per_inch: Scale<f32, Inch, Mm> = Scale::new(25.4);
///
/// let one_foot: Length<f32, Inch> = Length::new(12.0);
/// let one_foot_in_mm: Length<f32, Mm> = one_foot * mm_per_inch;
/// ```
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(
    feature = "serde",
    serde(bound(
        serialize = "T: serde::Serialize",
        deserialize = "T: serde::Deserialize<'de>"
    ))
)]
pub struct Scale<T, Src, Dst>(pub T, #[doc(hidden)] pub PhantomData<(Src, Dst)>);

impl<T, Src, Dst> Scale<T, Src, Dst> {
    #[inline]
    pub const fn new(x: T) -> Self {
        Scale(x, PhantomData)
    }

    /// Returns the given point transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, point2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_point(point2(42, -42)), point2(420, -420));
    /// ```
    #[inline]
    pub fn transform_point(self, point: Point2D<T, Src>) -> Point2D<T::Output, Dst>
    where
        T: Copy + Mul,
    {
        Point2D::new(point.x * self.0, point.y * self.0)
    }

    /// Returns the given vector transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, vec2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_vector(vec2(42, -42)), vec2(420, -420));
    /// ```
    #[inline]
    pub fn transform_vector(self, vec: Vector2D<T, Src>) -> Vector2D<T::Output, Dst>
    where
        T: Copy + Mul,
    {
        Vector2D::new(vec.x * self.0, vec.y * self.0)
    }

    /// Returns the given vector transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, size2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_size(size2(42, -42)), size2(420, -420));
    /// ```
    #[inline]
    pub fn transform_size(self, size: Size2D<T, Src>) -> Size2D<T::Output, Dst>
    where
        T: Copy + Mul,
    {
        Size2D::new(size.width * self.0, size.height * self.0)
    }

    /// Returns the given rect transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, rect};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_rect(&rect(1, 2, 42, -42)), rect(10, 20, 420, -420));
    /// ```
    #[inline]
    pub fn transform_rect(self, rect: &Rect<T, Src>) -> Rect<T::Output, Dst>
    where
        T: Copy + Mul,
    {
        Rect::new(
            self.transform_point(rect.origin),
            self.transform_size(rect.size),
        )
    }

    /// Returns `true` if this scale has no effect.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// use euclid::num::One;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);
    /// let mm_per_mm: Scale<f32, Mm, Mm> = Scale::new(1.0);
    ///
    /// assert_eq!(cm_per_mm.is_identity(), false);
    /// assert_eq!(mm_per_mm.is_identity(), true);
    /// assert_eq!(mm_per_mm, Scale::one());
    /// ```
    #[inline]
    pub fn is_identity(self) -> bool
    where
        T: PartialEq + One,
    {
        self.0 == T::one()
    }

    /// Returns the underlying scalar scale factor.
    #[inline]
    pub fn get(self) -> T {
        self.0
    }

    /// The inverse Scale (1.0 / self).
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let cm_per_mm: Scale<f32, Cm, Mm> = Scale::new(0.1);
    ///
    /// assert_eq!(cm_per_mm.inverse(), Scale::new(10.0));
    /// ```
    pub fn inverse(self) -> Scale<T::Output, Dst, Src>
    where
        T: One + Div,
    {
        let one: T = One::one();
        Scale::new(one / self.0)
    }
}

impl<T: NumCast, Src, Dst> Scale<T, Src, Dst> {
    /// Cast from one numeric representation to another, preserving the units.
    ///
    /// # Panics
    ///
    /// If the source value cannot be represented by the target type `NewT`, then
    /// method panics. Use `try_cast` if that must be case.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.cast::<f32>(), Scale::new(10.0));
    /// ```
    /// That conversion will panic, because `i32` not enough to store such big numbers:
    /// ```rust,should_panic
    /// use euclid::Scale;
    /// enum Mm {};// millimeter = 10^-2 meters
    /// enum Em {};// exameter   = 10^18 meters
    ///
    /// // Panics
    /// let to_em: Scale<i32, Mm, Em> = Scale::new(10e20).cast();
    /// ```
    #[inline]
    pub fn cast<NewT: NumCast>(self) -> Scale<NewT, Src, Dst> {
        self.try_cast().unwrap()
    }

    /// Fallible cast from one numeric representation to another, preserving the units.
    /// If the source value cannot be represented by the target type `NewT`, then `None`
    /// is returned.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    /// enum Em {};// Exameter = 10^18 meters
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    /// let to_em: Scale<f32, Mm, Em> = Scale::new(10e20);
    ///
    /// assert_eq!(to_mm.try_cast::<f32>(), Some(Scale::new(10.0)));
    /// // Integer to small to store that number
    /// assert_eq!(to_em.try_cast::<i32>(), None);
    /// ```
    pub fn try_cast<NewT: NumCast>(self) -> Option<Scale<NewT, Src, Dst>> {
        NumCast::from(self.0).map(Scale::new)
    }
}

impl<Src, Dst> Scale<f32, Src, Dst> {
    /// Identity scaling, could be used to safely transit from one space to another.
    pub const ONE: Self = Scale(1.0, PhantomData);
}

// scale0 * scale1
// (A,B) * (B,C) = (A,C)
impl<T: Mul, A, B, C> Mul<Scale<T, B, C>> for Scale<T, A, B> {
    type Output = Scale<T::Output, A, C>;

    #[inline]
    fn mul(self, other: Scale<T, B, C>) -> Self::Output {
        Scale::new(self.0 * other.0)
    }
}

// scale0 + scale1
impl<T: Add, Src, Dst> Add for Scale<T, Src, Dst> {
    type Output = Scale<T::Output, Src, Dst>;

    #[inline]
    fn add(self, other: Scale<T, Src, Dst>) -> Self::Output {
        Scale::new(self.0 + other.0)
    }
}

// scale0 - scale1
impl<T: Sub, Src, Dst> Sub for Scale<T, Src, Dst> {
    type Output = Scale<T::Output, Src, Dst>;

    #[inline]
    fn sub(self, other: Scale<T, Src, Dst>) -> Self::Output {
        Scale::new(self.0 - other.0)
    }
}

// FIXME: Switch to `derive(PartialEq, Clone)` after this Rust issue is fixed:
// https://github.com/rust-lang/rust/issues/26925

impl<T: PartialEq, Src, Dst> PartialEq for Scale<T, Src, Dst> {
    fn eq(&self, other: &Scale<T, Src, Dst>) -> bool {
        self.0 == other.0
    }
}

impl<T: Eq, Src, Dst> Eq for Scale<T, Src, Dst> {}

impl<T: PartialOrd, Src, Dst> PartialOrd for Scale<T, Src, Dst> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl<T: Ord, Src, Dst> Ord for Scale<T, Src, Dst> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl<T: Clone, Src, Dst> Clone for Scale<T, Src, Dst> {
    fn clone(&self) -> Scale<T, Src, Dst> {
        Scale::new(self.0.clone())
    }
}

impl<T: Copy, Src, Dst> Copy for Scale<T, Src, Dst> {}

impl<T: fmt::Debug, Src, Dst> fmt::Debug for Scale<T, Src, Dst> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<T: Default, Src, Dst> Default for Scale<T, Src, Dst> {
    fn default() -> Self {
        Self::new(T::default())
    }
}

impl<T: Hash, Src, Dst> Hash for Scale<T, Src, Dst> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state)
    }
}

impl<T: One, Src, Dst> One for Scale<T, Src, Dst> {
    #[inline]
    fn one() -> Self {
        Scale::new(T::one())
    }
}

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

    enum Inch {}
    enum Cm {}
    enum Mm {}

    #[test]
    fn test_scale() {
        let mm_per_inch: Scale<f32, Inch, Mm> = Scale::new(25.4);
        let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);

        let mm_per_cm: Scale<f32, Cm, Mm> = cm_per_mm.inverse();
        assert_eq!(mm_per_cm.get(), 10.0);

        let one: Scale<f32, Mm, Mm> = cm_per_mm * mm_per_cm;
        assert_eq!(one.get(), 1.0);

        let one: Scale<f32, Cm, Cm> = mm_per_cm * cm_per_mm;
        assert_eq!(one.get(), 1.0);

        let cm_per_inch: Scale<f32, Inch, Cm> = mm_per_inch * cm_per_mm;
        //  mm     cm     cm
        // ---- x ---- = ----
        // inch    mm    inch
        assert_eq!(cm_per_inch, Scale::new(2.54));

        let a: Scale<isize, Inch, Inch> = Scale::new(2);
        let b: Scale<isize, Inch, Inch> = Scale::new(3);
        assert_ne!(a, b);
        assert_eq!(a, a.clone());
        assert_eq!(a.clone() + b.clone(), Scale::new(5));
        assert_eq!(a - b, Scale::new(-1));
    }
}
<commit_msg>Auto merge of #457 - nical:scale-identity, r=kvark<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A type-checked scaling factor between units.

use crate::num::One;

use crate::{Point2D, Rect, Size2D, Vector2D};
use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use core::ops::{Add, Div, Mul, Sub};
use num_traits::NumCast;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// A scaling factor between two different units of measurement.
///
/// This is effectively a type-safe float, intended to be used in combination with other types like
/// `length::Length` to enforce conversion between systems of measurement at compile time.
///
/// `Src` and `Dst` represent the units before and after multiplying a value by a `Scale`. They
/// may be types without values, such as empty enums.  For example:
///
/// ```rust
/// use euclid::Scale;
/// use euclid::Length;
/// enum Mm {};
/// enum Inch {};
///
/// let mm_per_inch: Scale<f32, Inch, Mm> = Scale::new(25.4);
///
/// let one_foot: Length<f32, Inch> = Length::new(12.0);
/// let one_foot_in_mm: Length<f32, Mm> = one_foot * mm_per_inch;
/// ```
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(
    feature = "serde",
    serde(bound(
        serialize = "T: serde::Serialize",
        deserialize = "T: serde::Deserialize<'de>"
    ))
)]
pub struct Scale<T, Src, Dst>(pub T, #[doc(hidden)] pub PhantomData<(Src, Dst)>);

impl<T, Src, Dst> Scale<T, Src, Dst> {
    #[inline]
    pub const fn new(x: T) -> Self {
        Scale(x, PhantomData)
    }

    /// Creates an identity scale (1.0).
    #[inline]
    pub fn identity() -> Self
    where
        T: One
    {
        Scale::new(T::one())
    }

    /// Returns the given point transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, point2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_point(point2(42, -42)), point2(420, -420));
    /// ```
    #[inline]
    pub fn transform_point(self, point: Point2D<T, Src>) -> Point2D<T::Output, Dst>
    where
        T: Copy + Mul,
    {
        Point2D::new(point.x * self.0, point.y * self.0)
    }

    /// Returns the given vector transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, vec2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_vector(vec2(42, -42)), vec2(420, -420));
    /// ```
    #[inline]
    pub fn transform_vector(self, vec: Vector2D<T, Src>) -> Vector2D<T::Output, Dst>
    where
        T: Copy + Mul,
    {
        Vector2D::new(vec.x * self.0, vec.y * self.0)
    }

    /// Returns the given vector transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, size2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_size(size2(42, -42)), size2(420, -420));
    /// ```
    #[inline]
    pub fn transform_size(self, size: Size2D<T, Src>) -> Size2D<T::Output, Dst>
    where
        T: Copy + Mul,
    {
        Size2D::new(size.width * self.0, size.height * self.0)
    }

    /// Returns the given rect transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, rect};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_rect(&rect(1, 2, 42, -42)), rect(10, 20, 420, -420));
    /// ```
    #[inline]
    pub fn transform_rect(self, rect: &Rect<T, Src>) -> Rect<T::Output, Dst>
    where
        T: Copy + Mul,
    {
        Rect::new(
            self.transform_point(rect.origin),
            self.transform_size(rect.size),
        )
    }

    /// Returns `true` if this scale has no effect.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// use euclid::num::One;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);
    /// let mm_per_mm: Scale<f32, Mm, Mm> = Scale::new(1.0);
    ///
    /// assert_eq!(cm_per_mm.is_identity(), false);
    /// assert_eq!(mm_per_mm.is_identity(), true);
    /// assert_eq!(mm_per_mm, Scale::one());
    /// ```
    #[inline]
    pub fn is_identity(self) -> bool
    where
        T: PartialEq + One,
    {
        self.0 == T::one()
    }

    /// Returns the underlying scalar scale factor.
    #[inline]
    pub fn get(self) -> T {
        self.0
    }

    /// The inverse Scale (1.0 / self).
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let cm_per_mm: Scale<f32, Cm, Mm> = Scale::new(0.1);
    ///
    /// assert_eq!(cm_per_mm.inverse(), Scale::new(10.0));
    /// ```
    pub fn inverse(self) -> Scale<T::Output, Dst, Src>
    where
        T: One + Div,
    {
        let one: T = One::one();
        Scale::new(one / self.0)
    }
}

impl<T: NumCast, Src, Dst> Scale<T, Src, Dst> {
    /// Cast from one numeric representation to another, preserving the units.
    ///
    /// # Panics
    ///
    /// If the source value cannot be represented by the target type `NewT`, then
    /// method panics. Use `try_cast` if that must be case.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.cast::<f32>(), Scale::new(10.0));
    /// ```
    /// That conversion will panic, because `i32` not enough to store such big numbers:
    /// ```rust,should_panic
    /// use euclid::Scale;
    /// enum Mm {};// millimeter = 10^-2 meters
    /// enum Em {};// exameter   = 10^18 meters
    ///
    /// // Panics
    /// let to_em: Scale<i32, Mm, Em> = Scale::new(10e20).cast();
    /// ```
    #[inline]
    pub fn cast<NewT: NumCast>(self) -> Scale<NewT, Src, Dst> {
        self.try_cast().unwrap()
    }

    /// Fallible cast from one numeric representation to another, preserving the units.
    /// If the source value cannot be represented by the target type `NewT`, then `None`
    /// is returned.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    /// enum Em {};// Exameter = 10^18 meters
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    /// let to_em: Scale<f32, Mm, Em> = Scale::new(10e20);
    ///
    /// assert_eq!(to_mm.try_cast::<f32>(), Some(Scale::new(10.0)));
    /// // Integer to small to store that number
    /// assert_eq!(to_em.try_cast::<i32>(), None);
    /// ```
    pub fn try_cast<NewT: NumCast>(self) -> Option<Scale<NewT, Src, Dst>> {
        NumCast::from(self.0).map(Scale::new)
    }
}

// scale0 * scale1
// (A,B) * (B,C) = (A,C)
impl<T: Mul, A, B, C> Mul<Scale<T, B, C>> for Scale<T, A, B> {
    type Output = Scale<T::Output, A, C>;

    #[inline]
    fn mul(self, other: Scale<T, B, C>) -> Self::Output {
        Scale::new(self.0 * other.0)
    }
}

// scale0 + scale1
impl<T: Add, Src, Dst> Add for Scale<T, Src, Dst> {
    type Output = Scale<T::Output, Src, Dst>;

    #[inline]
    fn add(self, other: Scale<T, Src, Dst>) -> Self::Output {
        Scale::new(self.0 + other.0)
    }
}

// scale0 - scale1
impl<T: Sub, Src, Dst> Sub for Scale<T, Src, Dst> {
    type Output = Scale<T::Output, Src, Dst>;

    #[inline]
    fn sub(self, other: Scale<T, Src, Dst>) -> Self::Output {
        Scale::new(self.0 - other.0)
    }
}

// FIXME: Switch to `derive(PartialEq, Clone)` after this Rust issue is fixed:
// https://github.com/rust-lang/rust/issues/26925

impl<T: PartialEq, Src, Dst> PartialEq for Scale<T, Src, Dst> {
    fn eq(&self, other: &Scale<T, Src, Dst>) -> bool {
        self.0 == other.0
    }
}

impl<T: Eq, Src, Dst> Eq for Scale<T, Src, Dst> {}

impl<T: PartialOrd, Src, Dst> PartialOrd for Scale<T, Src, Dst> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl<T: Ord, Src, Dst> Ord for Scale<T, Src, Dst> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl<T: Clone, Src, Dst> Clone for Scale<T, Src, Dst> {
    fn clone(&self) -> Scale<T, Src, Dst> {
        Scale::new(self.0.clone())
    }
}

impl<T: Copy, Src, Dst> Copy for Scale<T, Src, Dst> {}

impl<T: fmt::Debug, Src, Dst> fmt::Debug for Scale<T, Src, Dst> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<T: Default, Src, Dst> Default for Scale<T, Src, Dst> {
    fn default() -> Self {
        Self::new(T::default())
    }
}

impl<T: Hash, Src, Dst> Hash for Scale<T, Src, Dst> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state)
    }
}

impl<T: One, Src, Dst> One for Scale<T, Src, Dst> {
    #[inline]
    fn one() -> Self {
        Scale::new(T::one())
    }
}

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

    enum Inch {}
    enum Cm {}
    enum Mm {}

    #[test]
    fn test_scale() {
        let mm_per_inch: Scale<f32, Inch, Mm> = Scale::new(25.4);
        let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);

        let mm_per_cm: Scale<f32, Cm, Mm> = cm_per_mm.inverse();
        assert_eq!(mm_per_cm.get(), 10.0);

        let one: Scale<f32, Mm, Mm> = cm_per_mm * mm_per_cm;
        assert_eq!(one.get(), 1.0);

        let one: Scale<f32, Cm, Cm> = mm_per_cm * cm_per_mm;
        assert_eq!(one.get(), 1.0);

        let cm_per_inch: Scale<f32, Inch, Cm> = mm_per_inch * cm_per_mm;
        //  mm     cm     cm
        // ---- x ---- = ----
        // inch    mm    inch
        assert_eq!(cm_per_inch, Scale::new(2.54));

        let a: Scale<isize, Inch, Inch> = Scale::new(2);
        let b: Scale<isize, Inch, Inch> = Scale::new(3);
        assert_ne!(a, b);
        assert_eq!(a, a.clone());
        assert_eq!(a.clone() + b.clone(), Scale::new(5));
        assert_eq!(a - b, Scale::new(-1));
    }
}
<|endoftext|>