use std::{num::ParseIntError, path::Path, fs::File, io::{BufReader, BufRead}, collections::{BTreeSet, BTreeMap}};
use crate::model::Lcs;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("io error {0}")]
Io(#[from] std::io::Error),
#[error("parse int {0}")]
ParseInt(#[from] ParseIntError),
#[error("ill formed instance")]
Format,
}
pub fn read_instance<P: AsRef<Path>>(fname: P) -> Result<Lcs, Error> {
let f = File::open(fname)?;
let f = BufReader::new(f);
let mut lines = f.lines();
let params = lines.next().ok_or(Error::Format)??.split_whitespace()
.map(|x| x.parse::<usize>().unwrap())
.collect::<Vec<_>>();
if params.len() != 2 {
return Err(Error::Format);
}
let n_strings = params[0];
let n_chars = params[1];
let mut strings = vec![];
let mut alphabet = BTreeSet::default();
for (i, line) in (&mut lines).enumerate() {
let line = line?;
let mut data = line.split_ascii_whitespace();
data.next().ok_or(Error::Format)?; strings.push(data.next().ok_or(Error::Format)?.to_string());
for char in strings[i].chars() {
alphabet.insert(char);
}
}
let mut mapping = BTreeMap::default();
let mut inverse_mapping = BTreeMap::default();
for (i, char) in alphabet.iter().enumerate() {
mapping.insert(i, *char);
inverse_mapping.insert(*char, i);
}
let mut strings = strings.drain(..)
.map(|s| s.chars().map(|c| *inverse_mapping.get(&c).unwrap()).collect::<Vec<usize>>())
.collect::<Vec<Vec<usize>>>();
strings.sort_unstable_by_key(|s| s.len());
let mut string_length = vec![];
let mut next = vec![];
let mut rem = vec![];
for i in 0..n_strings {
string_length.push(strings[i].len());
let mut next_for_string = vec![];
let mut rem_for_string = vec![];
for j in 0..n_chars {
let mut next_for_char = vec![0; strings[i].len() + 1];
let mut rem_for_char = vec![0; strings[i].len() + 1];
next_for_char[strings[i].len()] = strings[i].len();
rem_for_char[strings[i].len()] = 0;
for (k, char) in strings[i].iter().enumerate().rev() {
if *char == j {
next_for_char[k] = k;
rem_for_char[k] = rem_for_char[k + 1] + 1;
} else {
next_for_char[k] = next_for_char[k + 1];
rem_for_char[k] = rem_for_char[k + 1];
}
}
next_for_string.push(next_for_char);
rem_for_string.push(rem_for_char);
}
next.push(next_for_string);
rem.push(rem_for_string);
}
Ok(Lcs::new(
strings,
n_strings,
n_chars,
string_length,
next,
rem,
mapping,
))
}