diff options
| -rw-r--r-- | srchr/src/config.rs | 16 | ||||
| -rw-r--r-- | srchr/src/corpus.rs | 17 | ||||
| -rw-r--r-- | srchr/src/evaluation.rs | 49 | ||||
| -rw-r--r-- | 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<const N: usize, const M: usize>( columns: &[[u8; N]; M], corpus: &Corpus, - ) -> Vec<(Vec<u8>, u32)> { + ) -> Vec<(Vec<u8>, 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::<Vec<(Vec<u8>, u32)>>(); - result.sort_by(|(_, l), (_, r)| r.cmp(l)); + .collect::<Vec<(Vec<u8>, 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; |
