use std::{path::Path, num::ParseIntError, fs::File, io::{BufReader, BufRead}};
use crate::BitSet;
#[derive(Debug, Clone)]
pub struct SopInstance {
pub nb_jobs: usize,
pub distances: Vec<Vec<isize>>,
pub predecessors: Vec<BitSet>,
pub n_predecessors: Vec<usize>,
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("io error {0}")]
Io(#[from] std::io::Error),
#[error("parse int {0}")]
ParseInt(#[from] ParseIntError),
}
pub fn read_instance<P: AsRef<Path>>(fname: P) -> Result<SopInstance, Error> {
let f = File::open(fname)?;
let f = BufReader::new(f);
let lines = f.lines();
let mut lc = 0;
let mut nb_nodes = 0;
let mut distances = vec![];
let mut predecessors= vec![];
let mut edge_weight_section = false;
for line in lines {
let line = line.unwrap();
let line = line.trim();
if line.contains("EDGE_WEIGHT_SECTION") {
edge_weight_section = true;
continue;
} else if !edge_weight_section {
continue;
}
if lc == 0 {
nb_nodes = line.split_whitespace().next().unwrap().to_string().parse::<usize>().unwrap();
distances = vec![vec![0; nb_nodes]; nb_nodes];
(0..nb_nodes).for_each(|_| predecessors.push(BitSet::empty()));
}
else if (1..=nb_nodes).contains(&lc) {
let i = (lc - 1) as usize;
for (j, distance) in line.split_whitespace().enumerate() {
let distance = distance.to_string().parse::<isize>().unwrap();
distances[i][j] = distance;
if distance == -1 {
predecessors[i].add_inplace(j);
}
}
}
lc += 1;
}
let n_predecessors = predecessors.iter().map(|b| b.len()).collect();
Ok(SopInstance{nb_jobs: nb_nodes, distances, predecessors, n_predecessors})
}