1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
mod corpus;
mod layout;
use rayon::prelude::*;
use rand::prelude::*;
use rand_pcg::*;
use corpus::*;
use layout::*;
use std::time::Instant;
const NUM_CONTESTANTS: usize = 128;
const NUM_PERSIST: usize = 8;
// TODO: command line arguments to start at a given layout string, maybe read
// from file? Might as well make num_contestants and survive_threshold
// configurable, and number of swaps when generating new layout, and index
// finger threshold.
struct Tournament<'a> {
rngs: Vec<Pcg64>,
top_prelayouts: Vec<(Prelayout, u32)>,
corpus: &'a Corpus,
}
impl<'a> Tournament<'a> {
fn new_from_seed_prelayout(seed_prelayout: &Prelayout, corpus: &'a Corpus) -> Tournament<'a> {
let mut rngs: Vec<Pcg64> = Vec::new();
for _ in 0..NUM_CONTESTANTS {
rngs.push(Pcg64::from_entropy());
}
let mut top_prelayouts: Vec<(Prelayout, u32)> = Vec::new();
let score = corpus.prelayout_fitness(&seed_prelayout);
for _ in 0..NUM_PERSIST {
top_prelayouts.push((seed_prelayout.clone(), score));
}
Tournament {
rngs,
top_prelayouts,
corpus,
}
}
fn run_round(&mut self) -> Option<Prelayout> {
let rngs = &mut self.rngs;
let mut tournament = rngs
.into_par_iter()
.map(|mut rng| {
let layout = Prelayout::new_random_from(
&self.top_prelayouts[rng.gen_range(0..NUM_PERSIST)].0,
&mut rng,
);
return (layout, self.corpus.prelayout_fitness(&layout));
})
.collect::<Vec<(Prelayout, u32)>>();
let best = self.top_prelayouts[0].1;
tournament.append(&mut self.top_prelayouts);
tournament.sort_by(|(_, lscore), (_, rscore)| lscore.cmp(rscore));
let result;
if tournament[0].1 < best {
result = Some(tournament[0].0);
} else {
result = None;
}
for i in 0..NUM_PERSIST {
self.top_prelayouts.push(tournament[i]);
}
result
}
}
fn main() {
let corpus = Corpus::load("new.txt").unwrap();
println!("{}", corpus);
let seed_prelayout = Layout::from_verbose("QWERTYUIOPASDFGHJKL'ZXCVBNM,./")
.unwrap()
.as_prelayout();
let mut tournament = Tournament::new_from_seed_prelayout(&seed_prelayout, &corpus);
let mut count: usize = 0;
let mut current = Instant::now();
loop {
let improvement = tournament.run_round();
if let Some(prelayout) = improvement {
let layout = Layout::from_prelayout(&prelayout, &corpus);
let evl = corpus.evaluate_layout(&layout);
println!("");
println!("================================================================================\n\n{}",
layout
);
println!("{}", evl);
}
count += 1;
if count > 65535 {
let duration = current.elapsed();
eprint!(
"\u{001b}[2K\u{001b}[1000D{} layouts/s",
(count * NUM_CONTESTANTS) as f32 / duration.as_millis() as f32 * 1000.0
);
current = Instant::now();
count = 0;
}
}
}
|