use rand;
use rand::{Rng, StdRng, SeedableRng};
use ea::*;
use neuro::{ActivationFunctionType, MultilayeredNetwork, NeuralArchitecture, NeuralNetwork};
use problem::*;
pub trait NeuroProblem: Problem {
fn get_inputs_num(&self) -> usize;
fn get_outputs_num(&self) -> usize;
fn get_default_net(&self) -> MultilayeredNetwork;
fn compute_with_net<T: NeuralNetwork>(&self, net: &mut T) -> f32;
}
#[allow(unused_variables, unused_mut)]
impl<T: NeuroProblem> Problem for T {
fn compute<I: Individual>(&self, ind: &mut I) -> f32 {
let fitness;
fitness = self.compute_with_net(ind.to_net_mut().expect("Can not extract mutable ANN"));
ind.set_fitness(fitness);
ind.get_fitness()
}
fn get_random_individual<U: Individual, R: Rng>(&self, size: usize, mut rng: &mut R) -> U {
let mut res_ind = U::new();
res_ind.set_net(self.get_default_net());
res_ind
}
}
#[allow(dead_code)]
pub struct XorProblem {}
#[allow(dead_code)]
impl XorProblem {
pub fn new() -> XorProblem {
XorProblem{}
}
}
#[allow(dead_code)]
impl NeuroProblem for XorProblem {
fn get_inputs_num(&self) -> usize {2}
fn get_outputs_num(&self) -> usize {1}
fn get_default_net(&self) -> MultilayeredNetwork {
let mut rng = rand::thread_rng();
let mut net: MultilayeredNetwork = MultilayeredNetwork::new(self.get_inputs_num(), self.get_outputs_num());
net.add_hidden_layer(4 as usize, ActivationFunctionType::Sigmoid)
.build(&mut rng, NeuralArchitecture::BypassInputs);
net
}
fn compute_with_net<T: NeuralNetwork>(&self, nn: &mut T) -> f32 {
let mut er = 0f32;
let output = nn.compute(&[0f32, 0f32]);
er += output[0] * output[0];
let output = nn.compute(&[1f32, 1f32]);
er += output[0] * output[0];
let output = nn.compute(&[0f32, 1f32]);
er += (1f32-output[0]) * (1f32-output[0]);
let output = nn.compute(&[1f32, 0f32]);
er += (1f32-output[0]) * (1f32-output[0]);
er
}
}
#[allow(dead_code)]
pub struct SymbolicRegressionProblem {
func: fn(&SymbolicRegressionProblem, f32) -> f32,
}
#[allow(dead_code)]
impl SymbolicRegressionProblem {
pub fn new(problem_type: char) -> SymbolicRegressionProblem {
match problem_type {
'f' => SymbolicRegressionProblem::new_f(),
'g' => SymbolicRegressionProblem::new_g(),
'h' => SymbolicRegressionProblem::new_h(),
_ => {
panic!(format!("Unknown problem type for symbolic regression problem: {}",
problem_type))
}
}
}
pub fn new_f() -> SymbolicRegressionProblem {
SymbolicRegressionProblem { func: SymbolicRegressionProblem::f }
}
pub fn new_g() -> SymbolicRegressionProblem {
SymbolicRegressionProblem { func: SymbolicRegressionProblem::g }
}
pub fn new_h() -> SymbolicRegressionProblem {
SymbolicRegressionProblem { func: SymbolicRegressionProblem::h }
}
fn f(&self, x: f32) -> f32 {
let x2 = x * x;
x2 * x2 + x2 * x + x2 + x
}
fn g(&self, x: f32) -> f32 {
let x2 = x * x;
x2 * x2 * x - 2f32 * x2 * x + x
}
fn h(&self, x: f32) -> f32 {
let x2 = x * x;
x2 * x2 * x2 - 2f32 * x2 * x2 + x2
}
}
impl NeuroProblem for SymbolicRegressionProblem {
fn get_inputs_num(&self) -> usize { 1 }
fn get_outputs_num(&self) -> usize { 1 }
fn get_default_net(&self) -> MultilayeredNetwork {
let mut rng = rand::thread_rng();
let mut net: MultilayeredNetwork = MultilayeredNetwork::new(self.get_inputs_num(), self.get_outputs_num());
net.add_hidden_layer(5 as usize, ActivationFunctionType::Sigmoid)
.build(&mut rng, NeuralArchitecture::Multilayered);
net
}
fn compute_with_net<T: NeuralNetwork>(&self, nn: &mut T) -> f32 {
const PTS_COUNT: u32 = 20;
let mut er = 0f32;
let mut input = vec![0f32];
let mut output;
let mut rng: StdRng = StdRng::from_seed(&[0]);
for _ in 0..PTS_COUNT {
let x = rng.gen::<f32>(); let y = (self.func)(&self, x);
input[0] = x;
output = nn.compute(&input);
er += (output[0] - y).abs();
}
er
}
}
#[cfg(test)]
#[allow(unused_imports)]
mod test {
use rand;
use math::*;
use ne::*;
use neproblem::*;
use problem::*;
use settings::*;
#[test]
fn test_xor_problem() {
let (pop_size, gen_count, param_count) = (20, 20, 100); let settings = EASettings::new(pop_size, gen_count, param_count);
let problem = XorProblem::new();
let mut ne: NE<XorProblem> = NE::new(&problem);
let res = ne.run(settings).expect("Error: NE result is empty");
println!("result: {:?}", res);
println!("\nbest individual: {:?}", res.best);
}
#[test]
fn test_symb_regression_problem() {
for prob_type in vec!['f', 'g', 'h'] {
let mut rng = rand::thread_rng();
let prob = SymbolicRegressionProblem::new(prob_type);
println!("Created problem of type: {}", prob_type);
let mut net = prob.get_default_net();
println!("Created default net with {} inputs, {} outputs, and {} hidden layers ", net.get_inputs_num(), net.get_outputs_num(), net.len()-1);
println!(" Network weights: {:?}", net.get_weights());
let mut ind: NEIndividual = prob.get_random_individual(0, &mut rng);
println!(" Random individual: {:?}", ind.to_vec().unwrap());
println!(" Random individual ANN: {:?}", ind.to_net().unwrap());
let input_size = net.get_inputs_num();
let mut ys = Vec::with_capacity(100);
for _ in 0..100 {
let x = rand_vector_std_gauss(input_size, &mut rng);
let y = net.compute(&x);
ys.push(y);
}
println!(" Network outputs for 100 random inputs: {:?}", ys);
println!(" Network evaluation: {:?}\n", prob.compute_with_net(&mut net));
}
}
}