aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortslil clingman <tslil@posteo.de>2022-09-25 23:33:03 +0200
committertslil clingman <tslil@posteo.de>2022-09-25 23:35:24 +0200
commit938764a7328eeee747acfa4af07d3b3b91173fc1 (patch)
tree5bf6f110143d7eeee00de16cf115dea42876029e /src
parent6c9cee559d6f461ec660d3a1416b70e475b1c3bb (diff)
Added in prelayouts, speed info
Diffstat (limited to 'src')
-rw-r--r--src/config.rs4
-rw-r--r--src/corpus.rs72
-rw-r--r--src/layout.rs169
-rw-r--r--src/main.rs65
4 files changed, 222 insertions, 88 deletions
diff --git a/src/config.rs b/src/config.rs
index 4449b7b..bc86613 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,4 +1,6 @@
-pub const NUM_KEYS: usize = 30; // you should not change this
+// Do not change
+pub const NUM_KEYS: usize = 30;
+pub const ROW_LENGTH: usize = 10;
pub const KEY_CHARS: [char; NUM_KEYS] = [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
diff --git a/src/corpus.rs b/src/corpus.rs
index 2fab5a4..2677cd2 100644
--- a/src/corpus.rs
+++ b/src/corpus.rs
@@ -51,55 +51,45 @@ impl Corpus {
});
}
- pub fn layout_fitness(&self, layout: &Layout) -> u32 {
+ pub fn prelayout_fitness(&self, layout: &Prelayout) -> u32 {
let mut sfb: u32 = 0;
- // TODO: We make assumptions about NUM_KEYS here
- for i in 0..8 {
- let ind = if i < 4 { i } else { i + 2 };
-
- let k1 = layout.get_key(ind + 10 * 0);
- let k2 = layout.get_key(ind + 10 * 1);
- let k3 = layout.get_key(ind + 10 * 2);
+ for i in 0..6 {
+ let keys = layout.get_standard_column(i);
+ let k1 = keys[0];
+ let k2 = keys[1];
+ let k3 = keys[2];
sfb += self.bigram_count[pair_to_index(k1, k2)]
+ self.bigram_count[pair_to_index(k1, k3)]
+ self.bigram_count[pair_to_index(k2, k3)];
+ }
- if i == 3 {
- let k4 = layout.get_key(4 + 10 * 0);
- let k5 = layout.get_key(4 + 10 * 1);
- let k6 = layout.get_key(4 + 10 * 2);
- sfb += self.bigram_count[pair_to_index(k4, k5)]
- + self.bigram_count[pair_to_index(k4, k6)]
- + self.bigram_count[pair_to_index(k5, k6)]
- + self.bigram_count[pair_to_index(k1, k4)]
- + self.bigram_count[pair_to_index(k1, k5)]
- + self.bigram_count[pair_to_index(k1, k6)]
- + self.bigram_count[pair_to_index(k2, k4)]
- + self.bigram_count[pair_to_index(k2, k5)]
- + self.bigram_count[pair_to_index(k2, k6)]
- + self.bigram_count[pair_to_index(k3, k4)]
- + self.bigram_count[pair_to_index(k3, k5)]
- + self.bigram_count[pair_to_index(k3, k6)];
- } else if i == 4 {
- let k4 = layout.get_key(5 + 10 * 0);
- let k5 = layout.get_key(5 + 10 * 1);
- let k6 = layout.get_key(5 + 10 * 2);
- sfb += self.bigram_count[pair_to_index(k4, k5)]
- + self.bigram_count[pair_to_index(k5, k6)]
- + self.bigram_count[pair_to_index(k4, k6)]
- + self.bigram_count[pair_to_index(k1, k4)]
- + self.bigram_count[pair_to_index(k1, k5)]
- + self.bigram_count[pair_to_index(k1, k6)]
- + self.bigram_count[pair_to_index(k2, k4)]
- + self.bigram_count[pair_to_index(k2, k5)]
- + self.bigram_count[pair_to_index(k2, k6)]
- + self.bigram_count[pair_to_index(k3, k4)]
- + self.bigram_count[pair_to_index(k3, k5)]
- + self.bigram_count[pair_to_index(k3, k6)];
- }
+ for i in 0..2 {
+ let keys = layout.get_index_column(i);
+ let k1 = keys[0];
+ let k2 = keys[1];
+ let k3 = keys[2];
+ let k4 = keys[3];
+ let k5 = keys[4];
+ let k6 = keys[5];
+ sfb += self.bigram_count[pair_to_index(k1, k2)]
+ + self.bigram_count[pair_to_index(k1, k3)]
+ + self.bigram_count[pair_to_index(k2, k3)]
+ + self.bigram_count[pair_to_index(k4, k5)]
+ + self.bigram_count[pair_to_index(k4, k6)]
+ + self.bigram_count[pair_to_index(k5, k6)]
+ + self.bigram_count[pair_to_index(k1, k4)]
+ + self.bigram_count[pair_to_index(k1, k5)]
+ + self.bigram_count[pair_to_index(k1, k6)]
+ + self.bigram_count[pair_to_index(k2, k4)]
+ + self.bigram_count[pair_to_index(k2, k5)]
+ + self.bigram_count[pair_to_index(k2, k6)]
+ + self.bigram_count[pair_to_index(k3, k4)]
+ + self.bigram_count[pair_to_index(k3, k5)]
+ + self.bigram_count[pair_to_index(k3, k6)];
}
+
sfb
}
diff --git a/src/layout.rs b/src/layout.rs
index 4c77be4..fe853ad 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -4,6 +4,120 @@ use rand::prelude::*;
use std::fmt;
#[derive(Copy, Clone)]
+pub struct Prelayout {
+ standard_columns: [[char; 3]; 6],
+ index_columns: [[char; 6]; 2],
+}
+
+impl Prelayout {
+ pub fn get_standard_column(&self, index: usize) -> &[char; 3] {
+ &self.standard_columns[index]
+ }
+
+ pub fn get_index_column(&self, index: usize) -> &[char; 6] {
+ &self.index_columns[index]
+ }
+
+ pub fn new_random_from<R: RngCore>(pl: &Prelayout, rng: &mut R) -> Prelayout {
+ let mut standard_columns = pl.standard_columns.clone();
+ let mut index_columns = pl.index_columns.clone();
+
+ let mut count = rng.gen_range(1..=NUM_KEYS / 2);
+ while count > 0 {
+ let source_index: bool = rng.gen();
+ let target_index: bool = rng.gen();
+
+ let saved;
+ let target_col: usize;
+ let target_idx: usize;
+ if target_index {
+ target_col = rng.gen_range(0..2);
+ target_idx = rng.gen_range(0..6);
+ saved = index_columns[target_col][target_idx];
+ } else {
+ target_col = rng.gen_range(0..6);
+ target_idx = rng.gen_range(0..3);
+ saved = standard_columns[target_col][target_idx];
+ }
+
+ let source_col: usize;
+ let source_idx: usize;
+ if source_index {
+ source_col = rng.gen_range(0..2);
+ source_idx = rng.gen_range(0..6);
+ if target_index {
+ index_columns[target_col][target_idx] = index_columns[source_col][source_idx];
+ } else {
+ standard_columns[target_col][target_idx] =
+ index_columns[source_col][source_idx];
+ }
+ index_columns[source_col][source_idx] = saved;
+ } else {
+ source_col = rng.gen_range(0..6);
+ source_idx = rng.gen_range(0..3);
+ if target_index {
+ index_columns[target_col][target_idx] =
+ standard_columns[source_col][source_idx];
+ } else {
+ standard_columns[target_col][target_idx] =
+ standard_columns[source_col][source_idx];
+ }
+ standard_columns[source_col][source_idx] = saved;
+ }
+ count -= 1;
+ }
+ Prelayout {
+ standard_columns,
+ index_columns,
+ }
+ }
+
+ fn from_char_array(ca: &[char; NUM_KEYS]) -> Prelayout {
+ let mut standard_columns = [['x'; 3]; 6];
+ let mut index_columns = [['x'; 6]; 2];
+
+ for i in 0..6 {
+ let ind = if i < 3 { i } else { i + 4 };
+ for j in 0..3 {
+ standard_columns[i][j] = ca[ind + j * ROW_LENGTH];
+ }
+ }
+
+ for j in 0..3 {
+ index_columns[0][j] = ca[3 + j * ROW_LENGTH];
+ index_columns[1][j] = ca[6 + j * ROW_LENGTH];
+ index_columns[0][j + 3] = ca[4 + j * ROW_LENGTH];
+ index_columns[1][j + 3] = ca[5 + j * ROW_LENGTH];
+ }
+
+ Prelayout {
+ standard_columns,
+ index_columns,
+ }
+ }
+
+ fn to_char_array(&self) -> [char; NUM_KEYS] {
+ let mut result = ['x'; NUM_KEYS];
+
+ for i in 0..6 {
+ let ind = if i < 3 { i } else { i + 4 };
+ for j in 0..3 {
+ result[ind + j * ROW_LENGTH] = self.standard_columns[i][j];
+ }
+ }
+
+ for j in 0..3 {
+ result[3 + j * ROW_LENGTH] = self.index_columns[0][j];
+ result[6 + j * ROW_LENGTH] = self.index_columns[1][j];
+ result[4 + j * ROW_LENGTH] = self.index_columns[0][j + 3];
+ result[5 + j * ROW_LENGTH] = self.index_columns[1][j + 3];
+ }
+
+ result
+ }
+}
+
+#[derive(Copy, Clone)]
pub struct Layout {
keys: [char; NUM_KEYS],
// index in KEY_CHAR -> index in layout
@@ -11,15 +125,16 @@ pub struct Layout {
}
impl Layout {
- pub fn get_key(&self, index: usize) -> char {
- self.keys[index]
+ pub fn as_prelayout(&self) -> Prelayout {
+ Prelayout::from_char_array(&self.keys)
}
- pub fn translate_index(&self, i: usize) -> usize {
- self.translate_index[i]
+ pub fn from_prelayout(pl: &Prelayout) -> Layout {
+ // TODO: something more clever about permuting colums, keys within columns etc
+ Layout::char_array_to_layout(pl.to_char_array())
}
- fn keys_to_layout(layout: [char; NUM_KEYS]) -> Layout {
+ fn char_array_to_layout(layout: [char; NUM_KEYS]) -> Layout {
let mut translate_index: [usize; NUM_KEYS] = [0; NUM_KEYS];
for (i, seek) in KEY_CHARS.iter().enumerate() {
@@ -36,6 +151,14 @@ impl Layout {
};
}
+ pub fn get_key(&self, index: usize) -> char {
+ self.keys[index]
+ }
+
+ pub fn translate_index(&self, i: usize) -> usize {
+ self.translate_index[i]
+ }
+
pub fn from_verbose(inp: &str) -> Option<Layout> {
let mut layout: [char; NUM_KEYS] = ['x'; NUM_KEYS];
@@ -55,23 +178,23 @@ impl Layout {
}
}
- return Some(Layout::keys_to_layout(layout));
+ return Some(Layout::char_array_to_layout(layout));
}
- pub fn new_random_from<R: RngCore>(kbd: &Layout, rng: &mut R) -> Layout {
- let mut layout = kbd.keys;
- // layout.shuffle(rng);
- let mut count = rng.gen_range(1..=15);
- while count > 0 {
- let a = rng.gen_range(0..NUM_KEYS);
- let b = rng.gen_range(0..NUM_KEYS);
- let k = layout[b];
- layout[b] = layout[a];
- layout[a] = k;
- count -= 1;
- }
- Layout::keys_to_layout(layout)
- }
+ // pub fn new_random_from<R: RngCore>(kbd: &Layout, rng: &mut R) -> Layout {
+ // let mut layout = kbd.keys;
+ // // layout.shuffle(rng);
+ // let mut count = rng.gen_range(1..=NUM_KEYS / 2);
+ // while count > 0 {
+ // let a = rng.gen_range(0..NUM_KEYS);
+ // let b = rng.gen_range(0..NUM_KEYS);
+ // let k = layout[b];
+ // layout[b] = layout[a];
+ // layout[a] = k;
+ // count -= 1;
+ // }
+ // Layout::char_array_to_layout(layout)
+ // }
}
impl fmt::Display for Layout {
@@ -129,10 +252,8 @@ impl Evaluation {
);
}
- result += &format!(
- "\ntotal sfb: {:.2}%",
- self.sfb.iter().sum::<u32>() as f32 / tot * 100.0
- );
+ let sfb = self.sfb.iter().sum::<u32>();
+ result += &format!("\ntotal sfb: {:.2}% ({})", sfb as f32 / tot * 100.0, sfb);
return result;
}
diff --git a/src/main.rs b/src/main.rs
index cee008c..3fee6a7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -10,8 +10,10 @@ use rand_pcg::*;
use corpus::*;
use layout::*;
+use std::time::Instant;
+
const NUM_CONTESTANTS: usize = 24;
-const SURVIVE_THRESHOLD: usize = 2;
+const SURVIVE_THRESHOLD: usize = 4;
// TODO: Layout is really pre-layout, have something that takes a layout and
// re-orders columns to balance hands, and keys per column (block really
@@ -25,61 +27,80 @@ fn main() {
let corpus = Corpus::load("new.txt").unwrap();
println!("{}", corpus);
- let starting_layout = Layout::from_verbose(
+ let starting_prelayout = Layout::from_verbose(
"
Y W F L M K P O , Q
U R S N H D T E A I
Z X C V J B G ' . /
",
)
- .unwrap();
+ .unwrap()
+ .as_prelayout();
let mut rng = Pcg64::from_entropy();
- type Fun = Vec<(Layout, u32)>;
+ type Fun = Vec<(Prelayout, u32)>;
let mut best = std::u32::MAX;
- let mut layouts: Fun = (0..NUM_CONTESTANTS)
+ let mut prelayouts: Fun = (0..NUM_CONTESTANTS)
.into_iter()
- .map(|_| {
- let layout;
- layout = Layout::new_random_from(&starting_layout, &mut rng);
- return (layout, corpus.layout_fitness(&layout));
+ .map(|i| {
+ if i > 0 {
+ let layout;
+ layout = Prelayout::new_random_from(&starting_prelayout, &mut rng);
+ return (layout, std::u32::MAX);
+ } else {
+ (starting_prelayout, std::u32::MAX)
+ }
})
.collect();
+ let mut count: usize = 0;
+ let mut current = Instant::now();
loop {
- let new_layouts = layouts
+ let new_prelayouts = prelayouts
.iter()
.enumerate()
.map(|(i, (kbd, _))| {
if i > SURVIVE_THRESHOLD {
let parent = rng.gen_range(0..=SURVIVE_THRESHOLD);
- Layout::new_random_from(&layouts[parent].0, &mut rng)
+ Prelayout::new_random_from(&prelayouts[parent].0, &mut rng)
} else {
kbd.clone()
}
})
- .collect::<Vec<Layout>>();
+ .collect::<Vec<Prelayout>>();
- new_layouts
+ new_prelayouts
.par_iter()
.map(|layout| {
- return (*layout, corpus.layout_fitness(layout));
+ return (*layout, corpus.prelayout_fitness(layout));
})
- .collect_into_vec(&mut layouts);
+ .collect_into_vec(&mut prelayouts);
+
+ prelayouts.sort_by(|(_, lfit), (_, rfit)| lfit.cmp(rfit));
- layouts.sort_by(|(_, lfit), (_, rfit)| lfit.cmp(rfit));
+ count += 1;
+ if count > 65535 {
+ let duration = current.elapsed();
+ eprint!(
+ "\u{001b}[2K\u{001b}[1000D{} iters/s",
+ count as f32 / duration.as_millis() as f32 * 1000.0
+ );
+ current = Instant::now();
+ count = 0;
+ }
- if layouts[0].1 < best {
- best = layouts[0].1;
- let evl = corpus.evaluate_layout(&layouts[0].0);
+ if prelayouts[0].1 < best {
+ best = prelayouts[0].1;
+ let layout = Layout::from_prelayout(&prelayouts[0].0);
+ let evl = corpus.evaluate_layout(&layout);
println!("");
println!("================================================================================\nLayout:\n{}",
- layouts[0].0
- );
+ layout
+ );
- println!("{}\n{}", evl, layouts[0].1);
+ println!("{}", evl);
}
}
}