#pragma once
#include <algorithm>
#include <future>
#include <span>
#include <gch/small_vector.hpp>
#include "sleipnir/optimization/solver/exit_status.hpp"
#include "sleipnir/util/function_ref.hpp"
namespace slp {
template <typename DecisionVariables>
struct MultistartResult {
ExitStatus status;
double cost;
DecisionVariables variables;
};
template <typename DecisionVariables>
MultistartResult<DecisionVariables> Multistart(
function_ref<MultistartResult<DecisionVariables>(
const DecisionVariables& initial_guess)>
solve,
std::span<const DecisionVariables> initial_guesses) {
gch::small_vector<std::future<MultistartResult<DecisionVariables>>> futures;
futures.reserve(initial_guesses.size());
for (const auto& initial_guess : initial_guesses) {
futures.emplace_back(std::async(std::launch::async, solve, initial_guess));
}
gch::small_vector<MultistartResult<DecisionVariables>> results;
results.reserve(futures.size());
for (auto& future : futures) {
results.emplace_back(future.get());
}
return *std::ranges::min_element(results, [](const auto& a, const auto& b) {
if (a.status == ExitStatus::SUCCESS && b.status != ExitStatus::SUCCESS) {
return true;
}
return a.cost < b.cost;
});
}
}