feat: ✨ simulated_annealing
This commit is contained in:
parent
a573b86474
commit
e9cd102d0c
2 changed files with 129 additions and 0 deletions
9
simulated_annealing/Cargo.toml
Normal file
9
simulated_annealing/Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "simulated_annealing"
|
||||
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"
|
120
simulated_annealing/src/main.rs
Normal file
120
simulated_annealing/src/main.rs
Normal file
|
@ -0,0 +1,120 @@
|
|||
use rand::Rng;
|
||||
use std::io;
|
||||
|
||||
enum Bound {
|
||||
Upper,
|
||||
Lower,
|
||||
Nothing,
|
||||
}
|
||||
|
||||
const E: f64 = std::f64::consts::E;
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
|
||||
println!("Temperature = ");
|
||||
let temperature = get_float_input();
|
||||
|
||||
println!("Iteration = ");
|
||||
let iteration: u64 = get_float_input() as u64;
|
||||
|
||||
println!("Upper Bound = ");
|
||||
let upper_bound = get_float_input();
|
||||
|
||||
println!("Lower Bound = ");
|
||||
let lower_bound = get_float_input();
|
||||
|
||||
let mut x1: f64 = rand::thread_rng().gen_range(lower_bound..=upper_bound);
|
||||
let mut x2: f64 = rand::thread_rng().gen_range(lower_bound..=upper_bound);
|
||||
|
||||
let mut give_up_counter: u8 = 0;
|
||||
for i in 0..iteration {
|
||||
x1 = bound_detective(x1, upper_bound, lower_bound);
|
||||
x2 = bound_detective(x2, upper_bound, lower_bound);
|
||||
|
||||
let new_x1: f64;
|
||||
let new_x2: f64;
|
||||
|
||||
let where_to_go = rand::thread_rng().gen_range(0.0..=1.0);
|
||||
if where_to_go > 0.7 {
|
||||
new_x1 = rand::thread_rng().gen_range(x1..=(x1 + ((5.0 * x1) / 100.0)));
|
||||
new_x2 = rand::thread_rng().gen_range(x2..=(x2 + ((5.0 * x2) / 100.0)));
|
||||
} else if where_to_go > 0.5 {
|
||||
new_x1 = rand::thread_rng().gen_range(x1..=(x1 + ((5.0 * x1) / 100.0)));
|
||||
new_x2 = rand::thread_rng().gen_range((x2 - ((5.0 * x2) / 100.0))..=x2);
|
||||
} else if where_to_go > 0.3 {
|
||||
new_x1 = rand::thread_rng().gen_range((x1 - ((5.0 * x1) / 100.0))..=x1);
|
||||
new_x2 = rand::thread_rng().gen_range(x2..=(x2 + ((5.0 * x2) / 100.0)));
|
||||
} else {
|
||||
new_x1 = rand::thread_rng().gen_range((x1 - ((5.0 * x1) / 100.0))..=x1);
|
||||
new_x2 = rand::thread_rng().gen_range((x2 - ((5.0 * x2) / 100.0))..=x2);
|
||||
}
|
||||
|
||||
let give_up_return = give_up(x1, x2, new_x1, new_x2, give_up_counter);
|
||||
if give_up_return.0 {
|
||||
println!("Time to give up\n Iteration = {}", i);
|
||||
break;
|
||||
}
|
||||
give_up_counter = give_up_return.1;
|
||||
|
||||
let original_result = calculate(x1, x2);
|
||||
let new_result = calculate(new_x1, new_x2);
|
||||
let neighbour_dif = new_result - original_result;
|
||||
let temp_random = rand::thread_rng().gen_range(0.0..=1.0);
|
||||
let simulated_annealing_func = E.powf(-1.0 * neighbour_dif / temperature);
|
||||
|
||||
if neighbour_dif <= 0.0 || simulated_annealing_func > temp_random {
|
||||
x1 = new_x1;
|
||||
x2 = new_x2;
|
||||
}
|
||||
}
|
||||
println!("x1 = {}\nx2 = {}\nResult = {}", x1, x2, calculate(x1, x2));
|
||||
}
|
||||
|
||||
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 calculate(x1: f64, x2: f64) -> f64 {
|
||||
(x1 * x1) + (x2 * x2)
|
||||
}
|
||||
|
||||
fn bound_detective(x: f64, upper_bound: f64, lower_bound: f64) -> f64 {
|
||||
if x > upper_bound {
|
||||
magic_trick(upper_bound, Bound::Upper)
|
||||
} else if x < lower_bound {
|
||||
magic_trick(lower_bound, Bound::Lower)
|
||||
} else {
|
||||
magic_trick(x, Bound::Nothing)
|
||||
}
|
||||
}
|
||||
|
||||
fn magic_trick(x: f64, what_happened: Bound) -> f64 {
|
||||
match what_happened {
|
||||
Bound::Upper => x + (-0.000000001 * x / 100.0),
|
||||
Bound::Lower => x + (0.000000001 * x / 100.0),
|
||||
Bound::Nothing => x,
|
||||
}
|
||||
}
|
||||
|
||||
fn give_up(x1: f64, x2: f64, new_x1: f64, new_x2: f64, mut give_up_counter: u8) -> (bool, u8) {
|
||||
if x1 == 0.0 && x2 == 0.0 {
|
||||
println!("Touched 0.0 for both variables");
|
||||
return (true, give_up_counter);
|
||||
}
|
||||
|
||||
if give_up_counter > 10 {
|
||||
println!("Can't move anymore");
|
||||
return (true, give_up_counter);
|
||||
}
|
||||
|
||||
if x1 == new_x1 && x2 == new_x2 {
|
||||
give_up_counter += 1;
|
||||
(false, give_up_counter)
|
||||
} else {
|
||||
give_up_counter = 0;
|
||||
(false, give_up_counter)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue