Fix: Was broken in a number of creative ways, now tested to be functional

This commit is contained in:
Arlo Filley 2024-05-02 15:39:58 +01:00
parent 2dbe57d669
commit f5f6590a94

View File

@ -1,4 +1,4 @@
use std::collections::HashMap; use std::{collections::HashMap, hash::Hash};
fn main() { fn main() {
let mut pages: Graph<char> = Graph::new(); let mut pages: Graph<char> = Graph::new();
@ -8,69 +8,82 @@ fn main() {
pages.add_page('D'); pages.add_page('D');
pages.add_page('E'); pages.add_page('E');
println!("{pages:?}"); pages.add_link('A', 'E');
pages.link_page('B', 'A');
pages.link_page('C', 'B');
pages.link_page('D', 'C');
pages.link_page('B', 'D');
pages.link_page('E', 'D');
pages.link_page('A', 'E');
pages.link_page('B', 'E');
println!("{pages:?}");
println!("{:?} -> B", pages.get_links('B')); pages.add_link('B', 'A');
let p = pages.clone(); pages.add_link('B', 'D');
for page in p.items { pages.add_link('B', 'E');
println!("PageRank {page} => {}", pages.page_rank(page, 10))
pages.add_link('C', 'B');
pages.add_link('D', 'C');
pages.add_link('E', 'D');
// println!("{pages:?}");
pages.page_rank(40);
for (page, score) in pages.get_sorted_scores() {
println!("{page} => {score:.2}")
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Graph<T> { pub struct Graph<T> {
items: Vec<T>, nodes: HashMap<T, Node<T>>,
links: HashMap<usize, Vec<usize>>, damping: f64,
pub damping_factor: f64
} }
impl<T: Ord + Copy> Graph<T> { #[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 { pub fn new() -> Self {
Graph { items: vec![], links: HashMap::new(), damping_factor: 0.85 } 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, item: T) { pub fn add_page(&mut self, value: T) {
self.items.push(item); self.nodes.insert(value, Node::new());
self.items.sort();
let index = self.find_item(item);
self.links.insert(index, vec![]);
}
pub fn link_page(&mut self, item: T, link: T) {
let item = self.find_item(item);
let link = self.find_item(link);
self.add_link(item, link)
} }
fn add_link(&mut self, item_index: usize, link_index: usize) { pub fn add_link(&mut self, link: T, page: T) {
self.links.get_mut(&item_index).unwrap().push(link_index); self.nodes.get_mut(&link).unwrap().incoming_links.push(page.clone());
self.nodes.get_mut(&page).unwrap().outgoing_links.push(link);
} }
fn find_item(&self, item: T) -> usize { pub fn page_rank(&mut self, depth: usize) {
self.items.binary_search(&item).unwrap() 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_links(&self, item: T) -> Vec<T> { pub fn get_sorted_scores(&self) -> Vec<(T, f64)> {
let item = self.find_item(item); let mut scores = vec![];
self.links.get(&item).unwrap() for (key, node) in &self.nodes {
.to_vec().iter().map(|i| self.items[*i]).collect() scores.push((key.clone(), node.score))
} }
scores.sort_by(|a, b|
a.1.partial_cmp(&b.1).unwrap());
pub fn page_rank(&self, item: T, depth: i32) -> f64 { scores
if depth == 0 { return 0.0; }
let links = self.get_links(item);
let link_sums: f64 = links.clone().iter().map(
|i| self.page_rank(*i, depth - 1) / self.get_links(*i).len() as f64
).sum();
return (1.0 - self.damping_factor) + self.damping_factor * link_sums
} }
} }