use std::fs::File;
use std::io;
use std::sync::mpsc;
use std::thread;
use optlib::genetic::{
self, creation, cross, mutation, pairing, pre_birth, selection, GeneticOptimizer,
};
use optlib::tools::statistics::{
get_predicate_success_vec_solution, CallCountData, GoalCalcStatistics,
StatFunctionsConvergence, StatFunctionsGoal, StatFunctionsSolution,
};
use optlib::tools::{logging, statistics, stopchecker};
use optlib::{Goal, GoalFromFunction, Optimizer};
use optlib_testfunc;
type Gene = f32;
type Chromosomes = Vec<Gene>;
fn create_optimizer<'a>(
chromo_count: usize,
goal: Box<dyn Goal<Chromosomes> + 'a>,
) -> GeneticOptimizer<'a, Chromosomes> {
let minval: Gene = -500.0;
let maxval: Gene = 500.0;
let population_size = 100;
let intervals = vec![(minval, maxval); chromo_count];
let creator = creation::vec_float::RandomCreator::new(population_size, intervals.clone());
let families_count = population_size / 2;
let rounds_count = 5;
let pairing = pairing::Tournament::new(families_count).rounds_count(rounds_count);
let single_cross = cross::FloatCrossExp::new();
let cross = cross::VecCrossAllGenes::new(Box::new(single_cross));
let mutation_probability = 10.0;
let mutation_gene_count = 3;
let single_mutation = mutation::BitwiseMutation::new(mutation_gene_count);
let mutation = mutation::VecMutation::new(mutation_probability, Box::new(single_mutation));
let pre_births: Vec<Box<dyn genetic::PreBirth<Chromosomes>>> = vec![Box::new(
pre_birth::vec_float::CheckChromoInterval::new(intervals.clone()),
)];
let stop_checker = stopchecker::CompositeAny::new(vec![
Box::new(stopchecker::MaxIterations::new(3000)),
]);
let selections: Vec<Box<dyn genetic::Selection<Chromosomes>>> = vec![
Box::new(selection::KillFitnessNaN::new()),
Box::new(selection::LimitPopulation::new(population_size)),
];
let optimizer = genetic::GeneticOptimizer::new(
goal,
Box::new(stop_checker),
Box::new(creator),
Box::new(pairing),
Box::new(cross),
Box::new(mutation),
selections,
pre_births,
);
optimizer
}
fn print_convergence_statistics(
mut writer: &mut dyn io::Write,
stat: &statistics::Statistics<Chromosomes>,
) {
let average_convergence = stat.get_convergence().get_average_convergence();
for n in 0..average_convergence.len() {
if let Some(goal_value) = average_convergence[n] {
writeln!(
&mut writer,
"{n:<8}{value:15.10e}",
n = n,
value = goal_value
)
.unwrap();
}
}
}
fn print_solution(mut writer: &mut dyn io::Write, stat: &statistics::Statistics<Chromosomes>) {
let run_count = stat.get_run_count();
let results = stat.get_results();
for n in 0..run_count {
if let Some((solution, goal)) = &results[n] {
let mut result_str = String::new();
result_str = result_str + &format!("{:<8}", n);
for x in solution {
result_str = result_str + &format!(" {:<20.10}", x);
}
result_str = result_str + &format!(" {:20.10}", goal);
writeln!(&mut writer, "{}", result_str).unwrap();
} else {
writeln!(&mut writer, "{n:<8} Failed", n = n).unwrap();
}
}
}
fn print_statistics(
stat: &statistics::Statistics<Chromosomes>,
call_count: &CallCountData,
chromo_count: usize,
) {
let valid_answer = vec![420.9687; chromo_count];
let delta = vec![1.0; chromo_count];
let success_rate_answer = stat
.get_results()
.get_success_rate(get_predicate_success_vec_solution(valid_answer, delta))
.unwrap();
let average_goal = stat.get_results().get_average_goal().unwrap();
let standard_deviation_goal = stat.get_results().get_standard_deviation_goal().unwrap();
println!("Run count{:15}", stat.get_run_count());
println!("Success rate:{:15.5}", success_rate_answer);
println!("Average goal:{:15.5}", average_goal);
println!(
"Standard deviation for goal:{:15.5}",
standard_deviation_goal
);
println!(
"Average goal function call count:{:15.5}",
call_count.get_average_call_count().unwrap()
);
}
fn main() {
let cpu = num_cpus::get();
let dimension = 3;
let run_count = 1000 / cpu;
println!("CPUs:{:15}", cpu);
println!("Run count per CPU:{:8}", run_count);
print!("Run optimizations... ");
let mut full_stat = statistics::Statistics::new();
let mut full_call_count = CallCountData::new();
let (tx, rx) = mpsc::channel();
for _ in 0..cpu {
let current_tx = mpsc::Sender::clone(&tx);
thread::spawn(move || {
let mut local_full_stat = statistics::Statistics::new();
let mut local_full_call_count = CallCountData::new();
for _ in 0..run_count {
let mut statistics_data = statistics::Statistics::new();
let mut call_count = CallCountData::new();
{
let mut goal_object = GoalFromFunction::new(optlib_testfunc::schwefel);
let goal = GoalCalcStatistics::new(&mut goal_object, &mut call_count);
let mut optimizer = create_optimizer(dimension, Box::new(goal));
let stat_logger =
Box::new(statistics::StatisticsLogger::new(&mut statistics_data));
let loggers: Vec<Box<dyn logging::Logger<Chromosomes>>> = vec![stat_logger];
optimizer.set_loggers(loggers);
optimizer.find_min();
}
local_full_stat.unite(statistics_data);
local_full_call_count.unite(call_count);
}
current_tx
.send((local_full_stat, local_full_call_count))
.unwrap();
});
}
for _ in 0..cpu {
let (statistics_data, call_count) = rx.recv().unwrap();
full_stat.unite(statistics_data);
full_call_count.unite(call_count);
}
println!("OK");
let result_stat_fname = "result_stat.txt";
let mut result_stat_file = File::create(result_stat_fname).unwrap();
let convergence_stat_fname = "convergence_stat.txt";
let mut convergence_stat_file = File::create(convergence_stat_fname).unwrap();
print_solution(&mut result_stat_file, &full_stat);
print_convergence_statistics(&mut convergence_stat_file, &full_stat);
print_statistics(&full_stat, &full_call_count, dimension);
}