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::(); 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; }