10 个版本 (破坏性更新)
新 0.14.0 | 2024年8月12日 |
---|---|
0.13.0 | 2024年7月26日 |
0.12.0 | 2023年12月26日 |
0.11.0 | 2023年11月4日 |
0.9.0 | 2023年2月13日 |
#240 在 算法
每月414 次下载
50KB
962 行
localsearch
Rust本地搜索优化库
实现算法
所有算法都使用Rayon并行化。
- 爬山法。
- 禁忌搜索。
- 模拟退火
- ε贪婪搜索,爬山法的一个变体,即使试验解的得分比之前的一个更差,也会以恒定的概率接受试验解。
- 相对退火,模拟退火的一个变体,它使用相对得分差来计算转换概率。
- 逻辑退火,相对退火的一个变体,它使用逻辑函数而不是简单的指数。
如何使用
您需要实现自己的模型,该模型实现了OptModel
特质。实际的优化由每个算法函数处理。以下是一个使用爬山算法优化二次函数的简单示例。
use std::time::Duration;
use anyhow::Result as AnyResult;
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
use localsearch::{
optim::{HillClimbingOptimizer, LocalSearchOptimizer},
OptModel, OptProgress,
};
use ordered_float::NotNan;
use rand::{self, distributions::Uniform, prelude::Distribution};
type SolutionType = Vec<f64>;
type ScoreType = NotNan<f64>;
#[derive(Clone)]
struct QuadraticModel {
k: usize,
centers: Vec<f64>,
dist: Uniform<f64>,
}
impl QuadraticModel {
fn new(k: usize, centers: Vec<f64>, value_range: (f64, f64)) -> Self {
let (low, high) = value_range;
let dist = Uniform::new(low, high);
Self { k, centers, dist }
}
fn evaluate_solution(&self, solution: &SolutionType) -> NotNan<f64> {
let score = (0..self.k)
.into_iter()
.map(|i| (solution[i] - self.centers[i]).powf(2.0))
.sum();
NotNan::new(score).unwrap()
}
}
impl OptModel for QuadraticModel {
type SolutionType = SolutionType;
type TransitionType = ();
type ScoreType = ScoreType;
fn generate_random_solution<R: rand::Rng>(
&self,
rng: &mut R,
) -> AnyResult<(Self::SolutionType, Self::ScoreType)> {
let solution = self.dist.sample_iter(rng).take(self.k).collect::<Vec<_>>();
let score = self.evaluate_solution(&solution);
Ok((solution, score))
}
fn generate_trial_solution<R: rand::Rng>(
&self,
current_solution: Self::SolutionType,
_current_score: Self::ScoreType,
rng: &mut R,
) -> (Self::SolutionType, Self::TransitionType, NotNan<f64>) {
let k = rng.gen_range(0..self.k);
let v = self.dist.sample(rng);
let mut new_solution = current_solution;
new_solution[k] = v;
let score = self.evaluate_solution(&new_solution);
(new_solution, (), score)
}
}
fn create_pbar(n_iter: u64) -> ProgressBar {
let pb = ProgressBar::new(n_iter);
pb.set_style(
ProgressStyle::default_bar()
.template(
"{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {pos}/{len} (eta={eta}) {msg} ",
).unwrap()
.progress_chars("#>-")
);
pb.set_draw_target(ProgressDrawTarget::stderr_with_hz(10));
pb
}
fn main() {
let model = QuadraticModel::new(3, vec![2.0, 0.0, -3.5], (-10.0, 10.0));
println!("running Hill Climbing optimizer");
let n_iter = 10000;
let time_limit = Duration::from_secs_f32(1.0);
let patiance = 1000;
let n_trials = 50;
let opt = HillClimbingOptimizer::new(patiance, n_trials);
let pb = create_pbar(n_iter as u64);
let callback = |op: OptProgress<SolutionType, ScoreType>| {
pb.set_message(format!("best score {:e}", op.score.into_inner()));
pb.set_position(op.iter as u64);
};
let res = opt.run(&model, None, n_iter, time_limit, Some(&callback), ());
pb.finish();
dbg!(res.unwrap());
}
此外,您还可以向您的模型添加preprocess_initial_solution
和postprocess_final_solution
。在优化迭代开始之前调用preprocess_initial_solution
。如果没有提供初始解,则调用generate_initial_solution
,然后传递生成的解给preprocess_initial_solution
。在优化迭代之后调用postprocess_final_solution
。
更多详细信息可以在API文档、示例和测试代码中找到。
依赖项
~2–2.8MB
~56K SLoC