diff --git a/flake.lock b/flake.lock index d62dc25..f516fb0 100644 --- a/flake.lock +++ b/flake.lock @@ -25,11 +25,11 @@ "locked": { "lastModified": 1, "narHash": "sha256-PVtFcvxh3Aqgel46BBFzxN0IvEVDzw/n/hWJ76mVThQ=", - "path": "/nix/store/0d80mkh7c7904wghfbvy3rpd395lriny-source/nix/deno-flake", + "path": "./nix/deno-flake", "type": "path" }, "original": { - "path": "/nix/store/0d80mkh7c7904wghfbvy3rpd395lriny-source/nix/deno-flake", + "path": "./nix/deno-flake", "type": "path" } }, diff --git a/flake.nix b/flake.nix index f41f72c..bc089c3 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,7 @@ inputs.nixpkgs.url = "nixpkgs"; inputs.flake-utils.url = "github:numtide/flake-utils"; inputs.deno-flake = { - url = "./nix/deno-flake"; + url = "path:./nix/deno-flake"; inputs.nixpkgs.follows = "nixpkgs"; }; inputs.fenix = { diff --git a/klout/Cargo.lock b/klout/Cargo.lock index 79939a2..bd86659 100644 --- a/klout/Cargo.lock +++ b/klout/Cargo.lock @@ -2,6 +2,18 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "eyre" version = "0.6.12" @@ -12,6 +24,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "indenter" version = "0.3.3" @@ -23,10 +46,118 @@ name = "klout" version = "0.0.0" dependencies = [ "eyre", + "rand", ] +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/klout/Cargo.toml b/klout/Cargo.toml index 0c1f6cb..ce200d5 100644 --- a/klout/Cargo.toml +++ b/klout/Cargo.toml @@ -4,4 +4,5 @@ version = "0.0.0" edition = "2024" [dependencies] -eyre = "0.6.12" \ No newline at end of file +eyre = "0.6.12" +rand = "0.8.5" \ No newline at end of file diff --git a/klout/src/main.rs b/klout/src/main.rs index 103a357..cc179b0 100644 --- a/klout/src/main.rs +++ b/klout/src/main.rs @@ -1,12 +1,19 @@ -use std::collections::HashMap; +use core::f64; +use eyre::Result; +use rand::rngs::ThreadRng; +use std::{ + collections::HashMap, + io::{self, Write}, + sync::mpsc::{Receiver, Sender}, +}; -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] enum Hand { Left, Right, } -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] enum Digit { Pinky, Ring, @@ -14,7 +21,7 @@ enum Digit { Index, } -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] struct Finger { hand: Hand, digit: Digit, @@ -113,6 +120,7 @@ const CHAR_FREQ_LOOKUP: [f64; char_data_max_index()] = { data }; +#[derive(Copy, Clone)] struct Layout { key_indices: [usize; char_data_max_index()], } @@ -129,6 +137,15 @@ impl Layout { Self { key_indices } } + + fn to_key_matrix(self) -> [char; MATRIX_COUNT] { + let mut out = ['0'; MATRIX_COUNT]; + for ch in CHARACTERS.chars() { + out[self.key_indices[ch as usize]] = ch; + } + + out + } } fn key_effort(ch: char, l: &Layout) -> f64 { @@ -210,24 +227,82 @@ fn all_bigrams() -> &'static [String] { unsafe { ALL_BIGRAMS.as_ref().unwrap_unchecked() } } -fn main() { - unsafe { - init_bigram_freqs(); - init_all_bigrams(); - }; +const N_WORKERS: usize = 16; - let eff: f64 = CHARACTERS - .chars() - .map(|v| { - let mut eff = key_effort(v, &INITIAL_LAYOUT); - eff += all_bigrams() - .iter() - .map(|b| bigram_effort(b, &INITIAL_LAYOUT)) - .sum::(); - - eff - }) - .sum(); - - println!("{eff}"); +fn mutate_layout(layout: &mut Layout, rng: &mut ThreadRng, num_swaps: usize) { + for _ in 0..num_swaps {} +} + +struct WorkerThreadInit { + initial_layout: Layout, + report: Sender<(f64, Layout)>, + + /// The maximum amount of deviation from the min_effort value allowed before + /// reverting back to the currently-known best layout + max_dev: f64, + + /// The number of swaps to make between iterations + swaps: usize, +} + +fn worker_thread_run(init: WorkerThreadInit) { + let mut rng = rand::thread_rng(); + + let mut layout = init.initial_layout; + let mut best_layout = layout; + let mut min_effort: f64 = f64::MAX; + loop { + let mut eff: f64 = + CHARACTERS.chars().map(|v| key_effort(v, &layout)).sum(); + + eff += all_bigrams() + .iter() + .map(|b| bigram_effort(b, &layout)) + .sum::(); + + if eff < min_effort { + min_effort = eff; + best_layout = layout; + init.report.send((eff, layout)).unwrap(); + } else if (eff - min_effort) > init.max_dev { + layout = best_layout; + } + + mutate_layout(&mut layout, &mut rng, init.swaps); + } +} + +fn main() -> Result<()> { + let (tx_agg, rx_agg) = std::sync::mpsc::channel(); + let (tx_ui, rx_ui) = std::sync::mpsc::channel(); + + let ui_thread = std::thread::spawn(|| { + ui_thread_run(INITIAL_LAYOUT, rx_ui); + }); + + let aggregator_thread = std::thread::spawn(|| { + aggregator_thread_run(INITIAL_LAYOUT, rx_agg, tx_ui); + }); + + let worker_threads = (0..N_WORKERS) + .map(|_| { + let tx = tx_agg.clone(); + std::thread::spawn(move || { + worker_thread_run(WorkerThreadInit { + initial_layout: INITIAL_LAYOUT, + report: tx, + max_dev: 1000., + swaps: 1, + }) + }) + }) + .collect::>(); + + ui_thread.join().unwrap(); + aggregator_thread.join().unwrap(); + for j in worker_threads { + j.join().unwrap(); + } + + Ok(()) }