Carpalx optimizes keyboard layouts to create ones that require less effort and significantly reduced carpal strain!

Have ideas? Tell me.

# the best layout

Partially optimized QWKRFY and fully optimized QGMLWY layouts are the last word in easier typing.

# the worst layout

A fully anti-optimized TNWMLC layout is a joke and a nightmare to type. It's also the only keyboard layout that has its own fashion line.

# layouts

25 Oct 21 — Added vertical and horizontal alphabetic layouts to the layouts analysis.

19 Mar 21 — Added BEAKL 15, Hieamtsr, Colemak Mod-DH and Mtgap 2.0 layouts to the layouts analysis.

15 Mar 21 — Added the Engram layout by Arno Klein to the layouts analysis.

6 Aug 20 — The search for the world’s best keyboard layout by Paul Guerin

4 May 20 — An interview with Bloomberg's Arianne Cohen Splurge on a Better Keyboard, It's Worth It.

25 May 18 — The BBC article Why we can't give up this off way of typing by Tim McDonald discusses the history and persistence of QWERTY and my Carpalx work.

16 Aug 16 — Ergonomic Keyboard Layout Designed for the Filipino Language at AHFE2016 derives layout for Filipino language using Carpalx

18 Apr 16 — Carpalx layouts soon to appear in freedesktop (package xkeyboard-config) and kbd. Thanks to Perry Thompson.

# Basic Layout Optimization

configuration file : etc/tutorial-03.conf
output : out/tutorials/03

## Configuration

Here's what you're here for - keyboard layout optimization. For this tutorial, we'll do a quick-and-dirty optimization. We'll start with the QWERTY layout and a very short English corpus. To speed things along, I've set the triads_min_freq to 10 - any triads that appear in the corpus fewer than 10 times will not be used.

$... action = loadkeyboard,loadtriads,optimize,quit ... corpus = ../corpus/books.veryshort.txt mode = english triads_overlap = yes triads_min_freq = 10 ... keyboard_input = keyboards/qwerty.conf ...$

You can replace the corpus with books.short.txt, or if you would like an even larger corpus, books.txt.

The short corpus (corpus/books.short.txt) contains the first 50,000 lines (566,916 words) of the full corpus (corpus/books.txt). The very short corpus (corpus/books.veryshort.txt) contains the first 5,000 lines (50,308 words) of the full corpus. You can further limit the number of triads that are parsed by using triads_max_num (this limits the number of total, not unique, triads parsed). The time required for each iteration of optimization will be proportional to the number of unique triads that you parsed in; thus, limiting the corpus size may not necessarily result in a commensurately shorter execution time.

The annealing parameters are defined in the <annealing> block.

$<annealing> action = minimize iterations = 1000 t0 = 10 p0 = 1 k = 10 minswaps = 1 maxswaps = 3 onestep = no </annealing>$

The t0 and k variables control the annealing cooling schedule. minswaps and maxswaps control how many random character swaps are performed to generate a new state.

The output keyboard layout, optimization parameters and current annealing status are reported in the keyboard_output file. The keyboard file contains a random 6 character string to prevent concurrent instances of carpalx from clobbering report files.

