#![deny(missing_docs)]
use std::hash::Hash;
use std::error::Error;
pub type Graph<T, U> = (Vec<T>, Vec<([usize; 2], U)>);
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct GenerateSettings {
pub max_nodes: usize,
pub max_edges: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum GenerateError {
MaxNodes,
MaxEdges,
}
impl std::fmt::Display for GenerateError {
fn fmt(&self, w: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
match *self {
GenerateError::MaxNodes => write!(w, "Reached limit maximum number of nodes"),
GenerateError::MaxEdges => write!(w, "Reached limit maximum number of edges"),
}
}
}
impl Error for GenerateError {}
impl From<GenerateError> for () {
fn from(_: GenerateError) -> () {()}
}
pub fn gen<T, U, F, G, H, E>(
(mut nodes, mut edges): Graph<T, U>,
n: usize,
f: F,
g: G,
h: H,
settings: &GenerateSettings,
) -> Result<Graph<T, U>, (Graph<T, U>, E)>
where T: Eq + Hash + Clone,
F: Fn(&T, usize) -> Result<(T, U), E>,
G: Fn(&T) -> bool,
H: Fn(&U, &U) -> Result<U, Option<E>>,
E: From<GenerateError>
{
use std::collections::{HashMap, HashSet};
let mut error: Option<E> = None;
let mut has: HashMap<T, usize> = HashMap::new();
let mut has_edge: HashSet<[usize; 2]> = HashSet::new();
for n in &nodes {
has.insert(n.clone(), 0);
}
for edge in &edges {
has_edge.insert(edge.0);
}
let mut i = 0;
'outer: while i < nodes.len() {
for j in 0..n {
match f(&nodes[i], j) {
Ok((new_node, new_edge)) => {
let id = if let Some(&id) = has.get(&new_node) {id}
else {
let id = nodes.len();
has.insert(new_node.clone(), id);
nodes.push(new_node);
id
};
has_edge.insert([i, id]);
edges.push(([i, id], new_edge));
if nodes.len() >= settings.max_nodes {
if error.is_none() {
error = Some(GenerateError::MaxNodes.into());
}
break 'outer;
} else if edges.len() >= settings.max_edges {
if error.is_none() {
error = Some(GenerateError::MaxEdges.into());
}
break 'outer;
}
}
Err(err) => {
error = Some(err);
}
}
}
i += 1;
}
let mut removed: HashSet<usize> = HashSet::new();
for i in 0..nodes.len() {if !g(&nodes[i]) {removed.insert(i);}}
let edges_count = edges.len();
let mut removed_edges: Vec<usize> = vec![];
let mut j = 0;
while j < edges.len() {
let [a, b] = edges[j].0;
if removed.contains(&b) {
removed_edges.push(j);
for k in 0..edges_count {
let [c, d] = edges[k].0;
if c == b && !has_edge.contains(&[a, d]) {
match h(&edges[j].1, &edges[k].1) {
Ok(new_edge) => {
edges.push(([a, d], new_edge));
has_edge.insert([a, d]);
}
Err(None) => {}
Err(Some(err)) => {
if error.is_none() {
error = Some(err);
}
}
}
}
}
}
j += 1;
}
let mut new_nodes = vec![];
let mut map_nodes: Vec<Option<usize>> = vec![];
for (i, node) in nodes.into_iter().enumerate() {
if removed.contains(&i) {
map_nodes.push(None);
} else {
let id = new_nodes.len();
map_nodes.push(Some(id));
new_nodes.push(node);
}
}
for j in (0..edges.len()).rev() {
let [a, b] = edges[j].0;
if let (Some(a), Some(b)) = (map_nodes[a], map_nodes[b]) {
edges[j].0 = [a, b];
} else {
edges.swap_remove(j);
}
}
if let Some(err) = error {
Err(((new_nodes, edges), err))
} else {
Ok((new_nodes, edges))
}
}
pub fn bidir<T: PartialEq + std::fmt::Debug>(edges: &mut Vec<([usize; 2], T)>) {
if edges.len() == 0 {return};
for j in 0..edges.len() {
let [a, b] = edges[j].0;
edges[j].0 = [a.min(b), a.max(b)];
}
edges.sort_by_key(|s| s.0);
let mut pair = false;
for j in (0..edges.len()).rev() {
let k = j + 1;
if pair {
if k >= edges.len() {
edges.swap_remove(j);
} else {
if edges[j] == edges[k] {
edges.swap_remove(k);
} else {
edges.swap_remove(j);
}
pair = false;
}
} else {
pair = true;
}
}
}