use std::{collections::HashMap, hash::Hash};
#[derive(Debug, Clone)]
pub struct Graph<T> {
nodes: HashMap<T, Node<T>>,
damping: f64,
}
#[derive(Debug, Clone)]
pub struct Node<T> {
incoming_links: Vec<T>,
outgoing_links: Vec<T>,
score: f64,
}
impl<T> Node<T> {
pub fn new() -> Self {
Node { incoming_links: vec![], outgoing_links: vec![], score: 1.0 }
}
}
impl<T: Hash + Eq + PartialEq + Clone> Graph<T> {
pub fn new() -> Self {
Graph { nodes: HashMap::new(), damping: 0.85 }
}
pub fn add_page(&mut self, value: T) {
self.nodes.insert(value, Node::new());
}
pub fn add_link(&mut self, link: T, page: T) {
self.nodes.get_mut(&link).unwrap().incoming_links.push(page.clone());
self.nodes.get_mut(&page).unwrap().outgoing_links.push(link);
}
pub fn page_rank(&mut self, depth: usize) {
if depth == 0 { return }
let nodes = self.nodes.clone();
for (_, node) in self.nodes.iter_mut() {
let mut link_scores = 0.0;
for link in node.incoming_links.iter() {
let n = nodes.get(link).unwrap();
link_scores += n.score / n.outgoing_links.len() as f64
}
node.score = (1.0 - self.damping) + (self.damping * link_scores)
}
self.page_rank(depth - 1)
}
pub fn get_sorted_scores(&self) -> Vec<(T, f64)> {
let mut scores = vec![];
for (key, node) in &self.nodes {
scores.push((key.clone(), node.score))
}
scores.sort_by(|a, b|
a.1.partial_cmp(&b.1).unwrap());
scores
}
}