From 1fa7552c3018d541b617b5ceebc6abeaba013eaa Mon Sep 17 00:00:00 2001 From: tslil clingman Date: Thu, 20 Oct 2022 23:17:19 +0200 Subject: penalise pinky columns with too high usage even though we don't technically know which columns they are, we do know they will be the two lowest ultimately when the prelayout becomes a layout --- srchr/src/config.rs | 16 ++++++++++++++-- srchr/src/corpus.rs | 17 +++++++++-------- srchr/src/evaluation.rs | 49 +++++++++++++++++++++++++++++++------------------ srchr/src/layout.rs | 33 ++++++++++++++++++--------------- 4 files changed, 72 insertions(+), 43 deletions(-) diff --git a/srchr/src/config.rs b/srchr/src/config.rs index 5bb35c5..c9ca302 100644 --- a/srchr/src/config.rs +++ b/srchr/src/config.rs @@ -33,10 +33,10 @@ pub const MAX_NUM_TRANSPOSITIONS: usize = 12; // Fitness parameters pub const DESIRED_INDEX_USAGE_PERCENT: f32 = 0.12; +pub const MAX_PINKY_USAGE_PERCENT: f32 = 0.09; pub const STANDARD_DSFB_WEIGHT: f32 = 1.0 / 8.0; pub const INDEX_DSFB_WEIGHT: f32 = 1.0 / 8.0; -pub fn index_usage_fitness(total_count: u32, index_count: u32) -> f32 { - let index_perc = index_count as f32 / total_count as f32; +pub fn index_usage_fitness(index_perc: f32) -> f32 { if index_perc < DESIRED_INDEX_USAGE_PERCENT { DESIRED_INDEX_USAGE_PERCENT - index_perc } else { @@ -44,6 +44,18 @@ pub fn index_usage_fitness(total_count: u32, index_count: u32) -> f32 { } } +pub fn pinky_col_penalty(lesser_perc: f32, greater_perc: f32) -> f32 { + if greater_perc > MAX_PINKY_USAGE_PERCENT { + if lesser_perc > MAX_PINKY_USAGE_PERCENT { + lesser_perc + greater_perc - MAX_PINKY_USAGE_PERCENT * 2.0 + } else { + greater_perc - MAX_PINKY_USAGE_PERCENT + } + } else { + 0.0 + } +} + // ----------------------------------------------------------------------------- // Do not change the following, the code makes assumptions about these // ----------------------------------------------------------------------------- diff --git a/srchr/src/corpus.rs b/srchr/src/corpus.rs index 7216b1a..306018c 100644 --- a/srchr/src/corpus.rs +++ b/srchr/src/corpus.rs @@ -19,7 +19,7 @@ const NUM_BIGRAMS: usize = NUM_KEYS * NUM_KEYS; pub struct Corpus { bigram_percs: [f32; NUM_BIGRAMS], skipgram_percs: [f32; NUM_BIGRAMS], - character_count: [u32; 128], + character_percs: [f32; 128], total_count: u32, total_bigrams: u32, } @@ -31,8 +31,8 @@ fn pair_to_index(x: u8, y: u8) -> usize { } impl Corpus { - pub fn get_character_count(&self, c: u8) -> u32 { - self.character_count[c as usize] + pub fn get_character_perc(&self, c: u8) -> f32 { + self.character_percs[c as usize] } pub fn get_bigram_perc(&self, x: u8, y: u8) -> f32 { @@ -43,10 +43,6 @@ impl Corpus { self.skipgram_percs[pair_to_index(x, y)] } - pub fn get_total_count(&self) -> u32 { - self.total_count - } - pub fn get_total_bigrams(&self) -> u32 { self.total_bigrams } @@ -89,16 +85,21 @@ impl Corpus { let mut bigram_percs = [0.0; NUM_BIGRAMS]; let mut skipgram_percs = [0.0; NUM_BIGRAMS]; + let mut character_percs = [0.0; 128]; for i in 0..NUM_BIGRAMS { bigram_percs[i] = bigram_count[i] as f32 / total_bigrams as f32; skipgram_percs[i] = skipgram_count[i] as f32 / total_trigrams as f32; } + for i in 0..128 { + character_percs[i] = character_count[i] as f32 / total_count as f32; + } + return Ok(Corpus { skipgram_percs, bigram_percs, - character_count, + character_percs, total_count, total_bigrams, }); diff --git a/srchr/src/evaluation.rs b/srchr/src/evaluation.rs index 1c40b44..b412d88 100644 --- a/srchr/src/evaluation.rs +++ b/srchr/src/evaluation.rs @@ -7,6 +7,8 @@ use std::fmt; pub fn prelayout_fitness(corpus: &Corpus, layout: &Prelayout) -> f32 { let mut score: f32 = 0.0; + let mut min1: f32 = std::f32::INFINITY; + let mut min2: f32 = std::f32::INFINITY; for i in 0..6 { let keys = layout.get_standard_column(i); @@ -18,12 +20,27 @@ pub fn prelayout_fitness(corpus: &Corpus, layout: &Prelayout) -> f32 { + corpus.get_bigram_perc(k1, k3) + corpus.get_bigram_perc(k2, k3); + let col_usage = corpus.get_character_perc(k1) + + corpus.get_character_perc(k2) + + corpus.get_character_perc(k3); + + if col_usage < min2 { + if col_usage < min1 { + min2 = min1; + min1 = col_usage; + } else { + min2 = col_usage; + } + } + score += (corpus.get_skipgram_perc(k1, k2) + corpus.get_skipgram_perc(k1, k3) + corpus.get_skipgram_perc(k2, k3)) * STANDARD_DSFB_WEIGHT; } + score += pinky_col_penalty(min1, min2); + for i in 0..2 { let keys = layout.get_index_column(i); let k1 = keys[0]; @@ -33,8 +50,8 @@ pub fn prelayout_fitness(corpus: &Corpus, layout: &Prelayout) -> f32 { let k5 = keys[4]; let k6 = keys[5]; - let index_percs = keys.iter().map(|&k| corpus.get_character_count(k)).sum(); - score += index_usage_fitness(corpus.get_total_count(), index_percs); + let index_percs = keys.iter().map(|&k| corpus.get_character_perc(k)).sum(); + score += index_usage_fitness(index_percs); score += corpus.get_bigram_perc(k1, k2) + corpus.get_bigram_perc(k1, k3) @@ -74,8 +91,7 @@ pub fn prelayout_fitness(corpus: &Corpus, layout: &Prelayout) -> f32 { } pub struct Evaluation { - keypress: [u32; NUM_KEYS], - total_keypress: u32, + keypress_perc: [f32; NUM_KEYS], total_bigrams: u32, sfb: [f32; 8], dsfb: [f32; 8], @@ -83,12 +99,12 @@ pub struct Evaluation { impl Evaluation { pub fn evaluate_layout(corpus: &Corpus, layout: &Layout) -> Evaluation { - let mut keypress: [u32; NUM_KEYS] = [0; NUM_KEYS]; + let mut keypress_perc: [f32; NUM_KEYS] = [0.0; NUM_KEYS]; let mut sfb: [f32; 8] = [0.0; 8]; let mut dsfb: [f32; 8] = [0.0; 8]; for (i, &c) in layout.get_keys().iter().enumerate() { - keypress[i] = corpus.get_character_count(c as u8); + keypress_perc[i] = corpus.get_character_perc(c as u8); } for i in 0..8 { @@ -166,8 +182,7 @@ impl Evaluation { } return Evaluation { - keypress, - total_keypress: corpus.get_total_count(), + keypress_perc, total_bigrams: corpus.get_total_bigrams(), sfb, dsfb, @@ -176,28 +191,26 @@ impl Evaluation { fn output_eval(&self) -> String { let mut result = String::new(); - let tot = self.total_keypress as f32; let big = self.total_bigrams as f32; let tig = self.total_bigrams as f32; result += &"Percent per key:\n"; - result += &format_block_output(self.keypress.into_iter().map(|k| 100.0 * k as f32 / tot)); + result += &format_block_output(self.keypress_perc.into_iter().map(|u| u * 100.0)); - let mut finger_usages = [0; 8]; - for (i, &c) in self.keypress.iter().enumerate() { - finger_usages[KEY_TO_FINGER[i]] += c; + let mut finger_percs = [0.0; 8]; + for (i, &c) in self.keypress_perc.iter().enumerate() { + finger_percs[KEY_TO_FINGER[i]] += c; } result += "\nFinger usage: "; let mut lh: f32 = 0.0; let mut rh: f32 = 0.0; - for (i, &u) in finger_usages.iter().enumerate() { - let f = u as f32 / tot * 100.0; - result += &format!("{:>5.2}%{}", f, if i < 7 { ", " } else { "" }); + for (i, &u) in finger_percs.iter().enumerate() { + result += &format!("{:>5.2}%{}", u * 100.0, if i < 7 { ", " } else { "" }); if i % 10 < 4 { - lh += f; + lh += u; } else { - rh += f; + rh += u; } } diff --git a/srchr/src/layout.rs b/srchr/src/layout.rs index 81cfd9b..8f8b03a 100644 --- a/srchr/src/layout.rs +++ b/srchr/src/layout.rs @@ -109,23 +109,30 @@ impl Layout { } pub fn from_prelayout(pl: &Prelayout, corpus: &Corpus) -> Layout { + fn my_f32_compare(r: f32, l: f32) -> std::cmp::Ordering { + if r < l { + std::cmp::Ordering::Less + } else { + std::cmp::Ordering::Greater + } + } fn weight_function( columns: &[[u8; N]; M], corpus: &Corpus, - ) -> Vec<(Vec, u32)> { + ) -> Vec<(Vec, f32)> { let mut result = columns .iter() .map(|col| { - let mut weight = 0; - let mut wcol: Vec<(u8, u32)> = col + let mut weight = 0.0; + let mut wcol: Vec<(u8, f32)> = col .iter() .map(|&c| { - let w = corpus.get_character_count(c); + let w = corpus.get_character_perc(c); weight += w; (c, w) }) .collect(); - wcol.sort_by(|(_, l), (_, r)| r.cmp(l)); + wcol.sort_by(|(_, l), (_, r)| my_f32_compare(*r, *l)); wcol.swap(0, 1); if N == 6 { wcol.swap(0, 2); @@ -134,19 +141,19 @@ impl Layout { } (wcol.into_iter().map(|(k, _)| k as u8).collect(), weight) }) - .collect::, u32)>>(); - result.sort_by(|(_, l), (_, r)| r.cmp(l)); + .collect::, f32)>>(); + result.sort_by(|(_, l), (_, r)| my_f32_compare(*r, *l)); result } - let mut balance: i64 = 0; + let mut balance: f32 = 0.0; let mut left_col: usize = 0; let mut right_col: usize = 9; let mut keys = ['x'; NUM_KEYS]; let mut w_standard_columns = weight_function(&pl.standard_columns, corpus); while let Some((col, weight)) = w_standard_columns.pop() { - let left: bool = ((balance >= 0) && (left_col <= 2)) || (right_col <= 6); + let left: bool = ((balance >= 0.0) && (left_col <= 2)) || (right_col <= 6); let ind = if left { left_col } else { right_col }; for i in 0..3 { keys[ind + i * ROW_LENGTH] = col[i] as char; @@ -156,15 +163,11 @@ impl Layout { } else { right_col -= 1; } - balance += if left { - -(weight as i64) - } else { - weight as i64 - }; + balance += if left { -weight } else { weight }; } let w_index_columns = weight_function(&pl.index_columns, corpus); - let (left_ind, right_ind) = if balance >= 0 { (0, 1) } else { (1, 0) }; + let (left_ind, right_ind) = if balance >= 0.0 { (0, 1) } else { (1, 0) }; for j in 0..3 { keys[3 + j * ROW_LENGTH] = w_index_columns[left_ind].0[j] as char; keys[6 + j * ROW_LENGTH] = w_index_columns[right_ind].0[j] as char; -- cgit v1.3.1