[klout] before rewrite with runtime data

This commit is contained in:
soup 2024-12-22 00:08:14 -05:00
parent f303ddad1a
commit 8d838e3751
Signed by: soup
SSH key fingerprint: SHA256:GYxje8eQkJ6HZKzVWDdyOUF1TyDiprruGhE0Ym8qYDY
2 changed files with 94 additions and 16 deletions

4
klout/Cargo.lock generated
View file

@ -120,9 +120,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.90"
version = "2.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035"
dependencies = [
"proc-macro2",
"quote",

View file

@ -49,9 +49,9 @@ const RINDEX: Finger = F!(Right, Index);
#[rustfmt::skip]
const MATRIX_EFFORT: &[f64; MATRIX_COUNT] = &[
100., 3., 5., 3., 30., 30., 3., 5., 3., 100.,
50., 2., 1., 1., 15., 15., 1., 1., 2., 50.,
25., 7., 5., 7., 30., 1., 5., 7., 5., 100.,
100., 6., 10., 6., 40., 40., 10., 10., 10., 100.,
50., 2., 0.1, 0.1, 15., 15., 0.1, 0.1, 2., 50.,
10., 14., 10., 20., 40., 30., 6., 14., 6., 100.,
];
#[rustfmt::skip]
@ -86,7 +86,7 @@ const CHAR_FREQ_LOOKUP: [f64; char_data_max_index()] = {
macro_rules! d {
($ch:expr, $val:expr) => {{
data[$ch as usize] = $val * 100.;
data[$ch as usize] = $val * 1000.;
}};
}
@ -146,18 +146,62 @@ impl Layout {
out
}
fn key_to_xy(&self, ch: char) -> (u8, u8) {
let index = self.key_indices[ch as usize];
let y = index / 10;
let x = index % 10;
(x as u8, y as u8)
}
fn balance_penalty(&self) -> f64 {
let km = self.to_key_matrix();
let mut left_freq = 0.;
for x in 0..5 {
for y in 0..3 {
let i = y * 10 + x;
let ch = km[i];
left_freq += CHAR_FREQ_LOOKUP[ch as usize];
}
}
let mut right_freq = 0.;
for x in 5..10 {
for y in 0..3 {
let i = y * 10 + x;
let ch = km[i];
right_freq += CHAR_FREQ_LOOKUP[ch as usize];
}
}
(left_freq - right_freq).abs() * 10.
}
}
#[test]
fn test_key_to_xy() {
assert_eq!(INITIAL_LAYOUT.key_to_xy('g'), (4, 1));
}
fn key_effort(ch: char, l: &Layout) -> f64 {
CHAR_FREQ_LOOKUP[ch as usize] * MATRIX_EFFORT[l.key_indices[ch as usize]]
}
/*
#[rustfmt::skip]
const INITIAL_LAYOUT: Layout = Layout::from_key_matrix(&[
'q', 'w', 'f', 'p', 'b', 'j', 'l', 'u', 'y', '\'',
'a', 'r', 's', 't', 'g', 'm', 'n', 'e', 'i', 'o',
'x', 'c', 'd', 'v', 'z', 'k', 'h', ',', '.', '/',
]);
*/
#[rustfmt::skip]
const INITIAL_LAYOUT: Layout = Layout::from_key_matrix(&[
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p',
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', '\'',
'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
]);
type NGramFreqs = HashMap<&'static str, f64>;
@ -186,7 +230,7 @@ unsafe fn init_bigram_freqs() {
("ng", 0.01053385),
]
.into_iter()
.map(|(s, v)| (s, v * 100.))
.map(|(s, v)| (s, v * 4000.))
.collect::<NGramFreqs>();
unsafe { BIGRAM_FREQS = Some(freqs) };
@ -203,8 +247,39 @@ fn bigram_effort(bigram: &str, l: &Layout) -> f64 {
let finger1 = MATRIX_FINGERS[l.key_indices[ch1 as usize]];
let finger2 = MATRIX_FINGERS[l.key_indices[ch2 as usize]];
let ch1xy = l.key_to_xy(ch1 as char);
let ch2xy = l.key_to_xy(ch2 as char);
let x_diff = ch1xy.0.abs_diff(ch2xy.0);
let y_diff = ch1xy.1.abs_diff(ch2xy.1);
if finger1 == finger2 {
eff *= 10.;
if y_diff > 1 {
eff *= 1000.;
} else {
eff *= 500.;
}
}
if finger1.hand != finger2.hand {
eff /= 2.;
} else if x_diff == 1 {
let mult = if (finger1.hand == Hand::Left && ch1xy.0 < ch2xy.0)
|| (finger1.hand == Hand::Right && ch1xy.0 > ch2xy.0)
{
10.
} else {
1.
};
if y_diff == 0 {
eff /= 1000. * mult;
} else {
eff /= 250. * mult;
}
} else {
eff *= (x_diff + 1) as f64;
eff *= (y_diff + 1) as f64;
}
eff
@ -227,9 +302,10 @@ fn all_bigrams() -> &'static [String] {
unsafe { ALL_BIGRAMS.as_ref().unwrap_unchecked() }
}
const N_WORKERS: usize = 20;
const N_WORKERS: usize = 6;
fn mutate_layout(layout: &mut Layout, rng: &mut ThreadRng, num_swaps: usize) {
fn mutate_layout(layout: &mut Layout, rng: &mut ThreadRng, max_swaps: usize) {
let num_swaps = rng.gen_range(1..=max_swaps);
for _ in 0..num_swaps {
let ch1 = CHARACTERS
.chars()
@ -252,8 +328,8 @@ struct WorkerThreadInit {
/// reverting back to the currently-known best layout
max_dev: f64,
/// The number of swaps to make between iterations
swaps: usize,
/// The maximum number of swaps to make between iterations
max_swaps: usize,
}
fn worker_thread_run(init: WorkerThreadInit) {
@ -271,6 +347,8 @@ fn worker_thread_run(init: WorkerThreadInit) {
.map(|b| bigram_effort(b, &layout))
.sum::<f64>();
eff *= layout.balance_penalty();
if eff < min_effort {
min_effort = eff;
best_layout = layout;
@ -279,7 +357,7 @@ fn worker_thread_run(init: WorkerThreadInit) {
layout = best_layout;
}
mutate_layout(&mut layout, &mut rng, init.swaps);
mutate_layout(&mut layout, &mut rng, init.max_swaps);
}
}
@ -349,8 +427,8 @@ fn main() -> Result<()> {
worker_thread_run(WorkerThreadInit {
initial_layout: INITIAL_LAYOUT,
report: tx,
max_dev: 500.,
swaps: 5,
max_dev: 1000.,
max_swaps: 10,
})
})
})