aboutsummaryrefslogtreecommitdiff
path: root/srchr/src
diff options
context:
space:
mode:
authortslil clingman <tslil@posteo.de>2022-10-23 13:38:28 +0200
committertslil clingman <tslil@posteo.de>2022-10-23 13:38:28 +0200
commit13e282705df90829ac39b75efde47e84e35cc1b1 (patch)
treee88a0799573a035f6ee1e095c218b19c167872c9 /srchr/src
parent6db23c417ea59dd9b9b928f022d40e20b80d2e67 (diff)
enhanced pre-layout -> layout algorithm
Diffstat (limited to 'srchr/src')
-rw-r--r--srchr/src/config.rs9
-rw-r--r--srchr/src/corpus.rs35
-rw-r--r--srchr/src/layout.rs174
-rw-r--r--srchr/src/main.rs1
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);