Annealing simulation base impl
This commit is contained in:
parent
ab46566693
commit
d8b8ece8a7
@ -6,6 +6,7 @@ edition = "2024"
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
rand = "0.9.2"
|
||||||
eframe = { version = "0.33.3", default-features = false, features = ["default_fonts", "glow"] }
|
eframe = { version = "0.33.3", default-features = false, features = ["default_fonts", "glow"] }
|
||||||
|
|
||||||
[profile.dev.package.eframe]
|
[profile.dev.package.eframe]
|
||||||
|
|||||||
@ -10,6 +10,10 @@ impl Board {
|
|||||||
data: vec![0usize; size].into_boxed_slice(),
|
data: vec![0usize; size].into_boxed_slice(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
return self.data.len();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<usize> for Board {
|
impl Index<usize> for Board {
|
||||||
|
|||||||
65
lab1/src/algo/misc.rs
Normal file
65
lab1/src/algo/misc.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use super::Board;
|
||||||
|
use rand::random_range;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
pub(super) fn initializeBoard(b: &mut Board) {
|
||||||
|
for i in 0..b.len() {
|
||||||
|
b[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_range_with_hole(range: Range<usize>, hole: usize) -> usize {
|
||||||
|
assert!(
|
||||||
|
range.contains(&hole),
|
||||||
|
"Hole not in range: {hole} !in {}..{}",
|
||||||
|
range.start,
|
||||||
|
range.end
|
||||||
|
);
|
||||||
|
let shrunk = random_range(range.start..(range.end - 1));
|
||||||
|
if shrunk >= hole {
|
||||||
|
return shrunk + 1;
|
||||||
|
} else {
|
||||||
|
return shrunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn swapRandomQueensOnce(b: &mut Board) {
|
||||||
|
let i1 = random_range(0..b.len());
|
||||||
|
let i2 = random_range_with_hole(0..b.len(), i1);
|
||||||
|
|
||||||
|
let tmp = b[i1];
|
||||||
|
b[i1] = b[i2];
|
||||||
|
b[i2] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn isOnDiagonal(c1: (usize, usize), c2: (usize, usize)) -> bool {
|
||||||
|
let dist = c1.0.abs_diff(c2.0);
|
||||||
|
|
||||||
|
let diagonalPos;
|
||||||
|
if c1.1 > c2.1 {
|
||||||
|
diagonalPos = c1.1.checked_sub(dist)
|
||||||
|
} else {
|
||||||
|
diagonalPos = c1.1.checked_add(dist)
|
||||||
|
}
|
||||||
|
|
||||||
|
match diagonalPos {
|
||||||
|
None => {
|
||||||
|
// if coordinate over(under)flowed, it can be eq to another valid coordinate
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Some(i2e) => return c2.1 == i2e,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn isOnDiagonal_test1() {
|
||||||
|
assert!(isOnDiagonal((0, 0), (1, 1)))
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn isOnDiagonal_test2() {
|
||||||
|
assert!(isOnDiagonal((1, 0), (0, 1)))
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn isOnDiagonal_test3() {
|
||||||
|
assert!(!isOnDiagonal((0, 0), (0, 1)))
|
||||||
|
}
|
||||||
@ -1 +1,5 @@
|
|||||||
mod board;
|
mod board;
|
||||||
|
mod misc;
|
||||||
|
mod simulation;
|
||||||
|
|
||||||
|
pub(crate) use board::Board;
|
||||||
77
lab1/src/algo/simulation.rs
Normal file
77
lab1/src/algo/simulation.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
use eframe::emath::Numeric;
|
||||||
|
use rand::{random, random_range};
|
||||||
|
use crate::algo::Board;
|
||||||
|
use crate::algo::misc::{initializeBoard, isOnDiagonal, swapRandomQueensOnce};
|
||||||
|
|
||||||
|
pub(super) fn calculateEnergy(b: &Board) -> f64 {
|
||||||
|
let mut conflictsCount = 0usize;
|
||||||
|
for i1 in 0..b.len() {
|
||||||
|
for i2 in (i1 + 1)..b.len() {
|
||||||
|
if isOnDiagonal((i1, b[i1]), (i2, b[i2])) {
|
||||||
|
conflictsCount += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return conflictsCount.to_f64()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct State {
|
||||||
|
board: Board,
|
||||||
|
energy: f64
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AnnealingConfig {
|
||||||
|
pub initialTemperature: f64,
|
||||||
|
pub targetTemperature: f64,
|
||||||
|
pub cooldownCoefficient: f64,
|
||||||
|
pub iterationsPerAge: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn simulateAnnealing(len: usize, config: &AnnealingConfig) -> Board {
|
||||||
|
assert!(config.targetTemperature < config.initialTemperature);
|
||||||
|
assert!((0f64..1f64).contains(&config.cooldownCoefficient));
|
||||||
|
|
||||||
|
let mut currentState = State {
|
||||||
|
board: Board::alloc(len),
|
||||||
|
energy: f64::INFINITY
|
||||||
|
};
|
||||||
|
initializeBoard(&mut currentState.board);
|
||||||
|
currentState.energy = calculateEnergy(¤tState.board);
|
||||||
|
|
||||||
|
let mut bestState = currentState.clone();
|
||||||
|
|
||||||
|
let mut currentTemperature = config.initialTemperature;
|
||||||
|
|
||||||
|
while currentTemperature > config.targetTemperature {
|
||||||
|
|
||||||
|
for _ in 0..config.iterationsPerAge {
|
||||||
|
let mut newState = currentState.clone();
|
||||||
|
swapRandomQueensOnce(&mut newState.board);
|
||||||
|
newState.energy = calculateEnergy(&newState.board);
|
||||||
|
|
||||||
|
if newState.energy <= currentState.energy {
|
||||||
|
currentState = newState
|
||||||
|
} else {
|
||||||
|
let test = random::<f64>();
|
||||||
|
let delta = newState.energy - currentState.energy;
|
||||||
|
let calc = (-delta/test).exp();
|
||||||
|
|
||||||
|
if calc > test {
|
||||||
|
currentState = newState
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentState.energy < bestState.energy {
|
||||||
|
bestState = currentState.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentTemperature *= config.cooldownCoefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestState.board;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user