From 6584d8d24d2a97f3bac3c75306792e160ed74854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20Kaan=20G=C3=9CM=C3=9C=C5=9E?= <96421894+Tahinli@users.noreply.github.com> Date: Wed, 20 Nov 2024 00:20:40 +0300 Subject: [PATCH] feat: :sparkles: differential_evolution --- README.md | 4 +- differential_evolution/Cargo.toml | 9 ++ differential_evolution/src/main.rs | 141 +++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 differential_evolution/Cargo.toml create mode 100644 differential_evolution/src/main.rs diff --git a/README.md b/README.md index 2d2a4d7..12f0a14 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ ## Steepest Descent -1- We need starting solution x^t. Zeroise the iteration which is t. Specify tolerance value as ε. +1- We need starting solution x^t. Reset the iteration which is t. Specify tolerance value as ε. 2- at x^t point calculate g^t gradient and ||g^t|| then if ||g^t|| <= ε stop it, else continue. -3- Specfify road direction as d^t = -g^t. +3- Specify road direction as d^t = -g^t. 4- Calculate f(x^t + a^t*d^t) as like a^t (step size) is minimum. diff --git a/differential_evolution/Cargo.toml b/differential_evolution/Cargo.toml new file mode 100644 index 0000000..4bee5b6 --- /dev/null +++ b/differential_evolution/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "differential_evolution" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" diff --git a/differential_evolution/src/main.rs b/differential_evolution/src/main.rs new file mode 100644 index 0000000..60d0046 --- /dev/null +++ b/differential_evolution/src/main.rs @@ -0,0 +1,141 @@ +use std::io; + +use rand::Rng; + +fn main() { + println!("Hello, world!"); + + println!("Decision Variable Count"); + let decision_variable_count = get_float_input() as usize; + + println!("Population Number"); + let population_number = get_float_input() as u64; + + println!("Crossover Rate"); + let crossover_rate = get_float_input(); + + println!("Scale Factor"); + let scale_factor = get_float_input(); + + println!("Upper Bound"); + let upper_bound = get_float_input(); + + println!("Lower Bound"); + let lower_bound = get_float_input(); + + println!("Iteration"); + let iteration = get_float_input() as usize; + + let mut population = create_population( + population_number, + decision_variable_count, + upper_bound, + lower_bound, + ); + + for _ in 0..iteration { + for (current_location, element) in population.clone().iter().enumerate() { + let new_volunteer = mutate_and_recombine( + current_location, + crossover_rate, + scale_factor, + decision_variable_count, + population.clone(), + ); + + let current_calculation = calculate(element.clone()); + let new_calculation = calculate(new_volunteer.clone()); + if new_calculation < current_calculation { + println!( + "Changed | Old = {} | New {}", + current_calculation, new_calculation + ); + population[current_location] = new_volunteer; + } + } + } + + println!("{:#?}", population); +} + +fn get_float_input() -> f64 { + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); + let input: f64 = input.trim().parse().unwrap(); + input +} + +fn create_population( + population_number: u64, + decision_variable_count: usize, + upper_bound: f64, + lower_bound: f64, +) -> Vec> { + let mut population = vec![vec![decision_variable_count as f64]; population_number as usize]; + + for i in 0..population_number { + let mut randomized_single_dimension = vec![]; + for _ in 0..decision_variable_count { + randomized_single_dimension + .push(rand::thread_rng().gen_range(lower_bound..=upper_bound)); + } + population[i as usize] = randomized_single_dimension; + } + population +} + +fn calculate(decision_variables: Vec) -> f64 { + let mut result = 0.0; + for element in decision_variables { + result += element * element; + } + result +} + +fn mutate_and_recombine( + current_location: usize, + crossover_rate: f64, + scale_factor: f64, + decision_variable_count: usize, + population: Vec>, +) -> Vec { + let definite_random_decision_index: usize = + rand::thread_rng().gen_range(0..=decision_variable_count); + let mut definite_random = rand::thread_rng().gen_range(0..population.len()); + + while definite_random == current_location { + definite_random = rand::thread_rng().gen_range(0..population.len()); + } + + let mut chosen_indices = vec![]; + for _ in 0..3 { + chosen_indices.sort(); + + let mut maybe = rand::thread_rng().gen_range(0..population.len()); + while maybe == current_location || chosen_indices.binary_search(&maybe).is_ok() { + maybe = rand::thread_rng().gen_range(0..population.len()); + } + chosen_indices.push(maybe); + } + + let ingredients: Vec> = vec![ + population[chosen_indices[0]].clone(), + population[chosen_indices[1]].clone(), + population[chosen_indices[2]].clone(), + ]; + + let mut new_volunteer = vec![]; + + for i in 0..decision_variable_count { + if rand::thread_rng().gen_range(0.0..=1.0) < crossover_rate + || i == definite_random_decision_index + { + new_volunteer + .push(ingredients[0][i] + scale_factor * (ingredients[1][i] - ingredients[2][i])); + } else { + new_volunteer.push(population[definite_random][i]); + } + } + + new_volunteer +}