From 8d3734fcc835148e7e89c4e507879b1103f6f2ba Mon Sep 17 00:00:00 2001 From: Johannes Nakayama Date: Sun, 8 Dec 2024 23:28:59 +0100 Subject: [PATCH] feat: start implementing probability models for global brain --- Cargo.lock | 26 ++++++++++++ Cargo.toml | 1 + migrations/20241122221757_init_db.sql | 61 +++++++++++++++++++++++++++ src/main.rs | 1 + src/probability/mod.rs | 1 + src/probability/probability_models.rs | 24 +++++++++++ 6 files changed, 114 insertions(+) create mode 100644 src/probability/mod.rs create mode 100644 src/probability/probability_models.rs diff --git a/Cargo.lock b/Cargo.lock index 3cdb793..1264d8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1191,6 +1191,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "probability" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42746b805e424b759d46c22c65dc66ccca057a2db96e9db4fda6c337a287e485" +dependencies = [ + "random", + "special", +] + [[package]] name = "proc-macro2" version = "1.0.92" @@ -1239,6 +1249,12 @@ dependencies = [ "getrandom", ] +[[package]] +name = "random" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "474c42c904f04dfe2a595a02f71e1a0e5e92ffb5761cc9a4c02140b93b8dd504" + [[package]] name = "ranking-service" version = "0.1.0" @@ -1248,6 +1264,7 @@ dependencies = [ "chrono", "dotenv", "itertools", + "probability", "serde", "serde_json", "sqlx", @@ -1453,6 +1470,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "special" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89cf0d71ae639fdd8097350bfac415a41aabf1d5ddd356295fdc95f09760382" +dependencies = [ + "libm", +] + [[package]] name = "spin" version = "0.9.8" diff --git a/Cargo.toml b/Cargo.toml index 6e788fb..c01aea0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,4 @@ itertools = "0.13.0" chrono = "0.4.38" tracing-subscriber = "0.3.19" tower-http = { version = "0.6.2", features = ["trace"] } +probability = "0.20.3" diff --git a/migrations/20241122221757_init_db.sql b/migrations/20241122221757_init_db.sql index 7ff2f98..4d09c80 100644 --- a/migrations/20241122221757_init_db.sql +++ b/migrations/20241122221757_init_db.sql @@ -5,6 +5,67 @@ create table if not exists item ( , created_at integer not null default (unixepoch('subsec') * 1000) ) strict; +create table lineage ( + ancestor_id integer not null references item(item_id) + , descendant_id integer not null references item(item_id) + , separation integer not null + , primary key(ancestor_id, descendant_id) +) strict; + +create trigger after_insert_item +after insert on item when new.parent_id is not null +begin + -- Insert a lineage record for parent + insert into lineage ( + ancestor_id + , descendant_id + , separation + ) + values( + new.parent_id + , new.item_id + , 1 + ) + on conflict do nothing; + + -- Insert a lineage record for all ancestors of this parent + insert into lineage + select + ancestor_id + , new.item_id as descendant_id + , 1 + separation as separation + from lineage ancestor + where ancestor.descendant_id = new.parent_id; + + -- It is possible that this item is inserted *after* some of its children + -- In that case, the ancestry for those children (and their children) will + -- be incomplete. + + -- Insert a lineage record for all children joined to all ancestors + insert into lineage + select + ancestor.ancestor_id + , child.item_id descendant_id + , ancestor.separation + 1 as separation + from item child + join lineage ancestor + on ancestor.descendant_id = new.item_id + where child.parent_id = new.item_id; + + -- Insert a lineage record for all descendants joined to all ancestors + insert into Lineage + select + ancestor.ancestor_id + , descendant.descendant_id + , ancestor.separation + descendant.separation + 1 as separation + from item child + join Lineage descendant + on descendant.ancestor_id = child.item_id + join Lineage ancestor + on ancestor.descendant_id = new.item_id + where child.parent_id = new.item_id; +end; + create table if not exists vote_event ( vote_event_id integer not null primary key autoincrement , item_id integer not null references item(item_id) diff --git a/src/main.rs b/src/main.rs index 92059c6..18d1454 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ mod database; mod http_server; mod scheduler; mod util; +mod probability; #[tokio::main] async fn main() -> Result<(), common::error::AppError> { diff --git a/src/probability/mod.rs b/src/probability/mod.rs new file mode 100644 index 0000000..177e950 --- /dev/null +++ b/src/probability/mod.rs @@ -0,0 +1 @@ +pub mod probability_models; diff --git a/src/probability/probability_models.rs b/src/probability/probability_models.rs new file mode 100644 index 0000000..5693ee7 --- /dev/null +++ b/src/probability/probability_models.rs @@ -0,0 +1,24 @@ +use probability::prelude::*; + +#[allow(dead_code)] +#[derive(Debug)] +struct Tally { + upvotes: i32, + total_votes: i32, +} + +#[allow(dead_code)] +trait Update { + type Output: Update; + fn update(&self, new_data: &T) -> Self::Output; +} + +impl Update for Beta { + type Output = Beta; + fn update(&self, new_data: &Tally) -> Beta { + let new_upvotes = new_data.upvotes as f64; + let new_downvotes = (new_data.total_votes - new_data.upvotes) as f64; + Beta::new(self.alpha() + new_upvotes, self.beta() + new_downvotes, self.a(), self.b()) + } +} +