use anyhow::anyhow;
use std::fs::OpenOptions;
use std::io::BufReader;
use csv::ReaderBuilder;
use indexmap::IndexMap;
use std::collections::HashMap;
use petgraph::graph::{Graph, NodeIndex};
use petgraph::stable_graph::DefaultIx;
use crate::embed::gkernel::{idmap::*, pgraph::*};
pub struct PpiNode {
num: u32,
labels: Nweight<u8>,
}
impl PpiNode {
pub fn new(num: u32, labels: Nweight<u8>) -> Self {
PpiNode { num, labels }
}
#[allow(unused)]
pub fn get_num(&self) -> u32 {
self.num
}
}
impl HasNweight<u8> for PpiNode {
fn get_nweight(&self) -> &Nweight<u8> {
&self.labels
} }
#[derive(Default)]
pub struct PpiEdge {
labels: Eweight<u8>,
}
impl HasEweight<u8> for PpiEdge {
fn get_eweight(&self) -> &Eweight<u8> {
&self.labels
}
}
pub fn load_labels(dir: &String) -> anyhow::Result<(HashMap<u32, Vec<u8>>, IndexMap<u8, u8>)> {
let delim = b' ';
let nb_fields = 2;
let filepath = std::path::Path::new(&dir).join("ppi-labels.csv");
log::info!("\n reading label file : {:?}", filepath);
let fileres = OpenOptions::new().read(true).open(&filepath);
if fileres.is_err() {
log::error!(
"read_ppi_data : reload could not open file {:?}",
filepath.as_os_str()
);
println!(
"directed_from_csv could not open file {:?}",
filepath.as_os_str()
);
return Err(anyhow!(
"directed_from_csv could not open file {}",
filepath.display()
));
}
let file = fileres?;
let bufreader = BufReader::new(file);
let mut node: u32;
let mut label: u8;
let mut max_label = 0u8;
let mut rdr = ReaderBuilder::new()
.delimiter(delim)
.flexible(false)
.has_headers(false)
.from_reader(bufreader);
let mut nodelabels = HashMap::<u32, Vec<u8>>::with_capacity(5000);
for (nb_record, result) in rdr.records().enumerate() {
let record = result?;
if record.len() != nb_fields {
log::error!(
"record num : {}, record : {:?}, record length : {}",
nb_record,
&record,
record.len()
);
println!(
"non constant number of fields at record {} first record has {}",
nb_record + 1,
nb_fields
);
return Err(anyhow!(
"non constant number of fields at record {} first record has {}",
nb_record + 1,
nb_fields
));
}
let field = record.get(0).unwrap();
if let Ok(idx) = field.parse::<u32>() {
node = idx;
assert!(node <= 5000);
} else {
log::info!("error decoding field 1 of record {}", nb_record + 1);
return Err(anyhow!(
"error decoding field 1 of record {}",
nb_record + 1
));
}
let field = record.get(1).unwrap();
if let Ok(lbl) = field.parse::<u8>() {
label = lbl;
max_label = max_label.max(label);
} else {
return Err(anyhow!(
"error decoding field 2 of record {}",
nb_record + 1
));
}
match nodelabels.get_mut(&node) {
None => {
let labels = vec![label];
nodelabels.insert(node, labels);
}
Some(labels) => {
labels.push(label);
}
}
} log::info!("end reading labels");
assert!(max_label < u8::MAX);
let mut relabel = IndexMap::<u8, u8>::new();
let val_for_0 = max_label + 1;
for v in nodelabels.values_mut() {
for l in v {
if *l == 0 {
if relabel.get(l).is_none() {
relabel.insert(*l, val_for_0);
}
*l = val_for_0;
} else {
if relabel.get(l).is_none() {
relabel.insert(*l, *l);
}
}
}
}
log::info!("end relabelling labels");
Ok((nodelabels, relabel))
}
#[allow(unused)]
pub fn read_ppi_directed_data(
dir: String,
) -> anyhow::Result<(
Graph<PpiNode, PpiEdge, petgraph::Directed, DefaultIx>,
IdMap<u8, u8>,
)> {
let delim = b' ';
let relabels = load_labels(&dir);
if relabels.is_err() {
log::error!("read_ppi_directed_data could, call to ppisapiens::load_labels failed");
}
let (nodelabels, relabel) = relabels.unwrap();
let filepath = std::path::Path::new(&dir).join("ppi-network.csv");
log::info!("reading network file : {:?}", filepath);
let fileres = OpenOptions::new().read(true).open(&filepath);
if fileres.is_err() {
log::error!(
"read_ppi_data : reload could not open file {:?}",
filepath.as_os_str()
);
println!(
"directed_from_csv could not open file {:?}",
filepath.as_os_str()
);
return Err(anyhow!(
"directed_from_csv could not open file {}",
filepath.display()
));
}
let file = fileres?;
let bufreader = BufReader::new(file);
let nb_fields = 3;
let mut nb_self_loops = 0;
let mut nb_double_dir = 0; let mut node1: u32;
let mut node2: u32;
let mut gnode1: Option<NodeIndex>;
let mut gnode2: Option<NodeIndex>;
let mut graph = Graph::<PpiNode, PpiEdge, petgraph::Directed>::new();
let mut nodeset = IndexMap::<u32, NodeIndex>::new();
let mut rdr = ReaderBuilder::new()
.delimiter(delim)
.flexible(false)
.has_headers(true)
.from_reader(bufreader);
log::info!("reading records");
for (nb_record, result) in rdr.records().enumerate() {
log::trace!("edge record : {}", nb_record);
let record = result?;
if record.len() != nb_fields {
log::error!(
"record num : {}, record : {:?}, record length : {}",
nb_record,
&record,
record.len()
);
println!(
"non constant number of fields at record {} first record has {}",
nb_record + 1,
nb_fields
);
return Err(anyhow!(
"non constant number of fields at record {} first record has {}",
nb_record + 1,
nb_fields
));
}
let field = record.get(0).unwrap();
if let Ok(idx) = field.parse::<u32>() {
node1 = idx;
assert!(node1 <= 5000);
if !nodeset.contains_key(&node1) {
let labels = nodelabels.get(&node1).unwrap();
let labels = Nweight::<u8>::new(labels.clone());
gnode1 = Some(graph.add_node(PpiNode::new(node1, labels)));
nodeset.insert(node1, gnode1.unwrap());
} else {
gnode1 = Some(*nodeset.get(&node1).unwrap());
}
} else {
log::error!("error decoding node 2 of record {}", nb_record + 1);
return Err(anyhow!(
"error decoding field 1 of record {}",
nb_record + 1
));
}
let field = record.get(1).unwrap();
if let Ok(idx) = field.parse::<u32>() {
node2 = idx;
if !nodeset.contains_key(&node2) {
let labels = nodelabels.get(&node2).unwrap();
let labels = Nweight::<u8>::new(labels.clone());
gnode2 = Some(graph.add_node(PpiNode::new(node2, labels)));
nodeset.insert(node2, gnode2.unwrap());
} else {
gnode2 = Some(*nodeset.get(&node2).unwrap());
}
} else {
log::error!("error decoding node 2 of record {}", nb_record + 1);
return Err(anyhow!(
"error decoding node 2 of record {}",
nb_record + 1
));
}
if graph.contains_edge(gnode2.unwrap(), gnode1.unwrap()) {
nb_double_dir += 1;
}
graph.update_edge(gnode1.unwrap(), gnode2.unwrap(), PpiEdge::default());
if gnode1.unwrap() == gnode2.unwrap() {
nb_self_loops += 1;
}
} log::info!("nb nodes = {}", graph.raw_nodes().len());
log::info!("nb edges = {}", graph.raw_edges().len());
let idmap = IdMap::<u8, u8>::new(nodeset, relabel);
Ok((graph, idmap))
}
#[allow(unused)]
pub fn read_ppi_undirected_data(
dir: String,
) -> anyhow::Result<(
Graph<PpiNode, PpiEdge, petgraph::Undirected, DefaultIx>,
IdMap<u8, u8>,
)> {
let delim = b' ';
let relabels = load_labels(&dir);
if relabels.is_err() {
log::error!("read_ppi_undirected_data could, call to ppisapiens::load_labels failed");
}
let (nodelabels, relabel) = relabels.unwrap();
let filepath = std::path::Path::new(&dir).join("ppi-network.csv");
log::info!("reading network file : {:?}", filepath);
let fileres = OpenOptions::new().read(true).open(&filepath);
if fileres.is_err() {
log::error!(
"read_ppi_data : reload could not open file {:?}",
filepath.as_os_str()
);
println!(
"directed_from_csv could not open file {:?}",
filepath.as_os_str()
);
return Err(anyhow!(
"directed_from_csv could not open file {}",
filepath.display()
));
}
let file = fileres?;
let bufreader = BufReader::new(file);
let nb_fields = 3;
let mut node1: u32;
let mut node2: u32;
let mut nb_self_loops = 0;
let mut nb_double_dir = 0; let mut gnode1: Option<NodeIndex>;
let mut gnode2: Option<NodeIndex>;
let mut graph = Graph::<PpiNode, PpiEdge, petgraph::Undirected>::new_undirected();
let mut nodeset = IndexMap::<u32, NodeIndex>::new();
let mut rdr = ReaderBuilder::new()
.delimiter(delim)
.flexible(false)
.has_headers(true)
.from_reader(bufreader);
log::info!("reading records");
for (nb_record, result) in rdr.records().enumerate() {
log::trace!("edge record : {}", nb_record);
let record = result?;
if record.len() != nb_fields {
log::error!(
"record num : {}, record : {:?}, record length : {}",
nb_record,
&record,
record.len()
);
println!(
"non constant number of fields at record {} first record has {}",
nb_record + 1,
nb_fields
);
return Err(anyhow!(
"non constant number of fields at record {} first record has {}",
nb_record + 1,
nb_fields
));
}
let field = record.get(0).unwrap();
if let Ok(idx) = field.parse::<u32>() {
node1 = idx;
assert!(node1 <= 5000);
if !nodeset.contains_key(&node1) {
let labels = nodelabels.get(&node1).unwrap();
let labels = Nweight::<u8>::new(labels.clone());
gnode1 = Some(graph.add_node(PpiNode::new(node1, labels)));
nodeset.insert(node1, gnode1.unwrap());
} else {
gnode1 = Some(*nodeset.get(&node1).unwrap());
}
} else {
log::error!("error decoding node 2 of record {}", nb_record + 1);
return Err(anyhow!(
"error decoding field 1 of record {}",
nb_record + 1
));
}
let field = record.get(1).unwrap();
if let Ok(idx) = field.parse::<u32>() {
node2 = idx;
if !nodeset.contains_key(&node2) {
let labels = nodelabels.get(&node2).unwrap();
let labels = Nweight::<u8>::new(labels.clone());
gnode2 = Some(graph.add_node(PpiNode::new(node2, labels)));
nodeset.insert(node2, gnode2.unwrap());
} else {
gnode2 = Some(*nodeset.get(&node2).unwrap());
}
} else {
log::error!("error decoding node 2 of record {}", nb_record + 1);
return Err(anyhow!(
"error decoding node 2 of record {}",
nb_record + 1
));
}
if graph.contains_edge(gnode2.unwrap(), gnode1.unwrap()) {
nb_double_dir += 1;
} else {
graph.update_edge(gnode1.unwrap(), gnode2.unwrap(), PpiEdge::default());
}
if gnode1.unwrap() == gnode2.unwrap() {
nb_self_loops += 1;
}
} log::info!(
"nb self loops : {}, nb bidirectional edges {}",
nb_self_loops,
nb_double_dir
);
log::info!("nb nodes = {}", graph.raw_nodes().len());
log::info!("nb edges = {}", graph.raw_edges().len());
let idmap = IdMap::<u8, u8>::new(nodeset, relabel);
Ok((graph, idmap))
}
#[cfg(test)]
mod tests {
const PPI_DIR: &str = "/home/jpboth/Data/Graphs/PPI";
use super::*;
fn log_init_test() {
let _ = env_logger::builder().is_test(true).try_init();
}
#[test]
fn test_load_ppi_directed() {
log_init_test();
let res_graph = read_ppi_directed_data(String::from(PPI_DIR));
assert!(res_graph.is_ok());
let (graph, _nodeset) = res_graph.unwrap();
log::info!(
"ppi nodes : {}, ppi edge : {}",
graph.raw_nodes().len(),
graph.raw_edges().len()
);
}
#[test]
fn test_load_ppi_undirected() {
log_init_test();
let res_graph = read_ppi_undirected_data(String::from(PPI_DIR));
assert!(res_graph.is_ok());
let (graph, _nodeset) = res_graph.unwrap();
log::info!(
"ppi nodes : {}, ppi edge : {}",
graph.raw_nodes().len(),
graph.raw_edges().len()
);
} }