Skip to content

Commit

Permalink
Merge branch 'release/0.17.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
lucidfrontier45 committed Sep 8, 2024
2 parents 73d0274 + 135f89f commit f6f0ee5
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ categories = ["algorithms"]
repository = "https://github.com/lucidfrontier45/localsearch"
license-file = "LICENSE"
readme = "README.md"
version = "0.16.1"
version = "0.17.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
5 changes: 3 additions & 2 deletions examples/tsp_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ impl Default for DequeTabuList {
}
}

impl TabuList<TSPModel> for DequeTabuList {
impl TabuList for DequeTabuList {
type Item = TransitionType;
fn contains(&self, transition: &TransitionType) -> bool {
let (_, inserted_edges) = transition;
inserted_edges
Expand Down Expand Up @@ -285,7 +286,7 @@ fn main() {
pb.reset();

println!("run tabu search");
let optimizer = TabuSearchOptimizer::<TSPModel, DequeTabuList>::new(patience, 200, 10, 20);
let optimizer = TabuSearchOptimizer::<DequeTabuList>::new(patience, 200, 10, 20);
let (final_solution, final_score) = optimizer
.run_with_callback(
&tsp_model,
Expand Down
39 changes: 21 additions & 18 deletions src/optim/tabu_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,37 @@ use crate::{
use super::LocalSearchOptimizer;

/// Trait that a tabu list must satisfies
pub trait TabuList<M: OptModel>: Default {
pub trait TabuList: Default {
/// The type of item stored in the tabu list.
type Item: Clone + Sync + Send;

/// Set the length of the tabu list
fn set_size(&mut self, n: usize);

/// Check if the item is a Tabu
fn contains(&self, transition: &M::TransitionType) -> bool;
fn contains(&self, transition: &Self::Item) -> bool;

/// Append the item to the list
fn append(&mut self, transition: M::TransitionType);
fn append(&mut self, transition: Self::Item);
}

/// Optimizer that implements the tabu search algorithm
pub struct TabuSearchOptimizer<M: OptModel, T: TabuList<M>> {
pub struct TabuSearchOptimizer<T: TabuList> {
patience: usize,
n_trials: usize,
return_iter: usize,
default_tabu_size: usize,
phantom: PhantomData<(M, T)>,
phantom: PhantomData<T>,
}

fn find_accepted_solution<M, L, O>(
samples: Vec<(M::SolutionType, M::TransitionType, O)>,
fn find_accepted_solution<M, L>(
samples: Vec<(M::SolutionType, M::TransitionType, M::ScoreType)>,
tabu_list: &L,
best_score: O,
) -> Option<(M::SolutionType, M::TransitionType, O)>
best_score: M::ScoreType,
) -> Option<(M::SolutionType, M::TransitionType, M::ScoreType)>
where
M: OptModel,
L: TabuList<M>,
O: Ord,
L: TabuList<Item = M::TransitionType>,
{
for (solution, transition, score) in samples.into_iter() {
#[allow(unused_parens)]
Expand All @@ -55,7 +57,7 @@ where
None
}

impl<M: OptModel, T: TabuList<M>> TabuSearchOptimizer<M, T> {
impl<T: TabuList> TabuSearchOptimizer<T> {
/// Constructor of TabuSearchOptimizer
///
/// - `patience` : the optimizer will give up
Expand All @@ -78,10 +80,9 @@ impl<M: OptModel, T: TabuList<M>> TabuSearchOptimizer<M, T> {
}
}

impl<M, T> TabuSearchOptimizer<M, T>
impl<T> TabuSearchOptimizer<T>
where
M: OptModel,
T: TabuList<M>,
T: TabuList,
{
#[allow(clippy::too_many_arguments)]
/// Start optimization
Expand All @@ -93,7 +94,7 @@ where
/// - `time_limit`: maximum iteration time
/// - `callback` : callback function that will be invoked at the end of each iteration
/// - `tabu_list` : initial tabu list
fn optimize_with_tabu_list(
fn optimize_with_tabu_list<M: OptModel<TransitionType = T::Item>>(
&self,
model: &M,
initial_solution: M::SolutionType,
Expand Down Expand Up @@ -132,7 +133,7 @@ where

samples.sort_unstable_by_key(|(_, _, score)| *score);

let res = find_accepted_solution(samples, &tabu_list, best_score);
let res = find_accepted_solution::<M, T>(samples, &tabu_list, best_score);

if let Some((solution, trans, score)) = res {
if score < best_score {
Expand Down Expand Up @@ -168,7 +169,9 @@ where
}
}

impl<M: OptModel, T: TabuList<M>> LocalSearchOptimizer<M> for TabuSearchOptimizer<M, T> {
impl<T: TabuList, M: OptModel<TransitionType = T::Item>> LocalSearchOptimizer<M>
for TabuSearchOptimizer<T>
{
#[doc = " Start optimization"]
fn optimize(
&self,
Expand Down
5 changes: 3 additions & 2 deletions src/tests/test_tabu_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ impl Default for MyTabuList {
}
}

impl TabuList<QuadraticModel> for MyTabuList {
impl TabuList for MyTabuList {
type Item = TransitionType;
fn set_size(&mut self, n: usize) {
self.buff = RingBuffer::new(n);
}
Expand All @@ -47,7 +48,7 @@ impl TabuList<QuadraticModel> for MyTabuList {
#[test]
fn test() {
let model = QuadraticModel::new(3, vec![2.0, 0.0, -3.5], (-10.0, 10.0));
let opt = TabuSearchOptimizer::<QuadraticModel, MyTabuList>::new(1000, 25, 5, 10);
let opt = TabuSearchOptimizer::<MyTabuList>::new(1000, 25, 5, 10);
let (final_solution, final_score) = opt
.run(&model, None, 10000, Duration::from_secs(10))
.unwrap();
Expand Down

0 comments on commit f6f0ee5

Please sign in to comment.