This is a simple Rust implementation of the paper Coupled Simulated Annealing by Xavier-de-Sousa et al. Compared to regular parallel Simulated Annealing (SA) implementations, instead of running multiple runs in parallel to explore the search space, the parallel runs are instead coupled together through a parameter
In regular SA, we have
Essentially, the coupling term indicates the energy levels of the overall population across all coupled systems (the parallel runs), which gives a better indication the energy level of a given state
The paper derives a number of methods: CSA-MuSA, -BA, -M and -MwVC. I have implemented the first three in the code.
On the Ackley test function in three dimensions, with a total of 40.000 evaluations across all threads used, using more threads seems to certainly help, despite there being fewer function evaluations per individual thread. The information sharing between threads is having a noticeable effect.
The underlying algorithm is implemented entirely using generics. By defining a generation function (which takes the current state, the temperature, and a random number generator object), you are free to define a sampling process that generates a new object of the same type. Usually, that would be a Vec<f64>
object, but the code is written in a way that categoricals will also work, because I wanted this to work for a travelling salesman/vehicle routing-type problem too.
Following sampling, the current state coupled_simulated_annealing
function.
The code includes three of the methods derived in the paper, their associated method for calculating
- Exponential:
$T^{k+1} = \gamma t^{(k)}$ - Fast annealing:
$T^{k+1} = t^{(1)} / k$ - Logarithmic:
$T^{(1)} \cdot \ln (2) / \ln (k + 1)$
Additionally, there is a benchmark function with some Python code included to evaluate different parameters. After modifications, be sure to test the code with cargo test
.
Simply clone the repo and run cargo run --release
. main.rs
has an example ready using some convenience functions, and can directly be modified.
I came across this paper while studying simulated annealing algorithms and liked it a lot. It's a great idea, based on thermodynamic concepts (multiple connected thermodynamic heat baths), and once you get the idea, very intuitive. I was also curious if I could implement everything using generics in Rust: this is my first time using them. Having an excuse to explore Arc/Mutex/Barrier
concepts in parallel Rust was also a major reason to look into this.