///|
/// Original benchmark text from the Augerat Set A CVRPLIB family.
///
/// The fixture keeps the published node numbering, EUC_2D convention, vehicle
/// capacity, and five-vehicle limit. It is parsed at runtime by the same
/// parser that users can call for their own TSPLIB-compatible files.
pub let a_n32_k5_text : String =
  #|NAME : A-n32-k5
  #|COMMENT : (Augerat et al, Min no of trucks: 5, Optimal value: 784)
  #|TYPE : CVRP
  #|DIMENSION : 32
  #|EDGE_WEIGHT_TYPE : EUC_2D
  #|CAPACITY : 100
  #|TRUCKS : 5
  #|NODE_COORD_SECTION
  #|1 82 76
  #|2 96 44
  #|3 50 5
  #|4 49 8
  #|5 13 7
  #|6 29 89
  #|7 58 30
  #|8 84 39
  #|9 14 24
  #|10 2 39
  #|11 3 82
  #|12 5 10
  #|13 98 52
  #|14 84 25
  #|15 61 59
  #|16 1 65
  #|17 88 51
  #|18 91 2
  #|19 19 32
  #|20 93 3
  #|21 50 93
  #|22 98 14
  #|23 5 42
  #|24 42 9
  #|25 61 62
  #|26 9 97
  #|27 80 55
  #|28 57 69
  #|29 23 15
  #|30 20 70
  #|31 85 60
  #|32 98 5
  #|DEMAND_SECTION
  #|1 0
  #|2 19
  #|3 21
  #|4 6
  #|5 19
  #|6 7
  #|7 12
  #|8 16
  #|9 6
  #|10 16
  #|11 8
  #|12 14
  #|13 21
  #|14 16
  #|15 3
  #|16 22
  #|17 18
  #|18 19
  #|19 1
  #|20 24
  #|21 8
  #|22 12
  #|23 4
  #|24 8
  #|25 24
  #|26 24
  #|27 2
  #|28 20
  #|29 15
  #|30 2
  #|31 14
  #|32 9
  #|DEPOT_SECTION
  #|1
  #|-1
  #|EOF

///|
pub struct BenchmarkCase {
  name : String
  instance : @core.VrpInstance
  known_best : Double
  source : String
} derive(Debug)

///|
pub struct BenchmarkResult {
  case_name : String
  customer_count : Int
  known_best : Double
  seed_objective : Double
  best_objective : Double
  gap_percent : Double
  best_solution : @core.Solution
  stats : @core.SolveStats
} derive(Debug)

///|
pub fn BenchmarkCase::name(self : BenchmarkCase) -> String {
  self.name
}

///|
pub fn BenchmarkCase::instance(self : BenchmarkCase) -> @core.VrpInstance {
  self.instance
}

///|
pub fn BenchmarkCase::customer_count(self : BenchmarkCase) -> Int {
  self.instance.customer_count()
}

///|
pub fn BenchmarkCase::vehicle_capacity(self : BenchmarkCase) -> Double {
  self.instance.vehicle().capacity()
}

///|
pub fn BenchmarkCase::known_best(self : BenchmarkCase) -> Double {
  self.known_best
}

///|
pub fn BenchmarkCase::source(self : BenchmarkCase) -> String {
  self.source
}

///|
pub fn BenchmarkResult::case_name(self : BenchmarkResult) -> String {
  self.case_name
}

///|
pub fn BenchmarkResult::customer_count(self : BenchmarkResult) -> Int {
  self.customer_count
}

///|
pub fn BenchmarkResult::known_best(self : BenchmarkResult) -> Double {
  self.known_best
}

///|
pub fn BenchmarkResult::seed_objective(self : BenchmarkResult) -> Double {
  self.seed_objective
}

///|
pub fn BenchmarkResult::best_objective(self : BenchmarkResult) -> Double {
  self.best_objective
}

///|
pub fn BenchmarkResult::gap_percent(self : BenchmarkResult) -> Double {
  self.gap_percent
}

///|
pub fn BenchmarkResult::best_solution(self : BenchmarkResult) -> @core.Solution {
  self.best_solution.copy()
}

///|
pub fn BenchmarkResult::stats(self : BenchmarkResult) -> @core.SolveStats {
  self.stats
}

///|
pub fn a_n32_k5_case() -> BenchmarkCase raise @instance.ParseError {
  let instance = @instance.parse_cvrp(a_n32_k5_text)
  {
    name: "A-n32-k5",
    instance,
    known_best: 784.0,
    source: "CVRPLIB / Augerat Set A (1995)",
  }
}

///|
pub fn run_case(
  case : BenchmarkCase,
  config : @core.SolveConfig,
) -> BenchmarkResult {
  let seed = @constructive.clarke_wright_seed(case.instance, config~)
  let result = @search.solve_with_seed(case.instance, seed, config~)
  let gap_percent = (result.best_solution.objective - case.known_best) /
    case.known_best *
    100.0
  {
    case_name: case.name,
    customer_count: case.customer_count(),
    known_best: case.known_best,
    seed_objective: result.stats.seed_objective,
    best_objective: result.stats.best_objective,
    gap_percent,
    best_solution: result.best_solution,
    stats: result.stats,
  }
}

///|
pub fn result_text(result : BenchmarkResult) -> String {
  [
    "Benchmark: \{result.case_name}",
    "Customers: \{result.customer_count}",
    "Known best: \{result.known_best}",
    "Seed objective: \{result.seed_objective}",
    "Best objective: \{result.best_objective}",
    "Gap (%): \{result.gap_percent}",
    "Feasible: \{result.best_solution.feasible}",
    "Routes: \{result.best_solution.routes.length()}",
    "Iterations: \{result.stats.iterations}",
  ].join("\n")
}