Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[graph] Add DepthFirstSearch to GraphSearch #323 #325

Merged
merged 6 commits into from
Oct 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions crates/graph_search/src/breadth_first_search.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use crate::search_index::SearchIndex;
use crate::search_iterator::SearchIterator;
use std::mem::swap;
use std::vec::IntoIter;

pub(crate) struct BreadthFirstSearch {
stack_iterator: IntoIter<SearchIndex>,
}

impl BreadthFirstSearch {
fn take_stack(stack: &mut Vec<SearchIndex>) -> Vec<SearchIndex> {
let mut res = Vec::<SearchIndex>::new();
swap(&mut res, stack);

res
}
}

impl SearchIterator for BreadthFirstSearch {
fn new(stack: &mut Vec<SearchIndex>) -> Self {
Self {
stack_iterator: Self::take_stack(stack).into_iter(),
}
}

fn next(&mut self) -> Option<SearchIndex> {
self.stack_iterator.next()
}
}
16 changes: 16 additions & 0 deletions crates/graph_search/src/depth_first_search.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use crate::search_index::SearchIndex;
use crate::search_iterator::SearchIterator;

pub(crate) struct DepthFirstSearch {
index: Option<SearchIndex>,
}

impl SearchIterator for DepthFirstSearch {
fn new(stack: &mut Vec<SearchIndex>) -> Self {
Self { index: stack.pop() }
}

fn next(&mut self) -> Option<SearchIndex> {
self.index.take()
}
}
128 changes: 14 additions & 114 deletions crates/graph_search/src/graph_search.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
use std::mem::swap;

use crate::graph_search_index::GraphSearchIndex;
use crate::search_control::SearchControl;
use crate::breadth_first_search::BreadthFirstSearch;
use crate::depth_first_search::DepthFirstSearch;
use crate::search_handler::SearchHandler;
use agdb_bit_set::BitSet;
use crate::search_impl::SearchImpl;
use agdb_graph::GraphData;
use agdb_graph::GraphEdgeIterator;
use agdb_graph::GraphImpl;
use agdb_graph::GraphIndex;

Expand All @@ -14,9 +11,6 @@ where
Data: GraphData,
{
pub(crate) graph: &'a GraphImpl<Data>,
pub(crate) stack: Vec<GraphSearchIndex>,
pub(crate) visited: BitSet,
pub(crate) result: Vec<GraphIndex>,
}

impl<'a, Data> GraphSearch<'a, Data>
Expand All @@ -28,121 +22,27 @@ where
index: &GraphIndex,
handler: &Handler,
) -> Vec<GraphIndex> {
self.clear();
self.add_index_to_stack(index.clone(), 0);
self.search(handler);

self.take_result()
}

fn add_edges_to_stack(&mut self, edges: GraphEdgeIterator<Data>, distance: u64) {
for edge in edges {
self.stack.push(GraphSearchIndex {
index: edge.index(),
distance,
});
}
}

fn add_index_to_stack(&mut self, index: GraphIndex, distance: u64) {
if self.validate_index(&index) {
self.stack.push(GraphSearchIndex { index, distance });
}
}

fn clear(&mut self) {
self.result.clear();
self.stack.clear();
self.visited.clear();
}

fn expand_index(&mut self, index: &GraphSearchIndex) {
if let Some(node) = self.graph.node(&index.index) {
self.add_edges_to_stack(node.edge_from_iter(), index.distance + 1);
} else if let Some(edge) = self.graph.edge(&index.index) {
self.add_index_to_stack(edge.to_index(), index.distance + 1);
}
}

