-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from andyquinterom/int_symbols
Performance Improvements
- Loading branch information
Showing
16 changed files
with
760 additions
and
375 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
use std::rc::Rc; | ||
|
||
use crate::utils::{interner::InternerBuilder, node_map::NodeMap, sym::Sym}; | ||
use rayon::prelude::*; | ||
|
||
use super::{DirectedAcyclicGraph, DirectedGraph, GraphHasCycle}; | ||
|
||
#[derive(Clone)] | ||
pub struct DirectedGraphBuilder { | ||
pub(crate) parents: Vec<Sym>, | ||
pub(crate) children: Vec<Sym>, | ||
pub(crate) interner: InternerBuilder, | ||
} | ||
|
||
fn find_leaves(parents: &[Sym], children: &[Sym]) -> Vec<Sym> { | ||
let mut leaves: Vec<_> = children | ||
.par_iter() | ||
.filter(|child| parents.binary_search(child).is_err()) | ||
.copied() | ||
.collect(); | ||
leaves.sort_unstable(); | ||
leaves.dedup(); | ||
leaves | ||
} | ||
|
||
fn find_roots(parents: &[Sym], children: &[Sym]) -> Vec<Sym> { | ||
let mut roots: Vec<_> = parents | ||
.par_iter() | ||
.filter(|parent| children.binary_search(parent).is_err()) | ||
.copied() | ||
.collect(); | ||
roots.sort_unstable(); | ||
roots.dedup(); | ||
roots | ||
} | ||
|
||
impl DirectedGraphBuilder { | ||
pub fn new() -> Self { | ||
DirectedGraphBuilder { | ||
interner: InternerBuilder::new(), | ||
children: Vec::new(), | ||
parents: Vec::new(), | ||
} | ||
} | ||
|
||
#[inline(always)] | ||
pub(crate) fn get_or_intern(&mut self, val: impl AsRef<str>) -> Sym { | ||
self.interner.get_or_intern(val) | ||
} | ||
pub fn add_edge(&mut self, from: impl AsRef<str>, to: impl AsRef<str>) -> &mut Self { | ||
let from = self.get_or_intern(&from); | ||
let to = self.get_or_intern(&to); | ||
self.parents.push(from); | ||
self.children.push(to); | ||
self | ||
} | ||
pub fn add_path(&mut self, path: impl IntoIterator<Item = impl AsRef<str>>) -> &mut Self { | ||
let mut path = path.into_iter().peekable(); | ||
while let (Some(from), Some(to)) = (path.next(), path.peek()) { | ||
self.add_edge(from.as_ref(), to.as_ref()); | ||
} | ||
self | ||
} | ||
|
||
pub fn build_directed(self) -> DirectedGraph { | ||
// When we build we will do some optimizations | ||
let mut unique_parents = self.parents.clone(); | ||
unique_parents.sort_unstable(); | ||
unique_parents.dedup(); | ||
unique_parents.shrink_to_fit(); | ||
|
||
let mut unique_children = self.children.clone(); | ||
unique_children.sort_unstable(); | ||
unique_children.dedup(); | ||
unique_parents.shrink_to_fit(); | ||
|
||
let mut nodes = Vec::new(); | ||
nodes.extend_from_slice(&unique_parents); | ||
nodes.extend_from_slice(&unique_children); | ||
nodes.sort_unstable(); | ||
nodes.dedup(); | ||
nodes.shrink_to_fit(); | ||
|
||
let leaves = find_leaves(&unique_parents, &unique_children); | ||
let roots = find_roots(&unique_parents, &unique_children); | ||
|
||
let mut n_edges = 0; | ||
|
||
let interner = Rc::new(self.interner.build()); | ||
|
||
// Maps parents to their children | ||
let mut children_map = NodeMap::new(interner.len()); | ||
|
||
for i in 0..self.parents.len() { | ||
let was_added = children_map | ||
.get_mut(self.parents[i]) | ||
.or_init() | ||
.insert(self.children[i]); | ||
if was_added { | ||
n_edges += 1; | ||
} | ||
} | ||
|
||
// Maps children to their parents | ||
let mut parent_map = NodeMap::new(interner.len()); | ||
|
||
for i in 0..self.parents.len() { | ||
parent_map | ||
.get_mut(self.children[i]) | ||
.or_init() | ||
.insert(self.parents[i]); | ||
} | ||
|
||
DirectedGraph { | ||
interner, | ||
leaves, | ||
roots, | ||
nodes, | ||
children_map, | ||
parent_map, | ||
n_edges, | ||
buf: Default::default(), | ||
} | ||
} | ||
|
||
pub fn build_acyclic(self) -> Result<DirectedAcyclicGraph, GraphHasCycle> { | ||
DirectedAcyclicGraph::build(self.build_directed()) | ||
} | ||
} | ||
|
||
impl Default for DirectedGraphBuilder { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
use super::{DirectedGraph, LazySet}; | ||
|
||
const DEFAULT_MAX_PRINT_SIZE: usize = 15; | ||
|
||
fn get_max_str_length(graph: &DirectedGraph) -> usize { | ||
let mut n_printed = 0; | ||
let mut max_string_length = DEFAULT_MAX_PRINT_SIZE; | ||
'outer: for (parent, children) in graph.children_map.iter() { | ||
if let LazySet::Initialized(children) = children { | ||
for &child in children.iter() { | ||
n_printed += 1; | ||
max_string_length = max_string_length | ||
.max(graph.resolve(parent).len()) | ||
.max(graph.resolve(child).len()); | ||
if n_printed == 10 { | ||
break 'outer; | ||
} | ||
} | ||
} | ||
} | ||
max_string_length | ||
} | ||
|
||
impl std::fmt::Debug for DirectedGraph { | ||
#[inline] | ||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { | ||
let n_nodes = self.children_map.len(); | ||
let n_edges = self.n_edges; | ||
let n_roots = self.roots.len(); | ||
let n_leaves = self.leaves.len(); | ||
let max_string_length = get_max_str_length(self); | ||
writeln!(f, "# of nodes: {n_nodes}")?; | ||
writeln!(f, "# of edges: {n_edges}")?; | ||
writeln!(f, "# of roots: {n_roots}")?; | ||
writeln!(f, "# of leaves: {n_leaves}")?; | ||
writeln!(f)?; | ||
writeln!( | ||
f, | ||
"| {:^width$} | {:^width$} |", | ||
"Parent", | ||
"Child", | ||
width = max_string_length | ||
)?; | ||
writeln!( | ||
f, | ||
"| {:-<width$} | {:-<width$} |", | ||
"", | ||
"", | ||
width = max_string_length | ||
)?; | ||
let mut n_printed = 0; | ||
'outer: for (parent, children) in self.children_map.iter() { | ||
match children { | ||
LazySet::Initialized(children) => { | ||
for &child in children.iter() { | ||
n_printed += 1; | ||
let parent = self.resolve(parent); | ||
let child = self.resolve(child); | ||
writeln!( | ||
f, | ||
"| {:width$.width$} | {:width$.width$} |", | ||
parent, | ||
child, | ||
width = max_string_length | ||
)?; | ||
if n_printed == 10 { | ||
break 'outer; | ||
} | ||
} | ||
} | ||
LazySet::Uninitialized => continue, | ||
} | ||
} | ||
|
||
if n_nodes > 10 { | ||
writeln!(f, "Omitted {} nodes", n_nodes - 10)?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
//#[cfg(test)] | ||
//mod tests { | ||
// use crate::directed::DirectedGraphBuilder; | ||
// | ||
// #[test] | ||
// fn test_debug_printing() { | ||
// let mut builder = DirectedGraphBuilder::new(); | ||
// builder.add_path(["0", "111", "222", "333", "444", "4"]); | ||
// builder.add_path(["0", "999", "4"]); | ||
// builder.add_path(["0", "1", "2", "3", "4"]); | ||
// builder.add_path(["0", "4"]); | ||
// let graph = builder.build_acyclic().unwrap(); | ||
// | ||
// assert_eq!( | ||
// format!("{:?}", graph), | ||
// r#"# of nodes: 10 | ||
//# of edges: 12 | ||
//# of roots: 1 | ||
//# of leaves: 1 | ||
// | ||
//| Parent | Child | | ||
//| --------------- | --------------- | | ||
//| 0 | 1 | | ||
//| 0 | 111 | | ||
//| 0 | 999 | | ||
//| 0 | 4 | | ||
//| 111 | 222 | | ||
//| 222 | 333 | | ||
//| 333 | 444 | | ||
//| 444 | 4 | | ||
//| 999 | 4 | | ||
//| 1 | 2 | | ||
//Omitted 1 nodes | ||
//"#, | ||
// ); | ||
// } | ||
// | ||
// #[test] | ||
// fn test_debug_printing_longer_than_15() { | ||
// let mut builder = DirectedGraphBuilder::new(); | ||
// builder.add_edge("AAAAAAAAAAAAAAAAAAAAA", "B"); | ||
// builder.add_edge("C", "AAAAAAAAAAAAAAAAAAAAA"); | ||
// let graph = builder.build_acyclic().unwrap(); | ||
// | ||
// panic!("{:?}", graph); | ||
// | ||
// assert_eq!( | ||
// format!("{:?}", graph), | ||
// r#"# of nodes: 11 | ||
//# of edges: 12 | ||
//# of roots: 1 | ||
//# of leaves: 1 | ||
// | ||
//| Parent | Child | | ||
//| --------------- | --------------- | | ||
//| 0 | 1 | | ||
//| 0 | 111 | | ||
//| 0 | 999 | | ||
//| 0 | 4 | | ||
//| 111 | 222 | | ||
//| 222 | 333 | | ||
//| 333 | 444 | | ||
//| 444 | 4 | | ||
//| 999 | 4 | | ||
//| 1 | 2 | | ||
//Omitted 1 nodes | ||
//"#, | ||
// ); | ||
// } | ||
//} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.