$keyboard_output = /home/martink/work/carpalx/dev/out/tutorials/03/tmp-__$CONF{runid}__.conf ... runid = __join("", map { chr(97+rand(26)) } (0..5))__$ ### run-time reporting $> bin/carpalx -conf etc/tutorial-03.conf > out/tutorials/03/out.txt$ At the requested interval (defined by report_period and report_filter), the current keyboard state and annealing parameters will be written out the keyboard_output file. For each iteration, the current keyboard state and parameters will be reported to STDOUT. The STDOUT report looks like this: $iter 7 effort 2.641495 -> 2.613979 d -0.02751655 p 0.99705318 t 9.32393820 better/accept/repor t cpu 0.097902 ------------------------------------------------------------$ 1 2 3 4 5 6 7 8 9 0 - = ~ ! @ #$ % ^ & * ( ) _ +
q g k d o a v x b z [ ] \     Q G K D O A V X B Z { } |
s n f t y h e i m ; '         S N F T Y H E I M : "
u r c p j w l , . /           U R C P J W L < > ?
------------------------------------------------------------
...
iter    239 effort 2.995385 -> 2.511309 d -0.48407581 p 0.58960890 t 0.91629684 better/accept/repor
t cpu 0.097838
------------------------------------------------------------
$1 2 3 4 5 6 7 8 9 0 - = ~ ! @ # $% ^ & * ( ) _ + q g k d o a v x b z [ ] \ Q G K D O A V X B Z { } | s n m h y t e i l ; ' S N M H Y T E I L : " u r c p j w f , . / U R C P J W F < > ? ------------------------------------------------------------ ... iter 862 effort 1.802331 -> 1.799707 d -0.00262427 p 0.23358457 t 0.00180460 better/accept/repor t cpu 0.097255 ------------------------------------------------------------$ 1 2 3 4 5 6 7 8 9 0 - = ~ ! @ #$ % ^ & * ( ) _ +
b c p w y j m u l x [ ] \     B C P W Y J M U L X { } |
n d t a s i o e h ; '         N D T A S I O E H : "
q k r f z v g , . /           Q K R F Z V G < > ?
------------------------------------------------------------
...
iter    956 effort 1.786068 -> 1.778577 d -0.00749106 p 0.00002426 t 0.00070493 better/accept/repor
t cpu 0.098536
------------------------------------------------------------
$1 2 3 4 5 6 7 8 9 0 - = ~ ! @ # $% ^ & * ( ) _ + w m p l c q y u b x [ ] \ W M P L C Q Y U B X { } | d n t a s i o e h ; ' D N T A S I O E H : " j k r f z v g , . / J K R F Z V G < > ? ------------------------------------------------------------ Total time spent optimizing: 98.45551 s$ For each iteration, the candidate keyboard layout is shown (lower case on the left and upper case on the right). The effort transition from previous to current state is shown, along with the effort difference (d), the probability of transition to the new state (p), and the cooling parameter (t) for the current iteration. Each iteration is also annotated with FLAG1/FLAG2 where FLAG1=better|worse and FLAG2=accept|reject. FLAG1 indicates whether the new state is more desirable (lower effort) and FLAG2 indicates whether the new state is accepted. Lower effort states are always accepted and higher effort states are accepted based on the probability p. The time to perform the iteration is also shown. Concurrently, the keyboard_output file is updated each time the energy for a new state is lower than previously seen (note the difference between report_filter=lower and report_filter=lower_monotonic). For this specific run, the file is tmp-rhdbnd.conf. The format of this file is the same as the keyboard_input file. Therefore, you can resume optimization at a later time or generate reports for this keyboard layout. $<current_parameters> iter = 956 effort = 1.77857723249378466 deffort = -0.00749105590454603686 update_count = 465 t = 0.00070492798662117875 </current_parameters> <annealing_parameters> t0 = 10 k = 10 maxswaps = 3 p0 = 1 action = minimize iterations = 1000 onestep = 0 minswaps = 1 </annealing_parameters> <keyboard> <row 1> keys =$~ 1! 2@ 3\# 4$ 5% 6^ 7& 8* 9( 0) -_ =+
fingers  = 0 1 1 2 3 3 3 6 7 7 8 9 9
</row>
<row 2>
keys = w m p l c q y u b x [{ ]} \|
fingers  = 0 1 2 3 3 6 6 7 8 9 9 9 9
</row>
<row 3>
keys = d n t a s i o e h ;: '"
fingers  = 0 1 2 3 3 6 6 7 8 9 9
</row>
<row 4>
keys = j k r f z v g ,< .> /?
fingers  = 0 1 2 3 3 6 6 7 8 9
</row>
</keyboard>

$After this run, we've lowered the typing effort of the corpus from 3 to 1.8. The <current_parameters> block indicates that effort was lowered in 465 distinct steps and the lowest energy was seen at iteration 956. Simulated annealing is stochastic optimization method. I suggest you run carpalx multiple times with the same parameters and choose the best result. Performing multiple optimizations will also give you an indication of how many general families of layouts you are converging to. For example, running the process again (tmp-nfduur.conf), yields a layout with an effort of 4.8. $# first run (tmp-yryhmp.conf) (effort = 1.779)
w m p l c q y u b x [{ ]} \|
d n t a s i o e h ;: '"
j k r f z v g ,< .> /?

# second run (tmp-ippjnl.conf) (effort = 1.758)
x y d l g b f s w v [{ ]} \|
u h e i r t a o n ;: '"
z j k c q m p ,< .> /?

`

In this case, the layouts are quite different. Although you would need to perform more optimizations to determine whether the algorithm converges, I would do so with more iterations (e.g. 10,000 instead of 1,000). The advanced optimization tutorial discusses the effect of adjusting the annealing parameters, such as the cooling schedule.