#[cfg(all(feature = "mesalock_sgx", not(target_env = "sgx")))]
use std::prelude::v1::*;
use crate::decision_tree::ValueType;
use serde_derive::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum Loss {
SquaredError,
LogLikelyhood,
LAD,
RegLinear,
RegLogistic,
BinaryLogistic,
BinaryLogitraw,
MultiSoftprob,
MultiSoftmax,
RankPairwise,
}
impl Default for Loss {
fn default() -> Self {
Loss::SquaredError
}
}
pub fn string2loss(s: &str) -> Loss {
match s {
"LogLikelyhood" => Loss::LogLikelyhood,
"SquaredError" => Loss::SquaredError,
"LAD" => Loss::LAD,
"reg:linear" => Loss::RegLinear,
"binary:logistic" => Loss::BinaryLogistic,
"reg:logistic" => Loss::RegLogistic,
"binary:logitraw" => Loss::BinaryLogitraw,
"multi:softprob" => Loss::MultiSoftprob,
"multi:softmax" => Loss::MultiSoftmax,
"rank:pairwise" => Loss::RankPairwise,
_ => {
println!("unsupported loss, set to default(SquaredError)");
Loss::SquaredError
}
}
}
pub fn loss2string(l: &Loss) -> String {
match l {
Loss::LogLikelyhood => String::from("LogLikelyhood"),
Loss::SquaredError => String::from("SquaredError"),
Loss::LAD => String::from("LAD"),
Loss::RegLinear => String::from("reg:linear"),
Loss::BinaryLogistic => String::from("binary:logistic"),
Loss::RegLogistic => String::from("reg:logistic"),
Loss::BinaryLogitraw => String::from("binary:logitraw"),
Loss::MultiSoftprob => String::from("multi:softprob"),
Loss::MultiSoftmax => String::from("multi:softmax"),
Loss::RankPairwise => String::from("rank:pairwise"),
}
}
#[derive(Default, Clone, Serialize, Deserialize)]
pub struct Config {
pub feature_size: usize,
pub max_depth: u32,
pub iterations: usize,
pub shrinkage: ValueType,
pub feature_sample_ratio: f64,
pub data_sample_ratio: f64,
pub min_leaf_size: usize,
pub loss: Loss,
pub debug: bool,
pub initial_guess_enabled: bool,
pub training_optimization_level: u8,
}
impl Config {
pub fn new() -> Config {
Config {
feature_size: 1,
max_depth: 2,
iterations: 2,
shrinkage: 1.0,
feature_sample_ratio: 1.0,
data_sample_ratio: 1.0,
min_leaf_size: 1,
loss: Loss::SquaredError,
debug: false,
initial_guess_enabled: false,
training_optimization_level: 2,
}
}
pub fn set_feature_size(&mut self, n: usize) {
self.feature_size = n;
}
pub fn set_shrinkage(&mut self, eta: ValueType) {
self.shrinkage = eta;
}
pub fn set_training_optimization_level(&mut self, level: u8) {
let optimization_level = if level >= 3 { 2 } else { level };
self.training_optimization_level = optimization_level;
}
pub fn set_max_depth(&mut self, n: u32) {
self.max_depth = n;
}
pub fn set_iterations(&mut self, n: usize) {
self.iterations = n;
}
pub fn set_feature_sample_ratio(&mut self, n: f64) {
self.feature_sample_ratio = n;
}
pub fn set_data_sample_ratio(&mut self, n: f64) {
self.data_sample_ratio = n;
}
pub fn set_min_leaf_size(&mut self, n: usize) {
self.min_leaf_size = n;
}
pub fn set_loss(&mut self, l: &str) {
self.loss = string2loss(l);
}
pub fn set_debug(&mut self, option: bool) {
self.debug = option;
}
pub fn enabled_initial_guess(&mut self, option: bool) {
self.initial_guess_enabled = option;
}
pub fn to_string(&self) -> String {
let mut s = String::from("");
s.push_str(&format!("number of features = {}\n", self.feature_size));
s.push_str(&format!("min leaf size = {}\n", self.min_leaf_size));
s.push_str(&format!("maximum depth = {}\n", self.max_depth));
s.push_str(&format!("iterations = {}\n", self.iterations));
s.push_str(&format!("shrinkage = {}\n", self.shrinkage));
s.push_str(&format!(
"feature sample ratio = {}\n",
self.feature_sample_ratio
));
s.push_str(&format!("data sample ratio = {}\n", self.data_sample_ratio));
s.push_str(&format!("debug enabled = {}\n", self.debug));
s.push_str(&format!("loss type = {}\n", loss2string(&self.loss)));
s.push_str(&format!(
"initial guess enabled = {}\n",
self.initial_guess_enabled
));
s
}
}
#[cfg(test)]
mod tests {
use crate::config::{loss2string, string2loss, Config, Loss};
const STRINGLOSS: [(&str, Loss); 11] = [
("LogLikelyhood", Loss::LogLikelyhood),
("SquaredError", Loss::SquaredError),
("LAD", Loss::LAD),
("reg:linear", Loss::RegLinear),
("binary:logistic", Loss::BinaryLogistic),
("reg:logistic", Loss::RegLogistic),
("binary:logitraw", Loss::BinaryLogitraw),
("multi:softprob", Loss::MultiSoftprob),
("multi:softmax", Loss::MultiSoftmax),
("rank:pairwise", Loss::RankPairwise),
("unknown", Loss::SquaredError),
];
#[test]
fn doc_test_config_head() {
let mut cfg = Config::new();
cfg.set_feature_size(4);
cfg.set_max_depth(3);
cfg.set_iterations(3);
cfg.set_loss("LAD");
assert_eq!(cfg.feature_size, 4);
assert_eq!(cfg.max_depth, 3);
assert_eq!(cfg.iterations, 3);
assert_eq!(cfg.loss, Loss::LAD);
}
#[test]
fn doc_test_string2loss() {
for (s, l) in &STRINGLOSS {
assert_eq!(string2loss(s), *l);
}
}
#[test]
fn doc_test_loss2string() {
for (s, l) in &STRINGLOSS[..10] {
assert_eq!(loss2string(l), *s);
}
}
#[test]
fn doc_test_config_new() {
let cfg = Config::new();
assert_eq!(cfg.feature_size, 1);
assert_eq!(cfg.max_depth, 2);
assert_eq!(cfg.iterations, 2);
assert_eq!(cfg.shrinkage, 1.0);
assert_eq!(cfg.feature_sample_ratio, 1.0);
assert_eq!(cfg.data_sample_ratio, 1.0);
assert_eq!(cfg.min_leaf_size, 1);
assert_eq!(cfg.loss, Loss::SquaredError);
assert!(!cfg.debug);
assert!(!cfg.initial_guess_enabled);
assert_eq!(cfg.training_optimization_level, 2);
}
#[test]
fn doc_test_set_feature_size() {
let mut cfg = Config::new();
cfg.set_feature_size(10);
assert_eq!(cfg.feature_size, 10);
cfg.set_feature_size(20);
assert_eq!(cfg.feature_size, 20);
}
#[test]
fn doc_test_set_shrinkage() {
let mut cfg = Config::new();
cfg.set_shrinkage(3.0);
assert_eq!(cfg.shrinkage, 3.0);
cfg.set_shrinkage(5.0);
assert_eq!(cfg.shrinkage, 5.0);
}
#[test]
fn doc_test_set_training_optimization_level() {
let mut cfg = Config::new();
cfg.set_training_optimization_level(0);
assert_eq!(cfg.training_optimization_level, 0);
cfg.set_training_optimization_level(1);
assert_eq!(cfg.training_optimization_level, 1);
cfg.set_training_optimization_level(2);
assert_eq!(cfg.training_optimization_level, 2);
cfg.set_training_optimization_level(3);
assert_eq!(cfg.training_optimization_level, 2);
cfg.set_training_optimization_level(100);
assert_eq!(cfg.training_optimization_level, 2);
}
#[test]
fn doc_test_set_iterations() {
let mut cfg = Config::new();
cfg.set_iterations(1);
assert_eq!(cfg.iterations, 1);
cfg.set_iterations(10);
assert_eq!(cfg.iterations, 10);
cfg.set_iterations(100);
assert_eq!(cfg.iterations, 100);
}
#[test]
fn doc_test_set_feature_sample_ratio() {
let mut cfg = Config::new();
cfg.set_feature_sample_ratio(1.0);
assert_eq!(cfg.feature_sample_ratio, 1.0);
cfg.set_feature_sample_ratio(0.9);
assert_eq!(cfg.feature_sample_ratio, 0.9);
cfg.set_feature_sample_ratio(1.8);
assert_eq!(cfg.feature_sample_ratio, 1.8);
}
#[test]
fn doc_test_set_data_sample_ratio() {
let mut cfg = Config::new();
cfg.set_data_sample_ratio(1.0);
assert_eq!(cfg.data_sample_ratio, 1.0);
cfg.set_data_sample_ratio(0.9);
assert_eq!(cfg.data_sample_ratio, 0.9);
cfg.set_data_sample_ratio(1.8);
assert_eq!(cfg.data_sample_ratio, 1.8);
}
#[test]
fn doc_test_min_leaf_size() {
let mut cfg = Config::new();
cfg.set_min_leaf_size(1);
assert_eq!(cfg.min_leaf_size, 1);
cfg.set_min_leaf_size(10);
assert_eq!(cfg.min_leaf_size, 10);
cfg.set_min_leaf_size(100);
assert_eq!(cfg.min_leaf_size, 100);
}
#[test]
fn doc_test_set_loss() {
let mut cfg = Config::new();
for (s, l) in &STRINGLOSS {
cfg.set_loss(s);
assert_eq!(cfg.loss, *l);
}
}
#[test]
fn doc_test_set_debug() {
let mut cfg = Config::new();
cfg.set_debug(true);
assert!(cfg.debug);
cfg.set_debug(false);
assert!(!cfg.debug);
}
#[test]
fn doc_test_to_string() {
let cfg = Config::new();
assert_eq!(cfg.to_string(), "number of features = 1\nmin leaf size = 1\nmaximum depth = 2\niterations = 2\nshrinkage = 1\nfeature sample ratio = 1\ndata sample ratio = 1\ndebug enabled = false\nloss type = SquaredError\ninitial guess enabled = false\n");
}
}