@@ 2,7 2,7 @@ pub mod tsp;
pub mod graph;
use tsp::{TSPInstance, TSPRandomInitializer, SwapPerturbation};
-use nalgebra::{Const, Dyn};
+use nalgebra::{Const, Dim, Dyn};
use eoa_lib::{
initializer::Initializer,
local_search::local_search_first_improving,
@@ 56,10 56,43 @@ fn load_tsp_instance(filename: &str) -> Result<TSPInstance<Dyn>, Box<dyn std::er
Ok(TSPInstance::new_dyn(cities))
}
+fn load_optimal_cost(instance_filename: &str) -> Result<f64, Box<dyn std::error::Error>> {
+ let instance_name = std::path::Path::new(instance_filename)
+ .file_stem()
+ .and_then(|s| s.to_str())
+ .ok_or("Could not extract instance name")?
+ .trim_end_matches(".tsp");
+
+ let solutions_path = std::path::Path::new(instance_filename)
+ .parent()
+ .unwrap_or_else(|| std::path::Path::new("."))
+ .join("solutions.txt");
+
+ let content = std::fs::read_to_string(solutions_path)?;
+
+ for line in content.lines() {
+ let line = line.trim();
+ if let Some(colon_pos) = line.find(':') {
+ let name = line[..colon_pos].trim();
+ if name == instance_name {
+ let cost_str = line[colon_pos + 1..].trim();
+ return cost_str.parse::<f64>()
+ .map_err(|e| format!("Could not parse cost '{}': {}", cost_str, e).into());
+ }
+ }
+ }
+
+ Err(format!("Optimal cost not found for instance '{}'", instance_name).into())
+}
+
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load a TSP instance from file
- let instance = load_tsp_instance("instances/berlin52.tsp.gz")?;
+ let filename = "instances/berlin52.tsp.gz";
+ let instance = load_tsp_instance(filename)?;
let dimension = instance.dimension();
+ let optimal_cost = load_optimal_cost(filename)?;
+
+ println!("Loaded {} with {} cities (optimal cost: {})", filename, dimension.value(), optimal_cost);
// Plot just the instance
instance.plot("tsp_instance.png")?;
@@ 95,6 128,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
instance.solution_cost(&initial_solution),
result.best_candidate.fit,
result.cycles);
+ println!("Gap to optimal: {:.2} ({:.1}%)",
+ result.best_candidate.fit - optimal_cost,
+ ((result.best_candidate.fit - optimal_cost) / optimal_cost) * 100.0);
Ok(())
}