use std::collections::HashSet;
use crate::primitives::{Edge, Node};
use crate::{Graph, GraphGrammar, Production};
#[must_use]
pub fn string_grammar() -> GraphGrammar<u32, &'static str, ()> {
let start_graph = Graph {
nodes: vec![Node::new(0, "a"), Node::new(1, "A")],
edges: vec![Edge::new_unlabeled(0, 1)],
};
let productions = vec![
(
"finalize".to_string(),
Production::new(
Graph {
nodes: vec![Node::new(0, "a"), Node::new(1, "A")],
edges: vec![Edge::new_unlabeled(0, 1)],
},
Graph {
nodes: vec![Node::new(0, "a")],
edges: vec![],
},
Graph {
nodes: vec![Node::new(0, "a"), Node::new(1, "a")],
edges: vec![Edge::new_unlabeled(0, 1)],
},
),
),
(
"extend".to_string(),
Production::new(
Graph {
nodes: vec![Node::new(0, "a"), Node::new(1, "A")],
edges: vec![Edge::new_unlabeled(0, 1)],
},
Graph {
nodes: vec![Node::new(0, "a")],
edges: vec![],
},
Graph {
nodes: vec![Node::new(0, "a"), Node::new(1, "a"), Node::new(2, "A")],
edges: vec![Edge::new_unlabeled(0, 1), Edge::new_unlabeled(1, 2)],
},
),
),
]
.into_iter()
.collect();
let terminal_nodes = ["a"].into_iter().collect::<HashSet<_>>();
GraphGrammar {
start_graph,
productions,
terminal_nodes,
}
}
#[must_use]
pub fn ladder_grammar(width: u32) -> GraphGrammar<u32, &'static str, ()> {
let interface = {
let mut nodes = Vec::with_capacity(width as usize + 1);
for i in 0..width {
nodes.push(Node::new(i, "a"));
}
let mut edges = Vec::with_capacity(width as usize + 1);
for i in 1..width {
edges.push(Edge::new_unlabeled(i - 1, i));
}
Graph { nodes, edges }
};
let mut start_graph = interface.clone();
start_graph.nodes.push(Node::new(width, "A"));
start_graph
.edges
.extend(start_graph.nodes.iter().filter_map(|n| {
if n.id == width {
None
} else {
Some(Edge::new_unlabeled(n.id, width))
}
}));
let mut finalization_rhs = interface.clone();
finalization_rhs.nodes.extend(
interface
.nodes
.iter()
.map(|n| Node::new(n.id + width, n.label)),
);
finalization_rhs
.edges
.extend((0..width).map(|id| Edge::new_unlabeled(id, id + width)));
finalization_rhs
.edges
.extend((1..width).map(|id| Edge::new_unlabeled(id + width - 1, id + width)));
let mut extension_rhs = finalization_rhs.clone();
extension_rhs.nodes.push(Node::new(2 * width, "A"));
extension_rhs
.edges
.extend((width..(2 * width)).map(|id| Edge::new_unlabeled(id, 2 * width)));
let productions = vec![
(
"finalize".to_string(),
Production::new(start_graph.clone(), interface.clone(), finalization_rhs),
),
(
"extend".to_string(),
Production::new(start_graph.clone(), interface.clone(), extension_rhs),
),
]
.into_iter()
.collect();
let terminal_nodes = ["a"].into_iter().collect::<HashSet<_>>();
GraphGrammar {
start_graph,
productions,
terminal_nodes,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_predefined_string_grammer() {
let gg = string_grammar();
let mut g = gg.start_graph.clone();
for _ in 0..5 {
gg.productions["extend"].apply_inplace(&mut g).unwrap();
}
gg.productions["finalize"].apply_inplace(&mut g).unwrap();
assert!(gg.is_valid(&g));
}
#[test]
fn test_predefined_string_grammer_equals_ladder_with_width_1() {
let string = string_grammar();
let ladder = ladder_grammar(1);
let mut gs = string.start_graph.clone();
let mut gl = ladder.start_graph.clone();
for _ in 0..5 {
string.productions["extend"].apply_inplace(&mut gs).unwrap();
ladder.productions["extend"].apply_inplace(&mut gl).unwrap();
}
string.productions["finalize"]
.apply_inplace(&mut gs)
.unwrap();
ladder.productions["finalize"]
.apply_inplace(&mut gl)
.unwrap();
assert!(string.is_valid(&gs));
assert!(ladder.is_valid(&gl));
assert_eq!(gs, gl);
}
#[test]
fn test_predefined_ladder_grammer() {
let ladder = ladder_grammar(2);
let mut g = ladder.start_graph.clone();
ladder.productions["extend"].apply_inplace(&mut g).unwrap();
ladder.productions["extend"].apply_inplace(&mut g).unwrap();
ladder.productions["finalize"]
.apply_inplace(&mut g)
.unwrap();
let reference = Graph {
nodes: vec![
Node::new(0u32, "a"),
Node::new(1, "a"),
Node::new(2, "a"),
Node::new(3, "a"),
Node::new(4, "a"),
Node::new(5, "a"),
Node::new(6, "a"),
Node::new(7, "a"),
],
edges: vec![
Edge::new_unlabeled(0, 1),
Edge::new_unlabeled(2, 3),
Edge::new_unlabeled(4, 5),
Edge::new_unlabeled(6, 7),
Edge::new_unlabeled(0, 2),
Edge::new_unlabeled(2, 4),
Edge::new_unlabeled(1, 3),
Edge::new_unlabeled(3, 5),
Edge::new_unlabeled(4, 6),
Edge::new_unlabeled(5, 7),
],
};
assert!(ladder.is_valid(&g));
assert!(crate::are_graphs_isomorph(&g, &reference));
}
}