fn process_index<Handler: SearchHandler>(
&mut self,
index: GraphSearchIndex,
handler: &Handler,
) -> bool {
if !self.visit_index(&index) {
self.process_unvisited_index(index, handler)
if self.validate_index(index) {
SearchImpl::<'a, Data, BreadthFirstSearch>::new(self.graph, index.clone())
.search(handler)
} else {
true
vec![]
}
}

fn process_unvisited_index<Handler: SearchHandler>(
pub fn depth_first_search<Handler: SearchHandler>(
&mut self,
index: GraphSearchIndex,
index: &GraphIndex,
handler: &Handler,
) -> bool {
let add_index;
let result;

match handler.process(&index.index, &index.distance) {
SearchControl::Continue(add) => {
self.expand_index(&index);
add_index = add;
result = true;
}
SearchControl::Finish(add) => {
add_index = add;
result = false;
}
SearchControl::Stop(add) => {
add_index = add;
result = true;
}
}

if add_index {
self.result.push(index.index);
}

result
}

fn process_stack<Handler: SearchHandler>(&mut self, handler: &Handler) -> bool {
for i in self.take_stack() {
if !self.process_index(i, handler) {
return false;
}
) -> Vec<GraphIndex> {
if self.validate_index(index) {
SearchImpl::<'a, Data, DepthFirstSearch>::new(self.graph, index.clone()).search(handler)
} else {
vec![]
}

true
}

fn search<T: SearchHandler>(&mut self, handler: &T) {
while !self.stack.is_empty() && self.process_stack(handler) {}
}

fn take_result(&mut self) -> Vec<GraphIndex> {
let mut res = Vec::<GraphIndex>::new();
swap(&mut res, &mut self.result);

res
}

fn take_stack(&mut self) -> Vec<GraphSearchIndex> {
let mut res = Vec::<GraphSearchIndex>::new();
swap(&mut res, &mut self.stack);

res
}

fn validate_index(&self, index: &GraphIndex) -> bool {
self.graph.node(index).is_some() || self.graph.edge(index).is_some()
}

fn visit_index(&mut self, index: &GraphSearchIndex) -> bool {
let visited = self.visited.value(index.index.as_u64());
self.visited.insert(index.index.as_u64());

visited
}
}
8 changes: 1 addition & 7 deletions crates/graph_search/src/graph_search_from.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::graph_search::GraphSearch;
use agdb_bit_set::BitSet;
use agdb_graph::GraphData;
use agdb_graph::GraphImpl;

Expand All @@ -8,11 +7,6 @@ where
Data: GraphData,
{
fn from(graph: &'a GraphImpl<Data>) -> Self {
GraphSearch {
graph,
visited: BitSet::new(),
stack: vec![],
result: vec![],
}
GraphSearch { graph }
}
}
6 changes: 5 additions & 1 deletion crates/graph_search/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
mod breadth_first_search;
mod depth_first_search;
mod graph_search;
mod graph_search_from;
mod graph_search_index;
mod search_control;
mod search_handler;
mod search_impl;
mod search_index;
mod search_iterator;

pub use graph_search::GraphSearch;
pub use search_control::SearchControl;
Expand Down
135 changes: 135 additions & 0 deletions crates/graph_search/src/search_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
use crate::search_index::SearchIndex;
use crate::search_iterator::SearchIterator;
use crate::SearchControl;
use crate::SearchHandler;
use agdb_bit_set::BitSet;
use agdb_graph::GraphData;
use agdb_graph::GraphEdgeIterator;
use agdb_graph::GraphImpl;
use agdb_graph::GraphIndex;
use std::marker::PhantomData;
use std::mem::swap;

pub(crate) struct SearchImpl<'a, Data, SearchIt>
where
Data: GraphData,
SearchIt: SearchIterator,
{
pub(crate) graph: &'a GraphImpl<Data>,
pub(crate) stack: Vec<SearchIndex>,
pub(crate) visited: BitSet,
pub(crate) result: Vec<GraphIndex>,
pub(crate) algorithm: PhantomData<SearchIt>,
}

impl<'a, Data, SearchIt> SearchImpl<'a, Data, SearchIt>
where
Data: GraphData,
SearchIt: SearchIterator,
{
pub(crate) fn new(graph: &'a GraphImpl<Data>, index: GraphIndex) -> Self {
Self {
graph,
stack: vec![SearchIndex { index, distance: 0 }],
visited: BitSet::new(),
result: vec![],
algorithm: PhantomData,
}
}

pub(crate) fn search<Handler: SearchHandler>(&mut self, handler: &Handler) -> Vec<GraphIndex> {
while !self.stack.is_empty() && self.process_stack(handler) {}

self.take_result()
}

fn add_edges_to_stack(&mut self, edges: GraphEdgeIterator<Data>, distance: u64) {
for edge in edges {
self.stack.push(SearchIndex {
index: edge.index(),
distance,
});
}
}

fn add_index_to_stack(&mut self, index: GraphIndex, distance: u64) {
self.stack.push(SearchIndex { index, distance });
}

fn expand_index(&mut self, index: &SearchIndex) {
if let Some(node) = self.graph.node(&index.index) {
self.add_edges_to_stack(node.edge_from_iter(), index.distance + 1);
} else if let Some(edge) = self.graph.edge(&index.index) {
self.add_index_to_stack(edge.to_index(), index.distance + 1);
}
}

fn process_index<Handler: SearchHandler>(
&mut self,
index: SearchIndex,
handler: &Handler,
) -> bool {
if !self.visit_index(&index) {
self.process_unvisited_index(index, handler)
} else {
true
}
}

fn process_stack<Handler: SearchHandler>(&mut self, handler: &Handler) -> bool {
let mut it = SearchIt::new(&mut self.stack);

while let Some(i) = it.next() {
if !self.process_index(i, handler) {
return false;
}
}

true
}

fn process_unvisited_index<Handler: SearchHandler>(
&mut self,
index: SearchIndex,
handler: &Handler,
) -> bool {
let add_index;
let result;

match handler.process(&index.index, &index.distance) {
SearchControl::Continue(add) => {
self.expand_index(&index);
add_index = add;
result = true;
}
SearchControl::Finish(add) => {
add_index = add;
result = false;
}
SearchControl::Stop(add) => {
add_index = add;
result = true;
}
}

if add_index {
self.result.push(index.index);
}

result
}

fn take_result(&mut self) -> Vec<GraphIndex> {
let mut res = Vec::<GraphIndex>::new();
swap(&mut res, &mut self.result);

res
}

fn visit_index(&mut self, index: &SearchIndex) -> bool {
let visited = self.visited.value(index.index.as_u64());
self.visited.insert(index.index.as_u64());

visited
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use agdb_graph::GraphIndex;

pub(crate) struct GraphSearchIndex {
pub(crate) struct SearchIndex {
pub(crate) index: GraphIndex,
pub(crate) distance: u64,
}
6 changes: 6 additions & 0 deletions crates/graph_search/src/search_iterator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use crate::search_index::SearchIndex;

pub(crate) trait SearchIterator {
fn new(stack: &mut Vec<SearchIndex>) -> Self;
fn next(&mut self) -> Option<SearchIndex>;
}
Loading