diff options
Diffstat (limited to 'srchr/src')
| -rw-r--r-- | srchr/src/config.rs | 9 | ||||
| -rw-r--r-- | srchr/src/corpus.rs | 35 | ||||
| -rw-r--r-- | srchr/src/layout.rs | 174 | ||||
| -rw-r--r-- | srchr/src/main.rs | 1 |
4 files changed, 128 insertions, 91 deletions
diff --git a/srchr/src/config.rs b/srchr/src/config.rs index 9ed98d3..8a7faae 100644 --- a/srchr/src/config.rs +++ b/srchr/src/config.rs @@ -31,7 +31,7 @@ pub fn index_usage_fitness(index_perc: f32) -> f32 { } } -pub const MAX_PINKY_USAGE_PERCENT: f32 = 0.092; +pub const MAX_PINKY_USAGE_PERCENT: f32 = 0.095; 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 { @@ -45,7 +45,12 @@ pub fn pinky_col_penalty(lesser_perc: f32, greater_perc: f32) -> f32 { } // Pre-layout to layout -pub const MINIMISE_LSB_INSTEAD_OF_OPTIMISING_BALANCE: bool = true; +#[allow(dead_code)] +pub enum Algorithm { + MinimiseLSBThenBalance, + GreedyBalance, +} +pub const PRELAYOUT_TO_LAYOUT_ALGORITHM: Algorithm = Algorithm::MinimiseLSBThenBalance; // ----------------------------------------------------------------------------- // Do not change the following, the code makes assumptions about these diff --git a/srchr/src/corpus.rs b/srchr/src/corpus.rs index 846f611..bc6813e 100644 --- a/srchr/src/corpus.rs +++ b/srchr/src/corpus.rs @@ -1,4 +1,3 @@ -use std::fmt; use std::fs; use crate::config::*; @@ -152,37 +151,3 @@ impl Corpus { }); } } - -fn dump_bigrams(corpus: &Corpus) -> Vec<(String, f32)> { - let mut result: Vec<(String, f32)> = Vec::new(); - - for &x in KEY_CHARS.iter() { - for &y in KEY_CHARS.iter() { - let mut pair = String::from(x); - pair.push(y); - let perc = corpus.bigram_percs[pair_to_index(x as u8, y as u8)]; - if perc > 0.0 { - result.push((pair, perc)); - } - } - } - - result.sort_by(|(_, c1), (_, c2)| { - if c2 < c1 { - std::cmp::Ordering::Less - } else { - std::cmp::Ordering::Greater - } - }); - - return result; -} - -impl fmt::Display for Corpus { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(&format!( - "Corpus has top 5 bigrams {:?}", - &dump_bigrams(self)[0..5] - )) - } -} diff --git a/srchr/src/layout.rs b/srchr/src/layout.rs index bc519c1..cc963c7 100644 --- a/srchr/src/layout.rs +++ b/srchr/src/layout.rs @@ -146,68 +146,136 @@ impl Layout { result } - let mut balance: f32 = 0.0; - let mut left_col: usize = 0; - let mut right_col: usize = 9; - let mut keys = ['x'; NUM_KEYS]; - + // Derive column orderings + let w_index_columns = weight_function(&pl.index_columns, corpus); let w_standard_columns = weight_function(&pl.standard_columns, corpus); - for (col, weight) in w_standard_columns.iter() { - 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; - } - if left { - left_col += 1; - } else { - right_col -= 1; - } - balance += if left { -weight } else { *weight }; - } - let w_index_columns = weight_function(&pl.index_columns, corpus); + let mut standard_column_ordering = [0; 6]; + let mut left_ind; + let mut right_ind; + + match PRELAYOUT_TO_LAYOUT_ALGORITHM { + Algorithm::MinimiseLSBThenBalance => { + // first we still want left pinky to have lowest load + let mut balance: f32 = -w_index_columns[0].1 + w_index_columns[1].1; + standard_column_ordering[0] = 0; + standard_column_ordering[5] = 1; - let (left_ind, right_ind); - if MINIMISE_LSB_INSTEAD_OF_OPTIMISING_BALANCE { - // Choose index order to minimise LSB (middle-index only) even though we - // don't directly optimise for this parameter - let mut lsbs = [0.0; 2]; - for option in [0, 1] { - for left in [true, false] { - let mind = if left { 2 } else { 7 }; - let side = if left { option } else { 1 - option }; - let m1 = keys[mind + 10 * 0] as u8; - let m2 = keys[mind + 10 * 1] as u8; - let m3 = keys[mind + 10 * 2] as u8; - let i1 = w_index_columns[side].0[3]; - let i2 = w_index_columns[side].0[4]; - let i3 = w_index_columns[side].0[5]; - lsbs[option] += corpus.get_bigram_perc(m1, i1) - + corpus.get_bigram_perc(m1, i2) - + corpus.get_bigram_perc(m1, i3) - + corpus.get_bigram_perc(m2, i1) - + corpus.get_bigram_perc(m2, i2) - + corpus.get_bigram_perc(m2, i3) - + corpus.get_bigram_perc(m3, i1) - + corpus.get_bigram_perc(m3, i2) - + corpus.get_bigram_perc(m3, i3); + // next find minimum lsb pairing + let mut lsbs = [0.0; 2]; + for swap in [false, true] { + for first_pairing in [true, false] { + let mind = match (swap, first_pairing) { + (true, true) => 5, + (true, false) => 4, + (false, true) => 4, + (false, false) => 5, + }; + let m1 = w_standard_columns[mind].0[0]; + let m2 = w_standard_columns[mind].0[1]; + let m3 = w_standard_columns[mind].0[2]; + let iind = if first_pairing { 0 } else { 1 }; + let i1 = w_index_columns[iind].0[3]; + let i2 = w_index_columns[iind].0[4]; + let i3 = w_index_columns[iind].0[5]; + lsbs[if swap { 1 } else { 0 }] += corpus.get_bigram_perc(m1, i1) + + corpus.get_bigram_perc(m1, i2) + + corpus.get_bigram_perc(m1, i3) + + corpus.get_bigram_perc(m2, i1) + + corpus.get_bigram_perc(m2, i2) + + corpus.get_bigram_perc(m2, i3) + + corpus.get_bigram_perc(m3, i1) + + corpus.get_bigram_perc(m3, i2) + + corpus.get_bigram_perc(m3, i3); + } } + + // if lsbs[0] < lsbs[1] then (4, 0) and (5, 1) are paired, else (5, 0) and (4, 1) + // record weights of pairings and whether we swapped 4 <-> 5 for min lsb + let (swap, w1, w2) = if lsbs[0] < lsbs[1] { + ( + false, + w_standard_columns[4].1 + w_index_columns[0].1, + w_standard_columns[5].1 + w_index_columns[1].1, + ) + } else { + ( + true, + w_standard_columns[5].1 + w_index_columns[0].1, + w_standard_columns[4].1 + w_index_columns[1].1, + ) + }; + + // now we try to balance hands according to combined weight, place + // on left and check if we need to swap + let w: f32; + if w1 < w2 { + ( + (standard_column_ordering[2], left_ind), + (standard_column_ordering[3], right_ind), + ) = if swap { + ((5, 0), (4, 1)) + } else { + ((4, 0), (5, 1)) + }; + w = -w1 + w2; + } else { + ( + (standard_column_ordering[2], left_ind), + (standard_column_ordering[3], right_ind), + ) = if swap { + ((4, 1), (5, 0)) + } else { + ((5, 1), (4, 0)) + }; + w = -w2 + w1; + } + if (balance + w).abs() > (balance - w).abs() { + // swapping would be better + (left_ind, right_ind) = (right_ind, left_ind); + (standard_column_ordering[2], standard_column_ordering[3]) = + (standard_column_ordering[3], standard_column_ordering[2]); + balance -= w; + } else { + balance += w; + } + + // finally we do ring finger + (standard_column_ordering[1], standard_column_ordering[4]) = + if balance >= 0.0 { (3, 2) } else { (2, 3) }; } - (left_ind, right_ind) = if lsbs[0] < lsbs[1] { (0, 1) } else { (1, 0) }; - // if this disagrees with the balancing order, let's consider ring - // column swaps - if balance >= 0.0 && left_ind == 0 && w_standard_columns[2].0[0] == keys[1] as u8 { - for i in 0..3 { - let t = keys[8 + 10 * i]; - keys[8 + 10 * i] = keys[1 + 10 * i]; - keys[1 + 10 * i] = t; + Algorithm::GreedyBalance => { + // greedy on weight, not provably correct in *all* cases but good + // enough in practice + let mut balance: f32 = 0.0; + let mut left_col: usize = 0; + let mut right_col: usize = 9; + + for (src, (_, weight)) in w_standard_columns.iter().enumerate() { + let left: bool = ((balance >= 0.0) && (left_col <= 2)) || (right_col <= 6); + let ind = if left { left_col } else { right_col }; + standard_column_ordering[ind] = src; + if left { + left_col += 1; + } else { + right_col -= 1; + } + balance += if left { -weight } else { *weight }; } + (left_ind, right_ind) = if balance >= 0.0 { (0, 1) } else { (1, 0) } } - } else { - (left_ind, right_ind) = if balance >= 0.0 { (0, 1) } else { (1, 0) } } + // write keys + let mut keys = ['x'; NUM_KEYS]; + // standard + for (ind, src) in standard_column_ordering.into_iter().enumerate() { + let target = if ind < 3 { ind } else { 4 + ind }; + for i in 0..3 { + keys[target + i * ROW_LENGTH] = w_standard_columns[src].0[i] as char; + } + } + // index 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; diff --git a/srchr/src/main.rs b/srchr/src/main.rs index 628dbdb..af1d0d2 100644 --- a/srchr/src/main.rs +++ b/srchr/src/main.rs @@ -88,7 +88,6 @@ fn main() { } else { corpus = Corpus::load_from_text_file(CORPUS_FILE_NAME).unwrap(); } - println!("{}", corpus); let seed_layout = Layout::from_verbose(STARTING_LAYOUT_STRING).unwrap(); let seed_evl = Evaluation::evaluate_layout(&corpus, &seed_layout); |
