use crate::core::exceptions::GraphinaException;
use crate::core::types::{BaseGraph, GraphConstructor};
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Error, ErrorKind, Result, Write};
pub fn read_edge_list<Ty>(path: &str, graph: &mut BaseGraph<i32, f32, Ty>, sep: char) -> Result<()>
where
Ty: GraphConstructor<i32, f32>,
{
let file = File::open(path)?;
let reader = BufReader::new(file);
let mut node_map = HashMap::new();
for line in reader.lines() {
let mut line = line?;
if let Some(idx) = line.find('#') {
line.truncate(idx);
}
if line.trim().is_empty() {
continue;
}
let tokens: Vec<&str> = line.trim().split(sep).map(|s| s.trim()).collect();
if tokens.len() < 2 {
continue;
}
let src_val: i32 = tokens[0].parse().map_err(|e| {
Error::new(
ErrorKind::InvalidData,
GraphinaException::new(&format!(
"Error parsing source value '{}': {}",
tokens[0], e
)),
)
})?;
let tgt_val: i32 = tokens[1].parse().map_err(|e| {
Error::new(
ErrorKind::InvalidData,
GraphinaException::new(&format!(
"Error parsing target value '{}': {}",
tokens[1], e
)),
)
})?;
let weight: f32 = if tokens.len() >= 3 {
tokens[2].parse().map_err(|e| {
Error::new(
ErrorKind::InvalidData,
GraphinaException::new(&format!("Error parsing weight '{}': {}", tokens[2], e)),
)
})?
} else {
1.0
};
let src_node = *node_map
.entry(src_val)
.or_insert_with(|| graph.add_node(src_val));
let tgt_node = *node_map
.entry(tgt_val)
.or_insert_with(|| graph.add_node(tgt_val));
graph.add_edge(src_node, tgt_node, weight);
}
Ok(())
}
pub fn write_edge_list<Ty>(path: &str, graph: &BaseGraph<i32, f32, Ty>, sep: char) -> Result<()>
where
Ty: GraphConstructor<i32, f32>,
{
let file = File::create(path)?;
let mut writer = BufWriter::new(file);
for (src, tgt, weight) in graph.edges() {
let src_attr = graph.node_attr(src).ok_or_else(|| {
Error::new(
ErrorKind::InvalidData,
GraphinaException::new(&format!(
"Missing node attribute for source node: {:?}",
src
)),
)
})?;
let tgt_attr = graph.node_attr(tgt).ok_or_else(|| {
Error::new(
ErrorKind::InvalidData,
GraphinaException::new(&format!(
"Missing node attribute for target node: {:?}",
tgt
)),
)
})?;
writeln!(writer, "{}{}{}{}{}", src_attr, sep, tgt_attr, sep, weight)?;
}
writer.flush()?;
Ok(())
}
pub fn read_adjacency_list<Ty>(
path: &str,
graph: &mut BaseGraph<i32, f32, Ty>,
sep: char,
) -> Result<()>
where
Ty: GraphConstructor<i32, f32>,
{
let file = File::open(path)?;
let reader = BufReader::new(file);
let mut node_map = HashMap::new();
for line in reader.lines() {
let mut line = line?;
if let Some(idx) = line.find('#') {
line.truncate(idx);
}
if line.trim().is_empty() {
continue;
}
let tokens: Vec<&str> = line.trim().split(sep).map(|s| s.trim()).collect();
if tokens.is_empty() {
continue;
}
let src_val: i32 = tokens[0].parse().map_err(|e| {
Error::new(
ErrorKind::InvalidData,
GraphinaException::new(&format!(
"Error parsing source value '{}': {}",
tokens[0], e
)),
)
})?;
let src_node = *node_map
.entry(src_val)
.or_insert_with(|| graph.add_node(src_val));
let mut i = 1;
while i < tokens.len() {
let neighbor_val: i32 = tokens[i].parse().map_err(|e| {
Error::new(
ErrorKind::InvalidData,
GraphinaException::new(&format!(
"Error parsing neighbor value '{}': {}",
tokens[i], e
)),
)
})?;
let weight: f32 = if i + 1 < tokens.len() {
tokens[i + 1].parse().map_err(|e| {
Error::new(
ErrorKind::InvalidData,
GraphinaException::new(&format!(
"Error parsing weight '{}': {}",
tokens[i + 1],
e
)),
)
})?
} else {
1.0
};
let neighbor_node = *node_map
.entry(neighbor_val)
.or_insert_with(|| graph.add_node(neighbor_val));
graph.add_edge(src_node, neighbor_node, weight);
i += 2;
}
}
Ok(())
}
pub fn write_adjacency_list<Ty>(
path: &str,
graph: &BaseGraph<i32, f32, Ty>,
sep: char,
) -> Result<()>
where
Ty: GraphConstructor<i32, f32>,
{
let file = File::create(path)?;
let mut writer = BufWriter::new(file);
let mut adj_map: HashMap<i32, Vec<(i32, f32)>> = HashMap::new();
for (src, tgt, weight) in graph.edges() {
let src_attr = graph.node_attr(src).ok_or_else(|| {
Error::new(
ErrorKind::InvalidData,
GraphinaException::new(&format!(
"Missing node attribute for source node: {:?}",
src
)),
)
})?;
let tgt_attr = graph.node_attr(tgt).ok_or_else(|| {
Error::new(
ErrorKind::InvalidData,
GraphinaException::new(&format!(
"Missing node attribute for target node: {:?}",
tgt
)),
)
})?;
adj_map
.entry(*src_attr)
.or_default()
.push((*tgt_attr, *weight));
}
for (_, attr) in graph.nodes() {
write!(writer, "{}", attr)?;
if let Some(neighbors) = adj_map.get(attr) {
for (nbr, weight) in neighbors {
write!(writer, "{}{}:{}", sep, nbr, weight)?;
}
}
writeln!(writer)?;
}
writer.flush()?;
Ok(())
}