#pragma once
#include <cmath>
#include <functional>
#include <limits>
#include <random>
namespace frc {
template <typename State>
class SimulatedAnnealing {
public:
constexpr SimulatedAnnealing(double initialTemperature,
std::function<State(const State&)> neighbor,
std::function<double(const State&)> cost)
: m_initialTemperature{initialTemperature},
m_neighbor{neighbor},
m_cost{cost} {}
State Solve(const State& initialGuess, int iterations) {
State minState = initialGuess;
double minCost = std::numeric_limits<double>::infinity();
std::random_device rd;
std::mt19937 gen{rd()};
std::uniform_real_distribution<> distr{0.0, 1.0};
State state = initialGuess;
double cost = m_cost(state);
for (int i = 0; i < iterations; ++i) {
double temperature = m_initialTemperature / i;
State proposedState = m_neighbor(state);
double proposedCost = m_cost(proposedState);
double deltaCost = proposedCost - cost;
double acceptanceProbability = std::exp(-deltaCost / temperature);
if (deltaCost < 0 || acceptanceProbability >= distr(gen)) {
state = proposedState;
cost = proposedCost;
}
if (proposedCost < minCost) {
minState = proposedState;
minCost = proposedCost;
}
}
return minState;
}
private:
double m_initialTemperature;
std::function<State(const State&)> m_neighbor;
std::function<double(const State&)> m_cost;
};
}