๐๐ป hello! I've recently started to experiment with simulated annealing libraries. In terms of ruby annealer gems, this one seems to be the most recently updated and has the most tests. I've used it in a project of mine and am happy with its performance, but it does make a few assumptions about the annealing process and I had to monkey patch a few things to get it working with my solution. I'd like to contribute those back to this project. Are you open to discussing them and to contributions? Here's what I'm proposing:
Add a way to specify a custom move function that defaults to what Metal#swap_collection
does now.
Metal#swap_collection
assumes that the collection is a flat array and a neighboring state can be found by swapping elements. In my case, I'm working with a two dimensional array and neighboring states are created from shifting elements of one internal array to another. I'm sure there are other use cases that might call for more complicated object manipulations. Being able to specify a custom move function that receives the current collection
and returns the next collection state would allow this library to be able to anneal more complex objects.
Add a way to specify termination conditions
The simulated annealing algorithm definition typically provides for the ability to specify some condition that will halt the annealing process other than the temperature reaching 0. This could be a "good enough" energy threshold, a temperature other than 0, or some other arbitrary condition. Right now Simulator#run
will continue until the temperature reaches 0 and then return whatever state it had settled on. It would be beneficial to be able to specify a function that receives the current metal
and temperature
, and returns a boolean result as to whether to continue annealing. In my case, for example, the first state that has an energy cost of 0, including the initial state, is considered "good enough" and there's no need to continue annealing.
Add a way to specify a different cooling function
Simulator#cool_down
provides a linear temperature reduction algorithm, but simulated annealing is not always linear. There are allowances in the definition for raising, lowering, and holding the temperature until certain conditions are met. It would be useful to provide a way to specify a custom cooling method that takes the current metal
, and temperature
, and returns the new temperature, such that it could operate linearly, geometrically, exponentially, or based on some other custom formula with the current state in mind. It would use the linear Simulator#cool_down
as the default.
With those three changes, each step of the annealing process becomes configurable with reasonable defaults. None of these changes are particularly difficult, and all seem to fit in the same framework as what you already provide for specifying a custom energy calculator:
- provide a new configuration option that can hold a lambda
- set a default if nothing is provided
- allow lambdas to be passed in at run time
- call the passed or configured lambda
The biggest change would be that we would probably want to switch to keyword arguments for Simulator#run
and/or add the ability to pass them to Simulator#initialize
, and that's why I wanted to run this by you first since it changes the interface a bit. (We could also do it with positional arguments without changing the existing interface, but that makes it harder to work with IMO.)