| 
					
				 | 
			
			
				@@ -0,0 +1,230 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use std::collections::HashSet; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use rand::Rng; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use clap::Parser; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#[derive(Parser, Debug)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#[command(about, long_about=None)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+struct Args{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[arg(short='n', long="ants")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    num_ants: usize, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[arg(short, long)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iterations: usize, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[arg(short, long)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    alpha: f64, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[arg(short, long)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    beta: f64, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[arg(short, long)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    evaporation: f64, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[arg(short, long)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    q_value: f64, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[clap()] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    edges: Vec<String>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#[derive(Debug)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+struct Edge { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    from: String, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    to: String, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    distance: f64, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pheromone: f64, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+fn parse_edges(edge_strs: &[String]) -> Vec<Edge> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut edges = Vec::new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for edge_str in edge_strs { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let parts: Vec<&str> = edge_str.split(['=', '-']).collect(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if parts.len() != 3 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            panic!("Invalid edge format: {}", edge_str); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let distance = parts[2].parse::<f64>() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .expect("Distance must be a number"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        edges.push(Edge { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            from: parts[0].to_string(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            to: parts[1].to_string(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            distance, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            pheromone: 1.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        edges.push(Edge { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            from: parts[1].to_string(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            to: parts[0].to_string(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            distance, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            pheromone: 1.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    edges 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+fn construct_solution( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    edges: &[Edge], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    vertices: &Vec<String>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    alpha: f64, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    beta: f64, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+) -> Vec<String> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut rng = rand::thread_rng(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Текущая вершина (стартовая) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut current = vertices.iter().nth(0).unwrap().clone(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Текущий построенный путь 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut path = vec![current.clone()]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Список непосещенных вершин 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut unvisited: HashSet<_> = vertices.iter().cloned().filter(|v| v != ¤t).collect(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Пока существуют непосещенные вершины 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    while !unvisited.is_empty() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Список доступных ребер, на которые мы можем пойти из текущей вершины 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let available_edges: Vec<_> = edges.iter() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .filter(|e| e.from == current && unvisited.contains(&e.to)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .collect(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Если нет доступных ребер 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if available_edges.is_empty() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Сумма ощущаемых феромонов 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let total: f64 = available_edges.iter() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .map(|e| (e.pheromone.powf(alpha)) * ((1.0 / e.distance).powf(beta))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .sum(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Вероятность пойти на каждое ребро 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let probabilities: Vec<f64> = available_edges.iter() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .map(|e| (e.pheromone.powf(alpha)) * ((1.0 / e.distance).powf(beta)) / total) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .collect(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut cumsum = 0.0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let rand_val = rng.gen::<f64>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Выбираем следующее ребро 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let selected = available_edges.iter().zip(probabilities.iter()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .find(|(_, &p)| { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                cumsum += p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                rand_val <= cumsum 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .map(|(e, _)| e) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Переходим на следующую вершину 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        current = selected.to.clone(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Сохраняем новую текущую вершину в путь 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        path.push(current.clone()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Удаляем посещенную вершину из списка непосещенных 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        unvisited.remove(¤t); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    path 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+fn calculate_path_length(path: &[String], edges: &[Edge]) -> f64 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Считаем длину пути 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    path.windows(2) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .map(|window| { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let from = &window[0]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let to = &window[1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            edges.iter() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .find(|e| e.from == *from && e.to == *to) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .map(|e| e.distance) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .unwrap() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .sum() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+fn update_pheromones( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    edges: &mut [Edge], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    solutions: &[(Vec<String>, f64)], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    evaporation: f64,  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    q_value: f64, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Испаряем часть феромонов со всех рёбер графа 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for edge in edges.iter_mut() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        edge.pheromone *= 1.0 - evaporation; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Для каждого найденного пути добавляем новые феромоны 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (path, length) in solutions { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Вычисляем количество феромонов для отложения 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Чем короче путь, тем больше феромонов откладывается 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let deposit = q_value / length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Проходим по всем парам последовательных вершин в пути 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        path.windows(2).for_each(|window| { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let from = &window[0]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let to = &window[1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Добавляем феромоны на прямое ребро (from -> to) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if let Some(edge) = edges.iter_mut().find(|e| e.from == *from && e.to == *to) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                edge.pheromone += deposit; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Добавляем феромоны на обратное ребро (to -> from),  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // так как граф неориентированный 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if let Some(edge) = edges.iter_mut().find(|e| e.from == *to && e.to == *from) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                edge.pheromone += deposit; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+fn main() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Парсим аргументы командной строки 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let opt = Args::parse(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut edges = parse_edges(&opt.edges); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Собираем все вершины 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let vertices: Vec<String> = edges.iter() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .flat_map(|e| vec![e.from.clone(), e.to.clone()]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .collect(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut best_solution = None; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let mut best_length = f64::INFINITY; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Основной цикл итераций 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for _ in 0..opt.iterations { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut solutions = Vec::new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for _ in 0..opt.num_ants { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Строим путь 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let path = construct_solution(&edges, &vertices, opt.alpha, opt.beta); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Находим длину пути 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let length = calculate_path_length(&path, &edges); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Сохраняем решение 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            solutions.push((path.clone(), length)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if length < best_length { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                best_length = length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                best_solution = Some(path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        update_pheromones(&mut edges, &solutions, opt.evaporation, opt.q_value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Если решение найдено 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if let Some(_path) = best_solution { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut path = _path.clone(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Добавляем путь до стартовой вершины 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        path.push(vertices.iter().nth(0).clone().unwrap().to_string()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        best_length += edges.iter().filter(|e| e.from == path.first().unwrap().to_string() && e.to == _path.last().unwrap().to_string()).nth(0).unwrap().distance; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        println!("Best path: {}", path.join(" -> ")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut sum = 0f64; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Считаем сумму 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for edgenum in 1..path.len(){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let prev = path[edgenum - 1].clone(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let cver = path[edgenum].clone(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let edge = &edges.iter().filter(|e| e.from == prev && e.to == cver).last().expect(""); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            sum += edge.distance; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            println!("{}-{}={}\t(pheromone:\t{:.3}). \tCumulative length:\t{}", edge.from, edge.to, edge.distance, edge.pheromone, sum); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        println!("Total path length:\t.\t.\t.\t.\t.\t{}", best_length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        println!("No solution found."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |