1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use ndarray::{Array1, Array2, ArrayView1};
use num::Bounded;
use rand::{rngs::SmallRng, seq::SliceRandom, thread_rng, Rng, SeedableRng};
use serde::{Deserialize, Serialize};
use std::{
    fs::create_dir_all,
    path::{Path, PathBuf},
};

use crate::TspDistance;
use std::hash::{Hash, Hasher};

mod ant_colony_optimization;
mod der;
mod opt2;
mod ser;

pub struct TspSolver<T: TspDistance> {
    /// used for distribute system
    problem_id: String,
    objects: Array1<T>,
    best_path: Array1<usize>,
    best_distance: f64,
    rng: SmallRng,
    steps: usize,
    improves: usize,
    check_points: PathBuf,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TspRecord {
    pub problem: String,
    pub improves: usize,
    pub steps: usize,
    pub best_distance: f64,
    pub best_path: Array1<usize>,
}

impl Eq for TspRecord {}

impl PartialEq<Self> for TspRecord {
    fn eq(&self, other: &Self) -> bool {
        self.problem == other.problem && self.improves == other.improves
    }
}

impl Hash for TspRecord {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.problem.hash(state);
        self.improves.hash(state);
    }
}

impl<T> TspSolver<T>
where
    T: TspDistance,
{
    pub fn new<P: AsRef<Path>>(dir: P, objects: Array1<T>) -> Self {
        let rng = SmallRng::from_rng(thread_rng()).unwrap();
        let best_path = initialize_path(objects.len());
        TspSolver {
            problem_id: String::new(),
            objects,
            best_path,
            best_distance: f64::max_value(),
            rng,
            steps: 0,
            improves: 0,
            check_points: dir.as_ref().to_path_buf(),
        }
    }
    pub fn with_save_points<P: AsRef<Path>>(mut self, dir: P) -> Self {
        self.check_points = dir.as_ref().to_path_buf();
        match create_dir_all(&self.check_points) {
            Ok(_) => {}
            Err(e) => {
                tracing::error!("{e}")
            }
        }
        self
    }
}

// impl<T> TspSolver<T> {
//     pub fn lkh_solve(&mut self, ants: usize, iterations: usize) -> (Array1<usize>, f64) {
//         todo!()
//     }
// }

fn initialize_path(num: usize) -> Array1<usize> {
    let mut path = Array1::zeros((num,));
    for i in 0..num {
        path[i] = i;
    }
    path
}