use crate::{EdgeSet, HyperGraph};
use rand::prelude::*;
#[derive(Debug, Clone)]
pub enum WalkType {
Link,
UpDown,
DownUp,
}
pub fn random_walk<Walker: HyperGraph>(
hgraph: &Walker,
start: impl AsRef<[Walker::NodeID]>,
num_steps: usize,
walk_type: WalkType,
) -> Option<Vec<Walker::NodeID>> {
if num_steps == 0 {
return None;
}
let mut rng = thread_rng();
match walk_type {
WalkType::Link => {
let mut current_location: EdgeSet<Walker::NodeID> = start.into();
for _ in 0..num_steps {
let link_out = hgraph.link_of_nodes(current_location.node_vec());
if link_out.len() == 0 {
return None;
}
let link_ix = rng.gen_range(0..link_out.len());
let chosen_nodes = &link_out[link_ix].1;
current_location = EdgeSet::from(&chosen_nodes[..]);
}
Some(current_location.to_node_vec())
}
WalkType::UpDown => {
let mut current_location: Option<Walker::EdgeID> = None;
for _ in 0..num_steps {
let up_out = if current_location.is_none() {
hgraph.boundary_up_of_nodes(start.as_ref())
} else {
hgraph.boundary_up(¤t_location.unwrap())
};
if up_out.len() == 0 {
return None;
}
let up_out_ix = rng.gen_range(0..up_out.len());
let down_out = hgraph.boundary_down(&up_out[up_out_ix]);
if down_out.len() == 0 {
return None;
}
let down_out_ix = rng.gen_range(0..down_out.len());
current_location = Some(down_out[down_out_ix]);
}
hgraph.query_edge(¤t_location.unwrap())
}
WalkType::DownUp => {
let mut current_location: Option<Walker::EdgeID> = None;
for _ in 0..num_steps {
let down_out = if current_location.is_none() {
hgraph.boundary_down_of_nodes(start.as_ref())
} else {
hgraph.boundary_down(¤t_location.unwrap())
};
if down_out.len() == 0 {
return None;
}
let down_out_ix = rng.gen_range(0..down_out.len());
let up_out = hgraph.boundary_down(&down_out[down_out_ix]);
if up_out.len() == 0 {
return None;
}
let up_out_ix = rng.gen_range(0..up_out.len());
current_location = Some(up_out[up_out_ix]);
}
hgraph.query_edge(¤t_location.unwrap())
}
}
}