diff --git a/compare_layouts.ipynb b/compare_layouts.ipynb index a8da773..d45e4c6 100644 --- a/compare_layouts.ipynb +++ b/compare_layouts.ipynb @@ -90,7 +90,7 @@ "| [QGMLWB](https://keyboard-design.com/letterlayout.html?layout=qgmlwb.en.ansi) | 2009 | http://mkweb.bcgsc.ca/carpalx/?full_optimization | \n", "| [Colemak](https://keyboard-design.com/letterlayout.html?layout=colemak.en.ansi) | 2006 | https://colemak.com/ | \n", "| [Asset](https://keyboard-design.com/letterlayout.html?layout=asset.en.ansi) | 2006 | http://millikeys.sourceforge.net/asset/ | \n", - "| [Capewell-Dvorak](https://keyboard-design.com/letterlayout.html?layout=capewell.en.ansi) | 2004 | http://michaelcapewell.com/projects/keyboard/layout_capewell-dvorak.htm |\n", + "| Capewell-Dvorak | 2004 | http://michaelcapewell.com/projects/keyboard/layout_capewell-dvorak.htm |\n", "| [Klausler](https://www.keyboard-design.com/letterlayout.html?layout=klausler.en.ansi) | 2002 | https://web.archive.org/web/20031001163722/http://klausler.com/evolved.html |\n", "| [Dvorak](https://keyboard-design.com/letterlayout.html?layout=dvorak.en.ansi) | 1936 | https://en.wikipedia.org/wiki/Dvorak_keyboard_layout | \n", "| [QWERTY](https://keyboard-design.com/letterlayout.html?layout=qwerty.en.ansi) | 1873 | https://en.wikipedia.org/wiki/QWERTY |\n", diff --git a/engram_layout_v1.3.ipynb b/engram_layout_v1.3.ipynb index 68daced..6744319 100644 --- a/engram_layout_v1.3.ipynb +++ b/engram_layout_v1.3.ipynb @@ -160,7 +160,7 @@ "| [QGMLWB](https://keyboard-design.com/letterlayout.html?layout=qgmlwb.en.ansi) | 2009 | http://mkweb.bcgsc.ca/carpalx/?full_optimization | \n", "| [Colemak](https://keyboard-design.com/letterlayout.html?layout=colemak.en.ansi) | 2006 | https://colemak.com/ | \n", "| [Asset](https://keyboard-design.com/letterlayout.html?layout=asset.en.ansi) | 2006 | http://millikeys.sourceforge.net/asset/ | \n", - "| [Capewell-Dvorak](https://keyboard-design.com/letterlayout.html?layout=capewell.en.ansi) | 2004 | http://michaelcapewell.com/projects/keyboard/layout_capewell-dvorak.htm |\n", + "| Capewell-Dvorak | 2004 | http://michaelcapewell.com/projects/keyboard/layout_capewell-dvorak.htm |\n", "| [Klausler](https://www.keyboard-design.com/letterlayout.html?layout=klausler.en.ansi) | 2002 | https://web.archive.org/web/20031001163722/http://klausler.com/evolved.html |\n", "| [Dvorak](https://keyboard-design.com/letterlayout.html?layout=dvorak.en.ansi) | 1936 | https://en.wikipedia.org/wiki/Dvorak_keyboard_layout | \n", "| [QWERTY](https://keyboard-design.com/letterlayout.html?layout=qwerty.en.ansi) | 1873 | https://en.wikipedia.org/wiki/QWERTY |\n", diff --git a/engram_layout_v2.0.ipynb b/engram_layout_v2.0.ipynb new file mode 100644 index 0000000..2be9d19 --- /dev/null +++ b/engram_layout_v2.0.ipynb @@ -0,0 +1,6092 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "J1wRG8laa8Pm" + }, + "source": [ + "# Arno's Engram 2 keyboard layout\n", + "\n", + "Engram 2 is a key layout optimized for comfortable and efficient touch typing in English \n", + "created by [Arno Klein](https://binarybottle.com), \n", + "with [open source code](https://github.com/binarybottle/engram) to create other optimized key layouts.\n", + "You can install the Engram layout on [Windows, macOS, and Linux](https://keyman.com/keyboards/engram)\n", + "or [try it out online](https://keymanweb.com/#en,Keyboard_engram).\n", + "An article is under review (see the [preprint](https://www.preprints.org/manuscript/202103.0287/v1)).\n", + "\n", + "Letters are optimally arranged according to ergonomic factors that promote reduction of lateral finger movements and more efficient typing of high-frequency letter pairs: \n", + "\n", + " Y P O X F C M W Q\n", + " H I E A T S N R Z\n", + " G K J U D V B L\n", + "\n", + "The most common punctuation marks are logically grouped together in the middle columns and numbers are paired with mathematical and logic symbols (shown as pairs of default and Shift-key-accessed characters):\n", + "\n", + " [{ 1| 2= 3~ 4+ 5< 6> 7^ 8& 9% 0* ]} /\\\n", + " yY pP oO xX ‘( “) fF cC mM wW qQ #$ @`\n", + " hH iI eE aA ,; .: tT sS nN rR zZ\n", + " gG kK jJ uU -_ ?! dD vV bB lL \n", + "\n", + "See below for a full description and comparisons with other key layouts.\n", + "\n", + "### Standard diagonal keyboard (default and Shift-key layers)\n", + "![Standard keyboard](https://github.com/binarybottle/engram/blob/master/assets/engram-800px.png?raw=true)\n", + "\n", + "### \"Ergonomic\" orthonormal keyboard (default and Shift-key layers)\n", + "![Orthonormal keyboard](https://github.com/binarybottle/engram/blob/master/assets/engram-ergo-squeezed-800px.png?raw=true)\n", + "\n", + "(c) 2021 Arno Klein, MIT license\n", + "\n", + "----------------" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "awscg4wBa8Po" + }, + "source": [ + "# Contents\n", + "1. [Why a new key layout?](#why)\n", + "2. [How does Engram compare with other key layouts?](#scores)\n", + "3. [Guiding criteria](#criteria)\n", + "4. [Summary of steps and results](#summary)\n", + "5. Setup:\n", + " - [Dependencies and functions](#import)\n", + " - [Speed matrix](#speed)\n", + " - [Strength matrix](#strength)\n", + " - [Flow matrix](#flow)\n", + "6. Steps:\n", + " - [Step 1: Define the shape of the key layout to minimize lateral finger movements](#step1)\n", + " - [Step 2: Arrange the most frequent letters based on comfort and bigram frequencies](#step2)\n", + " - [Step 3: Optimize assignment of the remaining letters](#step3)\n", + " - [Step 4: Stability tests](#step4)\n", + " - [Step 5: Arrange non-letter characters in easy-to-remember places](#step5)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "SSdE4O9Wa8Pp" + }, + "source": [ + "## Why a new key layout? \n", + "\n", + "**Personal history**
\n", + "In the future, I hope to include an engaging rationale for why I took on this challenge.\n", + "Suffice to say I love solving problems, and I have battled repetitive strain injury \n", + "ever since I worked on an old DEC workstation at the MIT Media Lab while composing \n", + "my thesis back in the 1990s.\n", + "I have experimented with a wide variety of human interface technologies over the years --\n", + "voice dictation, one-handed keyboard, keyless keyboard, foot mouse, and ergonomic keyboards \n", + "like the Kinesis Advantage and [Ergodox](https://configure.ergodox-ez.com/ergodox-ez/layouts/APXBR/latest/0) keyboards with different key switches.\n", + "While these technologies can significantly improve comfort and reduce strain, \n", + "an optimized key layout can only help when typing on ergonomic or standard keyboards. \n", + "\n", + "I have used different key layouts (Qwerty, Dvorak, Colemak, etc.)\n", + "for communications and for writing and programming projects,\n", + "and have primarily relied on Colemak for the last 10 years. \n", + "**I find that most to all of these key layouts:**\n", + "\n", + "- Demand too much strain on tendons\n", + " - *strenuous lateral extension of the index and little fingers*\n", + "- Ignore the ergonomics of the human hand\n", + " - *different finger strengths*\n", + " - *different finger lengths*\n", + " - *natural roundedness of the hand*\n", + " - *home row easier than upper row for shorter fingers*\n", + " - *home row easier than lower row for longer fingers*\n", + " - *ease of little-to-index finger rolls vs. reverse*\n", + "- Over-emphasize alternation between hands and under-emphasize same-hand, different-finger transitions\n", + " - *same-row, adjacent finger transitions are easy and comfortable*\n", + " - *little-to-index finger rolls are easy and comfortable*\n", + "\n", + "While I used ergonomic principles outlined below and the accompanying code to help generate the Engram layout,\n", + "I also relied on massive bigram frequency data for the English language. \n", + "if one were to follow the procedure below and use a different set of bigram frequencies for another language or text corpus,\n", + "they could create a variant of the Engram layout, say \"Engram-French\", better suited to the French language.\n", + " \n", + "**Why \"Engram\"?**
\n", + "The name is a pun, referring both to \"n-gram\", letter permutations and their frequencies that are used to compute the Engram layout, and \"engram\", or memory trace, the postulated change in neural tissue to account for the persistence of memory, as a nod to my attempt to make this layout easy to remember." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "vkv2v3gla8Pt" + }, + "source": [ + "## How does Engram compare with other key layouts?
\n", + "\n", + "Despite the fact that the Engram layout was designed to reduce strain and discomfort, not specifically to increase speed or reduce finger travel from the home row, it scores higher than all other key layouts (Colemak, Dvorak, QWERTY, etc.) for some large, representative, publicly available data (all text sources are listed below and available on [GitHub](https://github.com/binarybottle/text_data)). Below are tables of different prominent key layouts scored using the Engram Scoring Model (detailed below).\n", + " \n", + "#### Engram Scoring Model scores (x1000) for different layouts, based on publicly available text data\n", + "\n", + "| Layout | Google bigrams | Alice | Romeo | Gita | Memento | 100K tweets | 20K tweets | MASC tweets | MASC spoken | COCA blogs | Google | Code |\n", + "| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |\n", + "| Engram | 25.14 | 19.53 | 21.11 | 19.48 | 26.12 | 33.19 | 29.95 | 28.08 | 18.45 | 24.97 | 44.19 | 27.43 |\n", + "| Hieamtsrn | 24.85 | 19.32 | 20.90 | 19.28 | 25.76 | 32.87 | 29.55 | 27.75 | 18.29 | 24.71 | 43.46 | 26.85 |\n", + "| Halmak | 24.74 | 19.31 | 20.86 | 19.22 | 25.88 | 32.94 | 29.62 | 27.76 | 18.33 | 24.64 | 43.59 | 27.14 |\n", + "| Workman | 24.51 | 19.10 | 20.63 | 19.01 | 25.64 | 32.60 | 29.31 | 27.49 | 18.08 | 24.37 | 42.89 | 26.95 |\n", + "| MTGap 2.0 | 24.42 | 18.91 | 20.49 | 18.90 | 25.45 | 32.39 | 29.07 | 27.42 | 17.89 | 24.28 | 42.88 | 27.04 |\n", + "| Colemak | 24.37 | 18.86 | 20.50 | 18.89 | 25.37 | 32.38 | 28.96 | 27.31 | 17.94 | 24.24 | 42.30 | 27.11 |\n", + "| Colemak Mod-DH | 24.26 | 18.80 | 20.37 | 18.85 | 25.24 | 32.20 | 28.82 | 27.19 | 17.86 | 24.11 | 42.24 | 26.80 |\n", + "| Norman | 24.22 | 19.03 | 20.49 | 18.97 | 25.43 | 32.31 | 28.98 | 27.15 | 18.02 | 24.14 | 42.11 | 26.60 |\n", + "| Klausler | 24.12 | 18.80 | 20.37 | 18.81 | 25.25 | 32.11 | 28.78 | 26.94 | 17.89 | 24.01 | 41.95 | 26.58 |\n", + "| QGMLWB | 24.07 | 18.82 | 20.29 | 18.75 | 25.23 | 32.06 | 28.85 | 26.88 | 17.85 | 23.95 | 42.12 | 26.44 |\n", + "| BEAKL 15 | 24.05 | 18.65 | 20.25 | 18.68 | 25.04 | 32.15 | 28.80 | 27.06 | 17.77 | 23.97 | 41.99 | 26.69 |\n", + "| Capewell-Dvorak | 23.90 | 18.66 | 20.19 | 18.64 | 24.97 | 31.88 | 28.52 | 26.79 | 17.73 | 23.82 | 41.50 | 26.30 |\n", + "| Asset | 23.75 | 18.34 | 20.00 | 18.32 | 24.88 | 31.76 | 28.42 | 26.82 | 17.47 | 23.69 | 41.95 | 26.57 |\n", + "| Dvorak | 23.70 | 18.52 | 20.08 | 18.39 | 24.80 | 31.57 | 28.40 | 26.47 | 17.65 | 23.62 | 41.15 | 26.05 |\n", + "| QWERTY | 21.35 | 16.85 | 18.14 | 16.70 | 22.43 | 28.82 | 25.83 | 24.05 | 15.82 | 21.35 | 37.96 | 24.03 |\n", + "\n", + "---\n", + "\n", + "| Layout | Year | Website |\n", + "| --- | --- | --- |\n", + "| Engram | 2021 | https://engram.dev |\n", + "| [BEAKL 15](https://deskthority.net/wiki/BEAKL#BEAKL_15) | 2020 | https://deskthority.net/wiki/BEAKL#BEAKL_15 |\n", + "| [Halmak 2.2](https://keyboard-design.com/letterlayout.html?layout=halmak-2-2.en.ansi) | 2016 | https://github.com/MadRabbit/halmak |\n", + "| [Hieamtsrn](https://www.keyboard-design.com/letterlayout.html?layout=hieamtsrn.en.ansi) | 2014 | https://mathematicalmulticore.wordpress.com/the-keyboard-layout-project/#comment-4976 |\n", + "| [Colemak Mod-DH](https://keyboard-design.com/letterlayout.html?layout=colemak-mod-DH-full.en.ansi) | 2014 | https://colemakmods.github.io/mod-dh/ | \n", + "| [Norman](https://keyboard-design.com/letterlayout.html?layout=norman.en.ansi) | 2013 | https://normanlayout.info/ |\n", + "| [Workman](https://keyboard-design.com/letterlayout.html?layout=workman.en.ansi) | 2010 | https://workmanlayout.org/ | \n", + "| [MTGAP 2.0](https://www.keyboard-design.com/letterlayout.html?layout=mtgap-2-0.en.ansi) | 2010 | https://mathematicalmulticore.wordpress.com/2010/06/21/mtgaps-keyboard-layout-2-0/ |\n", + "| [QGMLWB](https://keyboard-design.com/letterlayout.html?layout=qgmlwb.en.ansi) | 2009 | http://mkweb.bcgsc.ca/carpalx/?full_optimization | \n", + "| [Colemak](https://keyboard-design.com/letterlayout.html?layout=colemak.en.ansi) | 2006 | https://colemak.com/ | \n", + "| [Asset](https://keyboard-design.com/letterlayout.html?layout=asset.en.ansi) | 2006 | http://millikeys.sourceforge.net/asset/ | \n", + "| Capewell-Dvorak | 2004 | http://michaelcapewell.com/projects/keyboard/layout_capewell-dvorak.htm |\n", + "| [Klausler](https://www.keyboard-design.com/letterlayout.html?layout=klausler.en.ansi) | 2002 | https://web.archive.org/web/20031001163722/http://klausler.com/evolved.html |\n", + "| [Dvorak](https://keyboard-design.com/letterlayout.html?layout=dvorak.en.ansi) | 1936 | https://en.wikipedia.org/wiki/Dvorak_keyboard_layout | \n", + "| [QWERTY](https://keyboard-design.com/letterlayout.html?layout=qwerty.en.ansi) | 1873 | https://en.wikipedia.org/wiki/QWERTY |\n", + "\n", + "---\n", + "\n", + "| Text source | Information |\n", + "| --- | --- |\n", + "| \"Alice in Wonderland\" | [KLA analysis](http://patorjk.com/keyboard-layout-analyzer/#/load/Z36pgChl) of Alice in Wonderland (Ch.1), a standard text used for comparing layouts |\n", + "| \"Romeo and Juliet\" | [KLA analysis](http://patorjk.com/keyboard-layout-analyzer/#/load/8lV58JvQ) of [Romeo and Juliet](https://www.fulltextarchive.com/page/Romeo-and-Juliet1/) |\n", + "| \"Bhagavad Gita\" | [KLA analysis](http://patorjk.com/keyboard-layout-analyzer/#/load/xj8xNS6K) of [Bhagavad Gita](https://www.gutenberg.org/files/2388/2388-h/2388-h.htm) |\n", + "| \"Memento screenplay\" | [KLA analysis](http://patorjk.com/keyboard-layout-analyzer/#/load/XRNbgCCK) of the screenplay for [Memento](https://www.dailyscript.com/scripts/memento.html) |\n", + "| \"100K tweets\" | 100,000 tweets from: [Sentiment140 dataset](https://data.world/data-society/twitter-user-data) training data |\n", + "| \"20K tweets\" | 20,000 tweets from [Gender Classifier Data](https://www.kaggle.com/crowdflower/twitter-user-gender-classification) |\n", + "| \"MASC tweets\" | [KLA analysis](http://patorjk.com/keyboard-layout-analyzer/#/load/rfxwCPVn) of [MASC](http://www.anc.org/data/masc/corpus/) tweets (cleaned of html markup) |\n", + "| \"MASC spoken\" | [KLA analysis](http://patorjk.com/keyboard-layout-analyzer/#/load/SgMB6n8v) of [MASC](http://www.anc.org/data/masc/corpus/) spoken transcripts (phone and face-to-face: 25,783 words) |\n", + "| \"COCA blogs\" | [KLA analysis](http://patorjk.com/keyboard-layout-analyzer/#/load/fv3Cj2zQ) of [Corpus of Contemporary American English](https://www.english-corpora.org/coca/) [blog samples](https://www.corpusdata.org/) |\n", + "| \"Google website\" | [KLA analysis](http://patorjk.com/keyboard-layout-analyzer/#/load/8dB6s1rL) of the [Google home page](https://google.com) (accessed 10/20/2020) |\n", + "| \"Software languages\" | [KLA analysis](http://patorjk.com/keyboard-layout-analyzer/#/load/97D3c58k) of the \"Tower of Hanoi\" (programming languages A-Z from [Rosetta Code](https://rosettacode.org/wiki/Towers_of_Hanoi)) |\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "wm3T-hmja8Ps" + }, + "source": [ + "## Guiding criteria \n", + "\n", + " 1. Assign letters to keys that don't require lateral finger movements.\n", + " 2. Promote alternating between hands over uncomfortable transitions with the same hand.\n", + " 3. Assign the most common letters to the most comfortable keys.\n", + " 4. Arrange letters so that more frequent bigrams are easier to type.\n", + " 5. Promote little-to-index-finger roll-ins over index-to-little-finger roll-outs.\n", + " 6. Balance finger loads according to their relative strength.\n", + " 7. Avoid stretching shorter fingers up and longer fingers down.\n", + " 8. Avoid using the same finger.\n", + " 9. Avoid the upper and lower rows.\n", + " 10. Avoid skipping over the home row.\n", + " 11. Assign the most common punctuation to keys in the middle of the keyboard.\n", + " 12. Assign easy-to-remember symbols to the Shift-number keys.\n", + " \n", + "### Factors used to compute the Engram layout \n", + " - **N-gram letter frequencies**
\n", + " \n", + " [Peter Norvig's analysis](http://www.norvig.com/mayzner.html) of data from Google's book scanning project\n", + " - **Flow factors** (transitions between ordered key pairs)
\n", + " These factors are influenced by Dvorak's 11 criteria (1936)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "_8C_BEaXa8Pu" + }, + "source": [ + "## Summary of steps and results
\n", + "\n", + "\n", + "### Step 1: Define the shape of the key layout to minimize lateral finger movements\n", + "\n", + "We will assign 24 letters to 8 columns of keys separated by two middle columns reserved for punctuation. These 8 columns require no lateral finger movements when touch typing, since there is one column per finger. The most comfortable keys include the left and right home rows (keys 5-8 and 17-20), the top-center keys (2,3 and 14,15) that allow the longer middle and ring fingers to uncurl upwards, as well as the bottom corner keys (9,12 and 21,24) that allow the shorter fingers to curl downwards. We will assign the two least frequent letters, Z and Q, to the two hardest-to-reach keys lying outside the 24-key columns in the upper right:\n", + "\n", + " Left: Right:\n", + " 1 2 3 4 13 14 15 16 Z/Q\n", + " 5 6 7 8 17 18 19 20 Q/Z\n", + " 9 10 11 12 21 22 23 24\n", + "\n", + "### Step 2: Arrange the most frequent letters based on comfort and bigram frequencies \n", + "\n", + "We will assign letters to keys by choosing the arrangement with the highest score according to our scoring model. However, there are over four hundred septillion, or four hundred trillion trillion (26! = 403,291,461,126,605,635,584,000,000, or 4.032914611 E+26) possible arrangements of 26 letters (24! = 6.204484017 E+23), so we will arrange the letters in stages, based on ergonomic principles.\n", + " \n", + "In prior experiments using the methods below, all vowels consistently automatically clustered together. Below, we will arrange vowels on one side and the most frequent consonants to the other side to encourage balance and alternation across hands. Since aside from the letters Z and Q there is symmetry across left and right sides, we will decide later which side the vowels and which side the most frequent consonants should go.\n", + "\n", + "#### Vowels\n", + " \n", + "**E**, T, **A, O, I**, N, S, R, H, L, D, C, **U**, M, F, P, G, W, **Y**, B, V, K, X, J, Q, Z\n", + "\n", + "The high-frequency bigrams that contain these vowels are listed below in bold, with more than 10 billion instances:\n", + "\n", + "**OU, IO, EA, IE**, AI, IA, EI, UE, UA, AU, UI, OI, EO, OA, OE \n", + " \n", + " OU 24531132241\n", + " IO 23542263265\n", + " EA 19403941063\n", + " IE 10845731320\n", + " AI 8922759715\n", + " IA 8072199471 \n", + " EI 5169898489\n", + " UE 4158448570 \n", + " UA 3844138094 \n", + " AU 3356322923\n", + " UI 2852182384\n", + " OI 2474275212\n", + " EO 2044268477\n", + " OA 1620913259\n", + " OE 1089254517 \n", + " \n", + "We will assign the vowels (E,A,O,I,U) to the most comfortable keys (keys 5-8, 2-3, 12) of one side, with the letter E, the most frequent in the English language, assigned to either of the strongest keys (7 and 8, the middle and index fingers on the left home row). We will arrange the vowels such that any top-frequency bigram (more than 1 billion instances in Peter Norvig's analysis of Google data) reads from left to right (ex: TH, not HT) for ease of typing (roll-in from little to index finger vs. roll-out from index to little finger). These constraints lead to comfortable and efficient layouts:\n", + " \n", + " (1) - O U -\n", + " I - E A \n", + "\n", + " (2) - - U - \n", + " I O E A \n", + "\n", + " (3) - - - - \n", + " I O E A\n", + " - - - U\n", + " \n", + " (4) - O - - \n", + " I - E A\n", + " - - - U \n", + "\n", + " (5) - - O - \n", + " I - E A\n", + " - - - U \n", + "\n", + " (6) - - O - \n", + " - I E A\n", + " - - - U \n", + " \n", + "#### Consonants\n", + "\n", + "Next, to populate the home row on the other side of the keyboard, we examine all possible sequences of four letters from the eight most frequent consonants (T,N,S,R,H,L,D,C), covering half the alphabet, where each letter has at least 100 billion (at least 3% of) instances in Peter Norvig's analysis:\n", + "\n", + "E, **T**, A, O, I, **N, S, R, H, L, D, C**, U, M, F, P, G, W, Y, B, V, K, X, J, Q, Z\n", + "\n", + "These eight consonants are included among the highest frequency bigrams, listed below in bold, with more than 10 billion instances:\n", + "\n", + "**TH, ND, ST, NT, CH, NS, CT, TR, RS, NC**, (RT), SH, LD, RD, LS, DS, LT, (TL), RL, HR, NL, (SL)\n", + " \n", + " TH 100272945963 3.56% \n", + " ND 38129777631 1.35%\n", + " ST 29704461829 1.05%\n", + " NT 29359771944 1.04%\n", + " CH 16854985236 0.60%\n", + " NS 14350320288 \n", + " CT 12997849406\n", + " TR 12006693396 \n", + " RS 11180732354 \n", + " NC 11722631112\n", + " RT 10198055461 \n", + "\n", + "To maximize the number of bigrams we can comfortably type, we select 4-consonant sequences that consist of three consecutive highest frequency (>10 billion instances) bigrams, such as NSTR = NS + ST + TR. We also restrict T to the strongest (middle or index) fingers, because T is the most frequent consonant. Below are the resulting 5 consonant sequences and number of left-to-right bigrams with at least 10 billion instances:\n", + "\n", + " N S T H (4)\n", + " N S T R (4)\n", + " N C T H (5)\n", + " N C T R (4)\n", + " N R S T (5)\n", + "\n", + "The resulting 6 arrangements of 5 vowels on the left and 5 arrangements of 4 consonants on the right gives us 30 layouts, each with 15 unassigned keys (letters on the right side are reversed, in case Hand 2 is assigned to the right hand):\n", + "\n", + " Hand 1 Hand 2\n", + " -OU- I-EA ---- ---- HTSN ----\n", + " -OU- I-EA ---- ---- RTSN ----\n", + " -OU- I-EA ---- ---- HTCN ----\n", + " -OU- I-EA ---- ---- RTCN ----\n", + " -OU- I-EA ---- ---- TSRN ----\n", + " --U- IOEA ---- ---- HTSN ----\n", + " --U- IOEA ---- ---- RTSN ----\n", + " --U- IOEA ---- ---- HTCN ----\n", + " --U- IOEA ---- ---- RTCN ----\n", + " --U- IOEA ---- ---- TSRN ----\n", + " ---- IOEA ---U ---- HTSN ----\n", + " ---- IOEA ---U ---- RTSN ----\n", + " ---- IOEA ---U ---- HTCN ----\n", + " ---- IOEA ---U ---- RTCN ----\n", + " ---- IOEA ---U ---- TSRN ----\n", + " -O-- I-EA ---U ---- HTSN ----\n", + " -O-- I-EA ---U ---- RTSN ----\n", + " -O-- I-EA ---U ---- HTCN ----\n", + " -O-- I-EA ---U ---- RTCN ----\n", + " -O-- I-EA ---U ---- TSRN ----\n", + " --O- I-EA ---U ---- HTSN ----\n", + " --O- I-EA ---U ---- RTSN ----\n", + " --O- I-EA ---U ---- HTCN ----\n", + " --O- I-EA ---U ---- RTCN ---- \n", + " --O- I-EA ---U ---- TSRN ----\n", + " --O- -IEA ---U ---- HTSN ----\n", + " --O- -IEA ---U ---- RTSN ----\n", + " --O- -IEA ---U ---- HTCN ----\n", + " --O- -IEA ---U ---- RTCN ----\n", + " --O- -IEA ---U ---- TSRN ----\n", + "\n", + "### Step 3: Optimize assignment of the remaining letters \n", + " \n", + "We want to assign the 15 missing letters to the unassigned keys in each of the above 30 layouts based on our scoring model. That would mean scoring all possible arrangements for each layout and choosing the arrangement with the highest score, but since there are over 1.3 trillion possible ways of arranging 15 letters (15! = 1,307,674,368,000), we will break up the assignment into two stages: first for the most frequent remaining letters, and second for the least frequent remaining letters. \n", + " \n", + "#### **Engram Scoring Model**\n", + " \n", + "The optimization algorithm finds every permutation of a given set of letters, maps these letter permutations to a set of keys, and ranks these letter-key mappings according to a score reflecting ease of typing key pairs and frequency of letter pairs (bigrams). The score is the average of the scores for all possible bigrams in this arrangement. The score for each bigram is a product of the frequency of occurrence of that bigram and Flow factors, where **Flow** is a measure of ease of a finger transition from the first in a pair of letters to the second.\n", + "\n", + "Flow factors to _penalize_ difficult key transitions include:\n", + " \n", + "- roll out from index to little finger\n", + "- index or little finger on top row\n", + "- middle or ring finger on bottom row\n", + "- index above middle, or little above ring \n", + "- index above ring, or little above middle\n", + "- ring above middle\n", + "- use same finger twice for a non-repeating letter\n", + "- at least one key not on home row\n", + "- one key on top row, the other on bottom row\n", + " \n", + "#### Most frequent letters\n", + "First we will compute scores for every possible arrangement of the 7 most frequent remaining letters among those in bold below for the most comfortable of the remaining positions (3,9,14,15,21,24, and either 2 or 6 or 12):\n", + "\n", + "E, T, A, O, I, N, **S, R, H, L, D, C**, U, **M, F, P**, G, W, Y, B, V, K, X, J, Q, Z\n", + "\n", + " Hand 1: Hand 2:\n", + " - 2 3 - - 14 15 -\n", + " x 6 x x x x x x\n", + " 9 - - 12 21 - - 24\n", + " \n", + "Since there are 7! = 5,040 possible combinations, and we have 30 layouts, we need to score and evaluate 151,200 combinations. \n", + " \n", + "To score each arrangement of letters, we construct a frequency matrix of each ordered pair of letters (bigram), and multiply this frequency matrix by our speed-strength-flow matrix to compute a score. \n", + "\n", + "#### Least frequent letters\n", + "Second, we will compute scores for every possible arrangement of the 8 least frequent letters (aside from Z and Q) in bold below for the least comfortable remaining positions (1,4,10,11, and 13,16,22,23), after substituting in the results above:\n", + "\n", + "E, T, A, O, I, N, S, R, H, L, D, C, U, M, F, P, **G, W, Y, B, V, K, X, J**, Q, Z\n", + "\n", + " Hand 1: Hand 2:\n", + " 1 - - 4 13 - - 16\n", + " - - - - - - - -\n", + " - 10 11 - - 22 23 - \n", + "\n", + "Since there are 8! = 40,320 possible combinations, and we have 30 layouts, we need to score and evaluate 1,209,600 combinations.\n", + "\n", + "#### Exchange letters among rows\n", + "\n", + "If we treat the resulting layouts as initializations as opposed to final layouts, and permit reassignment of letters, then we can search for even higher-scoring layouts. As a final step we will exchange letters among rows. \n", + " \n", + " 1-6. Exchange letters among non-home rows.\n", + " 1. Allow top and bottom rows to exchange letters on the left. \n", + " 2. Allow top and bottom rows to exchange letters on the right. \n", + " 3. Allow bottom rows to exchange letters.\n", + " 4. Allow top rows to exchange letters.\n", + " 5. Allow top left and bottom right rows to exchange letters. \n", + " 6. Allow top right and bottom left rows to exchange letters.\n", + " 7. Exchange letters in corners.\n", + " 8. Exchange letters in middle columns.\n", + " 9. Exchange letters in the home rows.\n", + " 10-19. Repeat 1-9. \n", + " \n", + "### Step 4: Stability Tests \n", + "\n", + "We will run three stability tests on the winning layouts:\n", + " \n", + " 1. Compare score of the winning layout after rearranging random letters \n", + " 2. Compare ranking of all final layouts based only on interkey speed\n", + " 3. Compare ranking of all final layouts after removing each scoring parameter\n", + "\n", + "The first test is to see if allowing random sets of letters to rearrange in every possible combination improves the score of the winning layout. We repeat this test 1,000 times, randomly selecting eight of the 24 letters, and another 1,000 times, randomly selecting eight of the 16 letters in the non-home rows, for a total of 80,640,000 additional layout tests. \n", + "\n", + "In the second test, we rescore all of the final layouts, replacing the flow matrix with the inter-key speed matrix to see if this affects their ranking. In the third test we remove each Engram scoring parameter one at a time and rescore all of the final layouts to see if this affects their ranking.\n", + "\n", + "For test 1, the top-scoring layout remains unchanged, attesting to its stability. For tests 2 and 3, the top-scored layout remains at the top, attesting to its efficiency with respect to speed and its robustness to parameter perturbations.\n", + "\n", + "We therefore corroborate the choice of the top-scoring layout as our Engram layout:\n", + "\n", + " Y P O X F C L B Q\n", + " H I E A T S R N Z\n", + " G K J U D V W M \n", + " \n", + "### Step 5. Arrange non-letter characters in easy-to-remember places\n", + "\n", + "Now that we have all 26 letters accounted for, we turn our attention to non-letter characters, taking into account frequency of punctuation and ease of recall.\n", + " \n", + "### Frequency of punctuation marks\n", + "\n", + " - Statistical values of punctuation frequency in 20 English-speaking countries (Table 1):
\n", + "Sun, Kun & Wang, Rong. (2018). Frequency Distributions of Punctuation Marks in English: Evidence from Large-scale Corpora. English Today. 10.1017/S0266078418000512.
\n", + "https://www.researchgate.net/publication/328512136_Frequency_Distributions_of_Punctuation_Marks_in_English_Evidence_from_Large-scale_Corpora\n", + "
\"frequency of punctuation marks attested for twenty English-speaking countries and regions... The data were acquired through GloWbE.\"\n", + " \"The corpus of GloWbE (2013) is a large English corpus collecting international English from the internet, containing about 1.9 billion words of text from twenty different countries. For further information on the corpora used, see https://corpus.byu.edu/.\"\n", + " \n", + " - Google N-grams and Twitter analysis:
\n", + "\"Punctuation Input on Touchscreen Keyboards: Analyzing Frequency of Use and Costs\"
\n", + "S Malik, L Findlater - College Park: The Human-Computer Interaction Lab. 2013
\n", + "https://www.cs.umd.edu/sites/default/files/scholarly_papers/Malik.pdf
\n", + " \"the Twitter corpora included substantially higher punctuation use than the Google corpus,
\n", + " comprising 7.5% of characters in the mobile tweets and 7.6% in desktop versus only 4.4%...
\n", + "With the Google corpus,only 6 punctuation symbols (. -’ ( ) “) appeared more frequently than [q]\"\n", + "\n", + " - \"Frequencies for English Punctuation Marks\" by Vivian Cook
\n", + "http://www.viviancook.uk/Punctuation/PunctFigs.htm
\n", + " \"Based on a writing system corpus some 459 thousand words long.
\n", + " This includes three novels of different types (276 thousand words),
\n", + " selections of articles from two newspapers (55 thousand),
\n", + "one bureaucratic report (94 thousand), and assorted academic papers
\n", + "on language topics (34 thousand). More information is in
\n", + "Cook, V.J. (2013) ‘Standard punctuation and the punctuation of the street’
\n", + "in M. Pawlak and L. Aronin (eds.), Essential Topics in Applied Linguistics and Multilingualism,
\n", + " Springer International Publishing Switzerland (2013), 267-290\"\n", + "\n", + " - \"A Statistical Study of Current Usage in Punctuation\":
\n", + "Ruhlen, H., & Pressey, S. (1924). A Statistical Study of Current Usage in Punctuation. The English Journal, 13(5), 325-331. doi:10.2307/802253\n", + "\n", + " - \"Computer Languages Character Frequency\"\n", + "by Xah Lee.
\n", + "Date: 2013-05-23. Last updated: 2020-06-29.
\n", + "http://xahlee.info/comp/computer_language_char_distribution.html
\n", + "NOTE: biased toward C (19.8%) and Py (18.5%), which have high use of \"_\".\n", + "\n", + "Frequency: \n", + "\n", + " Sun: Malik: Ruhlen: Cook: Xah:\n", + " /1M N-gram % /10,000 /1,000 All% JS% Py%\n", + "\n", + " . 42840.02 1.151 535 65.3 6.6 9.4 10.3\n", + " , 44189.96 556 61.6 5.8 8.9 7.5\n", + " \" 2.284 44 26.7 3.9 1.6 6.2\n", + " ' 2980.35 0.200 40 24.3 4.4 4.0 8.6\n", + " - 9529.78 0.217 21 15.3 4.1 1.9 3.0\n", + " () 4500.81 0.140 7 7.4 9.8 8.1\n", + " ; 1355.22 0.096 22 3.2 3.8 8.6\n", + " z 0.09 - -\n", + " : 3221.82 0.087 11 3.4 3.5 2.8 4.7\n", + " ? 4154.78 0.032 14 5.6 0.3\n", + " / 0.019 4.0 4.9 1.1\n", + " ! 2057.22 0.013 3 3.3 0.4\n", + " _ 0.001 11.0 2.9 10.5\n", + "\n", + "\n", + "### Add punctuation keys and number keys\n", + "\n", + "We will assign the most frequent punctuation according to Sun, et al (2018) to the six keys in the middle two columns: . , \" ' - ? ; : () ! _\n", + "\n", + " \n", + " Y P O X ' \" F C M W Q\n", + " H I E A , . T S N R Z\n", + " G K J U - ? D V B L\n", + "\n", + "We will use the Shift key to group similar punctuation marks (separating and joining marks in the left middle column and closing marks in the right middle column):\n", + "\n", + " { | = ~ + < > ^ & % * } \\\n", + " [ 1 2 3 4 5 6 7 8 9 0 ] /\n", + "\n", + " Y P O X '( \") F C M W Q #$ @\n", + " H I E A ,; .: T S N R Z\n", + " G K J U -_ ?! D V B L\n", + " \n", + "**Separating marks (left)**: The comma separates text in lists; the semicolon can be used in place of the comma to separate items in a list (especially if these items contain commas); open parenthesis sets off an explanatory word, phrase, or sentence. \n", + "\n", + "**Joining marks (left)**: The apostrophe joins words as contractions; the hyphen joins words as compounds; the underscore joins words in cases where whitespace characters are not permitted (such as in variables or file names). \n", + "\n", + "**Closing marks (right)**: A sentence usually ends with a period, question mark, or exclamation mark. The colon ends one statement but precedes the following: an explanation, quotation, list, etc. Double quotes and close parenthesis closes a word, clause, or sentence separated by an open parenthesis.\n", + "\n", + "**Number keys**: \n", + "The numbers are flanked to the left and right by [square brackets], and {curly brackets} accessed by the Shift key. Each of the numbers is paired with a mathematical or logic symbol accessed by the Shift key:\n", + " \n", + " { | = ~ + < > ^ & % * } \\\n", + " [ 1 2 3 4 5 6 7 8 9 0 ] /\n", + "\n", + " 1: | (vertical bar or \"pipe\" represents the logical OR operator: 1 stroke, looks like the number one)\n", + " 2: = (equal: 2 strokes, like the Chinese character for \"2\")\n", + " 3: ~ (tilde: \"almost equal\", often written with 3 strokes, like the Chinese character for \"3\")\n", + " 4: + (plus: has four quadrants; resembles \"4\")\n", + " 5 & 6: < > (\"less/greater than\"; these angle brackets are directly above the other bracket keys)\n", + " 7: ^ (caret for logical XOR operator as well as exponentiation; resembles \"7\")\n", + " 8: & (ampersand: logical AND operator; resembles \"8\")\n", + " 9: % (percent: related to division; resembles \"9\")\n", + " 0: * (asterisk: for multiplication; resembles \"0\") \n", + "\n", + "The three remaining keys in many common keyboards (flanking the upper right hand corner Backspace key) are displaced in special keyboards, such as the Kinesis Advantage and Ergodox. For the top right key, we will assign the forward slash and backslash: / \\\\. For the remaining two keys, we will assign two symbols that in modern usage have significance in social media: the hash/pound sign and the \"at sign\". The hash or hashtag identifies digital content on a specific topic (the Shift key accesses the dollar sign). The \"at sign\" identifies a location or affiliation (such as in email addresses) and acts as a \"handle\" to identify users in popular social media platforms and online forums.\n", + "\n", + "The resulting Engram layout:\n", + "\n", + " { | = ~ + < > ^ & % * } \\\n", + " [ 1 2 3 4 5 6 7 8 9 0 ] /\n", + "\n", + " Y P O X '( \") F C M W Q #$ @\n", + " H I E A ,; .: T S N R Z\n", + " G K J U -_ ?! D V B L\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "2eTQ4jxPa8Pv" + }, + "source": [ + "### Import dependencies and functions
" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 71 + }, + "colab_type": "code", + "id": "q1wNgX_FDzRH", + "outputId": "7c14cebc-a4b7-4a77-d14f-26cbc7690c28" + }, + "outputs": [], + "source": [ + "# Import dependencies\n", + "import xlrd\n", + "import numpy as np\n", + "from sympy.utilities.iterables import multiset_permutations\n", + "import matplotlib\n", + "import matplotlib.pyplot as plt \n", + "import seaborn as sns\n", + "\n", + "# Influence of strength data\n", + "apply_strength = False\n", + "strength_factor = 0.9 # Published finger strength data.\n", + "\n", + "# Influence of speed data\n", + "apply_speed = False\n", + "speed_factor = 0.9 # Published inter-key speed data.\n", + "\n", + "# Find all permutations of letters, optimize layout, and generate output:\n", + "def permute_optimize(letters, all_letters, all_keys, data_matrix, bigrams, bigram_frequencies, verbose=False, ntop=0):\n", + " matrix_selected = select_keys(data_matrix, all_keys, verbose=False)\n", + " move_positions = []\n", + " fixed_positions = [] \n", + " move_letters = []\n", + " fixed_letters = []\n", + " assigned_letters = []\n", + " for iletter, letter in enumerate(letters):\n", + " if letter.strip() == \"\":\n", + " move_positions.append(iletter)\n", + " for all_letter in all_letters:\n", + " if all_letter not in letters and all_letter not in assigned_letters:\n", + " move_letters.append(all_letter)\n", + " assigned_letters.append(all_letter)\n", + " break\n", + " else:\n", + " fixed_positions.append(iletter)\n", + " fixed_letters.append(letter)\n", + " #print(move_positions, fixed_positions, move_letters, fixed_letters)\n", + " letter_permutations = permute_letters(move_letters, verbose)\n", + " top_permutation, scores = optimize_layout(matrix_selected, bigrams, bigram_frequencies, letter_permutations, move_positions, fixed_letters, fixed_positions, verbose)\n", + " if ntop > 0:\n", + " print_top_scores(letter_permutations, scores, ntop)\n", + " \n", + " return top_permutation, letter_permutations, scores\n", + "\n", + "\n", + "# Select keys to quantify pairwise relationships:\n", + "def select_keys(data_matrix, keys, verbose=False):\n", + "\n", + " # Extract pairwise entries for the keys:\n", + " nkeys = len(keys)\n", + " Select = np.zeros((nkeys, nkeys))\n", + " u = 0\n", + " for i in keys:\n", + " u += 1\n", + " v = 0\n", + " for j in keys:\n", + " v += 1\n", + " Select[u-1,v-1] = data_matrix[i-1,j-1]\n", + "\n", + " # Normalize matrix with min-max scaling to a range with max 1:\n", + " newMin = np.min(Select) / np.max(Select)\n", + " newMax = 1.0\n", + " Select = newMin + (Select - np.min(Select)) * (newMax - newMin) / (np.max(Select) - np.min(Select))\n", + " \n", + " if verbose:\n", + " #print(\"Matrix:\")\n", + " #np.set_printoptions(precision=2); print(Select)\n", + "\n", + " # Heatmap of array\n", + " heatmap(data=Select, title=\"Matrix heatmap\", xlabel=\"Key 1\", ylabel=\"Key 2\"); plt.show()\n", + " \n", + " return Select\n", + "\n", + "\n", + "# Find all permutations of a given set of letters (max: 8-10 letters)\n", + "def permute_letters(letters, verbose=False):\n", + " letter_permutations = []\n", + " for p in multiset_permutations(letters):\n", + " letter_permutations.append(p)\n", + " letter_permutations = np.array(letter_permutations)\n", + " #if verbose:\n", + " # print(\"First permutation: {0}\".format(letter_permutations[0])) \n", + " \n", + " return letter_permutations\n", + "\n", + "\n", + "# Compute the score for a given letter-key layout (NOTE normalization step):\n", + "def score_layout(data_matrix, letters, bigrams, bigram_frequencies, verbose=False):\n", + "\n", + " # Create a matrix of bigram frequencies:\n", + " nletters = len(letters)\n", + " F = np.zeros((nletters, nletters))\n", + "\n", + " # Find the bigram frequency for each ordered pair of letters in the permutation:\n", + " for i1 in range(nletters):\n", + " for i2 in range(nletters):\n", + " bigram = letters[i1] + letters[i2]\n", + " i2gram = np.where(bigrams == bigram)\n", + " if np.size(i2gram) > 0:\n", + " F[i1, i2] = bigram_frequencies[i2gram][0]\n", + "\n", + " # Normalize matrix with min-max scaling to a range with max 1:\n", + " newMax = 1\n", + " newMin = np.min(F) / np.max(F)\n", + " F = newMin + (F - np.min(F)) * (newMax - newMin) / (np.max(F) - np.min(F))\n", + "\n", + " # Compute the score for this permutation:\n", + " score = np.average(data_matrix * F) \n", + "\n", + " if verbose:\n", + " print(\"Score for letter permutation {0}: {1}\".format(letters, score))\n", + "\n", + " return score\n", + "\n", + "\n", + "# Compute the score for a given letter-key layout (NOTE normalization step):\n", + "def tally_bigrams(input_text, bigrams, normalize=True, verbose=False):\n", + " \n", + " # Find the bigram frequency for each ordered pair of letters in the input text\n", + " #input_text = [str.upper(str(x)) for x in input_text]\n", + " input_text = [str.upper(x) for x in input_text]\n", + " nchars = len(input_text)\n", + " F = np.zeros(len(bigrams))\n", + "\n", + " for ichar in range(0, nchars-1):\n", + " bigram = input_text[ichar] + input_text[ichar + 1]\n", + " i2gram = np.where(bigrams == bigram)\n", + " if np.size(i2gram) > 0:\n", + " F[i2gram] += 1\n", + "\n", + " # Normalize matrix with min-max scaling to a range with max 1:\n", + " if normalize:\n", + " newMax = 1\n", + " newMin = np.min(F) / np.max(F)\n", + " F = newMin + (F - np.min(F)) * (newMax - newMin) / (np.max(F) - np.min(F))\n", + "\n", + " bigram_frequencies_for_input = F\n", + "\n", + " if verbose:\n", + " print(\"Bigram frequencies for input: {0}\".format(bigram_frequencies_for_input))\n", + "\n", + " return bigram_frequencies_for_input\n", + "\n", + "\n", + "# Compute scores for all letter-key layouts:\n", + "def optimize_layout(data_matrix, bigrams, bigram_frequencies, letter_permutations, move_positions, fixed_letters, fixed_positions=[], verbose=False):\n", + " iter = 0\n", + " top_score = 0\n", + " scores = []\n", + " use_score_function = False\n", + "\n", + " nletters = len(move_positions) + len(fixed_positions)\n", + " top_permutation = np.array(['E' for x in range(nletters)])\n", + " F = np.zeros((nletters, nletters))\n", + "\n", + " # Loop through the permutations of the selected letters:\n", + " for p in letter_permutations:\n", + " letters = np.array(['E' for x in range(nletters)]) # KEEP to initialize!\n", + " for imove, move_position in enumerate(move_positions):\n", + " letters[move_position] = p[imove]\n", + " for ifixed, fixed_position in enumerate(fixed_positions):\n", + " letters[fixed_position] = fixed_letters[ifixed]\n", + "\n", + " # Compute the score for this permutation:\n", + " if use_score_function:\n", + " score = score_layout(data_matrix, letters, bigrams, bigram_frequencies, verbose=False)\n", + " else:\n", + " # Find the bigram frequency for each ordered pair of letters in the permutation:\n", + " for i1 in range(nletters):\n", + " for i2 in range(nletters):\n", + " bigram = letters[i1] + letters[i2]\n", + " i2gram = np.where(bigrams == bigram)\n", + " # Put bigram frequency in matrix of bigram frequencies:\n", + " if np.size(i2gram) > 0:\n", + " F[i1, i2] = bigram_frequencies[i2gram][0]\n", + " else:\n", + " F[i1, i2] = 0\n", + " \n", + " # Normalize matrix with min-max scaling to a range with max 1:\n", + " minF = np.min(F)\n", + " maxF = np.max(F)\n", + " newMin = minF / maxF\n", + " F = newMin + (F - minF) * (1 - newMin) / (maxF - minF)\n", + "\n", + " # Compute the score for this permutation:\n", + " score = np.average(data_matrix * F) \n", + "\n", + " # Store all scores and the top score and permutation:\n", + " scores.append(score)\n", + " if score > top_score:\n", + " top_score = score\n", + " top_permutation = letters\n", + " \n", + " if verbose:\n", + " iter += 1\n", + " if iter % len(letter_permutations)/10 == 0:\n", + " print(\"{0}: {1} {2:0.5f}\".format(iter, top_permutation, top_score))\n", + " #imax = np.argmax(scores)\n", + " #print(scores[imax], letter_permutations[imax])\n", + " \n", + " print(\"Topmost of {0} permutations: {1}\".format(len(letter_permutations), top_score))\n", + " print(\"{0}\".format(top_permutation))\n", + " \n", + " return top_permutation, scores\n", + "\n", + "\n", + "# Print top-scored letter permutations:\n", + "def print_top_scores(letter_permutations, scores, ntop):\n", + " scores_negative = -np.array(scores)\n", + " isort = np.argsort(scores_negative)[:ntop]\n", + " sorted_scores = [scores[isort[x]] for x in range(len(isort))]\n", + " sorted_letter_permutations = [letter_permutations[isort[x]].tolist() for x in range(len(isort))]\n", + " for ix, x in enumerate(sorted_letter_permutations):\n", + " print(x, sorted_scores[ix])\n", + " \n", + " \n", + "# Print matrix output:\n", + "def print_matrix_info(matrix_data, matrix_label, nkeys, nlines=10):\n", + " print(\"{0} min = {1}, max = {2}\".format(matrix_label, np.min(matrix_data), np.max(matrix_data)))\n", + " matrix_flat = matrix_data.flatten()\n", + " argsort = np.argsort(matrix_flat)\n", + " print(\"{0} key number pairs with minimum values:\".format(matrix_label))\n", + " for x in argsort[0:nlines]:\n", + " if x % nkeys == 0:\n", + " min_row = np.int(np.ceil(x / nkeys)) + 1\n", + " min_col = 1\n", + " else:\n", + " min_row = np.int(np.ceil(x / nkeys))\n", + " min_col = x - nkeys * (min_row-1) + 1 \n", + " print(\" {0} -> {1} ({2})\".format(min_row, min_col, matrix_flat[x]))\n", + " print(\"{0} key number pairs with maximum values:\".format(matrix_label))\n", + " max_sort = argsort[-nlines::]\n", + " for x in max_sort[::-1]:\n", + " if x % nkeys == 0:\n", + " max_row = np.int(np.ceil(x / nkeys)) + 1\n", + " max_col = 1\n", + " else:\n", + " max_row = np.int(np.ceil(x / nkeys))\n", + " max_col = x - nkeys * (max_row-1) + 1 \n", + " print(\" {0} -> {1} ({2})\".format(max_row, max_col, matrix_flat[x]))\n", + "\n", + "\n", + "# Plot heatmap of matrix:\n", + "def heatmap(data, title=\"\", xlabel=\"\", ylabel=\"\"):\n", + " # use heatmap function, set the color as viridis and\n", + " # make each cell seperate using linewidth parameter\n", + " sns_plot = sns.heatmap(data, linewidths=1, cmap=\"viridis\", square=True, vmin=np.min(data), vmax=np.max(data))\n", + " plt.title(title)\n", + " plt.xlabel(xlabel)\n", + " plt.ylabel(ylabel)\n", + " sns_plot.figure.savefig(\"{0}_heatmap.png\".format(title))\n", + " \n", + " \n", + "# Plot histogram:\n", + "def histmap(data, title=\"\"):\n", + " sns.distplot(data)\n", + " plt.title(title)\n", + " sns_plot.figure.savefig(\"{0}_histogram.png\".format(title))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "rFiySi8rDzRN" + }, + "source": [ + "### Bigram frequencies \n", + "\n", + "[Peter Norvig's ngrams table](http://www.norvig.com/mayzner.html](http://www.norvig.com/mayzner.html)\n", + " \n", + "[NOTE: If you want to compute an optimized layout for another language, or based on another corpus, you can run the tally_bigrams() function above and replace bigram_frequencies below before running the rest of the code.]" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": {}, + "colab_type": "code", + "id": "K68F0fkqDzRO" + }, + "outputs": [], + "source": [ + "load_original_ngram_files = False\n", + "if load_original_ngram_files:\n", + " ngrams_table = \"data/bigrams-trigrams-frequencies.xlsx\"\n", + " wb = xlrd.open_workbook(ngrams_table) \n", + " ngrams_sheet = wb.sheet_by_index(0)\n", + " # 1-grams and frequencies\n", + " onegrams = np.array(())\n", + " onegram_frequencies = np.array(())\n", + " i = 0\n", + " start1 = 0\n", + " stop1 = 0\n", + " while stop1 == 0:\n", + " if ngrams_sheet.cell_value(i, 0) == \"2-gram\":\n", + " stop1 = 1\n", + " elif ngrams_sheet.cell_value(i, 0) == \"1-gram\":\n", + " start1 = 1\n", + " elif start1 == 1:\n", + " onegrams = np.append(onegrams, ngrams_sheet.cell_value(i, 0))\n", + " onegram_frequencies = np.append(onegram_frequencies, ngrams_sheet.cell_value(i, 1))\n", + " i += 1\n", + " onegram_frequencies = onegram_frequencies / np.sum(onegram_frequencies)\n", + "\n", + " # 2-grams and frequencies\n", + " bigrams = np.array(())\n", + " bigram_frequencies = np.array(())\n", + " i = 0\n", + " start1 = 0\n", + " stop1 = 0\n", + " while stop1 == 0:\n", + " if ngrams_sheet.cell_value(i, 0) == \"3-gram\":\n", + " stop1 = 1\n", + " elif ngrams_sheet.cell_value(i, 0) == \"2-gram\":\n", + " start1 = 1\n", + " elif start1 == 1:\n", + " bigrams = np.append(bigrams, ngrams_sheet.cell_value(i, 0))\n", + " bigram_frequencies = np.append(bigram_frequencies, ngrams_sheet.cell_value(i, 1))\n", + " i += 1\n", + " bigram_frequencies = bigram_frequencies / np.sum(bigram_frequencies)\n", + "\n", + " # Save:\n", + " file = open(\"onegrams.txt\", \"w+\")\n", + " file.write(str(onegrams))\n", + " file.close()\n", + " file = open(\"onegram_frequencies.txt\", \"w+\")\n", + " file.write(str(onegram_frequencies))\n", + " file.close()\n", + " file = open(\"bigrams.txt\", \"w+\")\n", + " file.write(str(bigrams))\n", + " file.close()\n", + " file = open(\"bigram_frequencies.txt\", \"w+\")\n", + " file.write(str(bigram_frequencies))\n", + " file.close()\n", + "\n", + " # Print:\n", + " print(repr(onegrams))\n", + " print(repr(onegram_frequencies))\n", + " print(repr(bigrams))\n", + " print(repr(bigram_frequencies))\n", + "\n", + "else:\n", + " onegrams = np.array(['E', 'T', 'A', 'O', 'I', 'N', 'S', 'R', 'H', 'L', 'D', 'C', 'U',\n", + " 'M', 'F', 'P', 'G', 'W', 'Y', 'B', 'V', 'K', 'X', 'J', 'Q', 'Z'],\n", + " dtype='\n", + "### 24x24 relative Speed matrix between key pair (averaged for left/right symmetry)\n", + "\n", + " - does not take into account order of key pairs (see Flow24x24 matrix)\n", + " - the original version was constructed with data from right-handed people\n", + " - 24 keys that don't require extending index or little fingers (\"vertical range keys\")\n", + "\n", + "### Vertical range keys\n", + "\n", + " Left: Right:\n", + " 1 2 3 4 13 14 15 16 \n", + " 5 6 7 8 17 18 19 20\n", + " 9 10 11 12 21 22 23 24\n", + "\n", + "Interkey stroke times in milliseconds from Table 3 of
\n", + "\"Estimation of digraph costs for keyboard layout optimization\",
\n", + "A Iseri, Ma Eksioglu, International Journal of Industrial Ergonomics, 48, 127-138, 2015.
\n", + "Key numbering in article and in spreadsheet:\n", + "\n", + " Left: Right:\n", + " 1 4 7 10 13 16 19 22 25 28 31\n", + " 2 5 8 11 14 17 20 23 26 29 32\n", + " 3 6 9 12 15 18 21 24 27 30\n", + " \n", + "### Load table of interkey speeds" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": {}, + "colab_type": "code", + "id": "095yG4iPDzRT" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Speed24x24 min = 0.9, max = 1.0\n", + "Speed24x24 key number pairs with minimum values:\n", + " 10 -> 1 (0.9)\n", + " 16 -> 23 (0.9)\n", + " 1 -> 10 (0.9)\n", + " 23 -> 16 (0.9)\n", + " 1 -> 9 (0.920935412026726)\n", + " 16 -> 24 (0.920935412026726)\n", + " 9 -> 1 (0.920935412026726)\n", + " 24 -> 16 (0.920935412026726)\n", + " 20 -> 23 (0.9282850779510022)\n", + " 23 -> 20 (0.9282850779510022)\n", + " 10 -> 5 (0.9282850779510022)\n", + " 5 -> 10 (0.9282850779510022)\n", + " 15 -> 23 (0.9338530066815145)\n", + " 23 -> 15 (0.9338530066815145)\n", + " 10 -> 2 (0.9338530066815145)\n", + " 2 -> 10 (0.9338530066815145)\n", + " 11 -> 1 (0.9347438752783964)\n", + " 22 -> 16 (0.9347438752783964)\n", + " 16 -> 22 (0.9347438752783964)\n", + " 1 -> 11 (0.9347438752783964)\n", + " 9 -> 2 (0.9385300668151447)\n", + " 15 -> 24 (0.9385300668151447)\n", + " 2 -> 9 (0.9385300668151447)\n", + " 24 -> 15 (0.9385300668151447)\n", + " 19 -> 16 (0.9396436525612473)\n", + " 1 -> 6 (0.9396436525612473)\n", + " 16 -> 19 (0.9396436525612473)\n", + " 6 -> 1 (0.9396436525612473)\n", + " 20 -> 24 (0.9414253897550111)\n", + " 10 -> 9 (0.9414253897550111)\n", + " 24 -> 23 (0.9414253897550111)\n", + " 5 -> 9 (0.9414253897550111)\n", + " 23 -> 24 (0.9414253897550111)\n", + " 9 -> 10 (0.9414253897550111)\n", + " 9 -> 5 (0.9414253897550111)\n", + " 24 -> 20 (0.9414253897550111)\n", + " 5 -> 1 (0.9418708240534521)\n", + " 20 -> 16 (0.9418708240534521)\n", + " 16 -> 20 (0.9418708240534521)\n", + " 1 -> 5 (0.9418708240534521)\n", + " 3 -> 11 (0.9438752783964365)\n", + " 14 -> 22 (0.9438752783964365)\n", + " 22 -> 14 (0.9438752783964365)\n", + " 11 -> 3 (0.9438752783964365)\n", + " 6 -> 5 (0.9461024498886415)\n", + " 6 -> 9 (0.9461024498886415)\n", + " 19 -> 24 (0.9461024498886415)\n", + " 20 -> 19 (0.9461024498886415)\n", + " 19 -> 20 (0.9461024498886415)\n", + " 24 -> 19 (0.9461024498886415)\n", + "Speed24x24 key number pairs with maximum values:\n", + " 17 -> 8 (1.0)\n", + " 8 -> 17 (1.0)\n", + " 17 -> 7 (0.9997772828507795)\n", + " 18 -> 8 (0.9997772828507795)\n", + " 7 -> 17 (0.9997772828507795)\n", + " 8 -> 18 (0.9997772828507795)\n", + " 7 -> 18 (0.999554565701559)\n", + " 18 -> 7 (0.999554565701559)\n", + " 17 -> 6 (0.998218262806236)\n", + " 7 -> 19 (0.998218262806236)\n", + " 18 -> 6 (0.998218262806236)\n", + " 19 -> 8 (0.998218262806236)\n", + " 6 -> 18 (0.998218262806236)\n", + " 19 -> 7 (0.998218262806236)\n", + " 6 -> 17 (0.998218262806236)\n", + " 8 -> 19 (0.998218262806236)\n", + " 6 -> 19 (0.9968819599109131)\n", + " 19 -> 6 (0.9968819599109131)\n", + " 17 -> 5 (0.9962138084632517)\n", + " 5 -> 17 (0.9962138084632517)\n", + " 20 -> 8 (0.9962138084632517)\n", + " 8 -> 20 (0.9962138084632517)\n", + " 5 -> 18 (0.9959910913140312)\n", + " 7 -> 20 (0.9959910913140312)\n", + " 20 -> 7 (0.9959910913140312)\n", + " 18 -> 5 (0.9959910913140312)\n", + " 6 -> 20 (0.9944320712694877)\n", + " 19 -> 5 (0.9944320712694877)\n", + " 5 -> 19 (0.9944320712694877)\n", + " 20 -> 6 (0.9944320712694877)\n", + " 20 -> 5 (0.9919821826280624)\n", + " 8 -> 13 (0.9919821826280624)\n", + " 21 -> 8 (0.9919821826280624)\n", + " 21 -> 7 (0.9919821826280624)\n", + " 18 -> 12 (0.9919821826280624)\n", + " 17 -> 12 (0.9919821826280624)\n", + " 8 -> 21 (0.9919821826280624)\n", + " 7 -> 21 (0.9919821826280624)\n", + " 13 -> 8 (0.9919821826280624)\n", + " 17 -> 4 (0.9919821826280624)\n", + " 5 -> 20 (0.9919821826280624)\n", + " 12 -> 17 (0.9919821826280624)\n", + " 12 -> 18 (0.9919821826280624)\n", + " 4 -> 17 (0.9919821826280624)\n", + " 4 -> 18 (0.9917594654788419)\n", + " 18 -> 4 (0.9917594654788419)\n", + " 13 -> 7 (0.9917594654788419)\n", + " 7 -> 13 (0.9917594654788419)\n", + " 21 -> 6 (0.9906458797327394)\n", + " 19 -> 12 (0.9906458797327394)\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "load_original_interkey_timings_table = False\n", + "if load_original_interkey_timings_table:\n", + "\n", + " interkey_table = \"data/interkey-timings.xlsx\"\n", + " wb = xlrd.open_workbook(interkey_table) \n", + " interkey_sheet = wb.sheet_by_index(0)\n", + "\n", + " # Convert interkey stroke times table to array:\n", + " Time32x32 = np.zeros((32,32))\n", + " for i in range(1,33):\n", + " for j in range(1,33):\n", + " if interkey_sheet.cell_value(i,j):\n", + " Time32x32[i-1,j-1] = interkey_sheet.cell_value(i,j)\n", + "\n", + " # Fill empty (symmetric) portion of the array:\n", + " for i in range(1,33):\n", + " for j in range(1,33):\n", + " if interkey_sheet.cell_value(i,j):\n", + " Time32x32[j-1,i-1] = interkey_sheet.cell_value(i,j)\n", + "\n", + " # Extract pairwise entries for the 24 vertical range keys:\n", + " table_24_positions = [1,4,7,10, 2,5,8,11, 3,6,9,12, 19,22,25,28, 20,23,26,29, 21,24,27,30]\n", + " Time24x24 = np.zeros((24, 24))\n", + " u = 0\n", + " for i in table_24_positions:\n", + " u += 1\n", + " v = 0\n", + " for j in table_24_positions:\n", + " v += 1\n", + " Time24x24[u-1,v-1] = Time32x32[i-1,j-1]\n", + "\n", + " # Save:\n", + " file = open(\"Time24x24.txt\", \"w+\")\n", + " file.write(str(Time24x24))\n", + " file.close()\n", + "\n", + " # Print:\n", + " print(repr(Time24x24))\n", + "\n", + "else:\n", + " Time24x24 = np.array([[196., 225., 204., 164., 266., 258., 231., 166., 357., 325., 263.,\n", + " 186., 169., 176., 178., 186., 156., 156., 158., 163., 171., 175., 177., 185.],\n", + " [225., 181., 182., 147., 239., 245., 196., 150., 289., 296., 229.,\n", + " 167., 162., 169., 170., 178., 148., 148., 150., 155., 163., 167., 169., 177.],\n", + " [204., 182., 170., 149., 196., 194., 232., 155., 237., 214., 263.,\n", + " 166., 157., 164., 165., 173., 143., 143., 145., 150., 158., 163., 164., 172.],\n", + " [164., 147., 149., 169., 160., 161., 157., 226., 165., 185., 234.,\n", + " 257., 154., 162., 163., 171., 141., 141., 143., 148., 156., 160., 162., 170.],\n", + " [266., 239., 196., 160., 196., 240., 208., 166., 271., 267., 208.,\n", + " 169., 143., 150., 151., 160., 129., 129., 132., 137., 145., 149., 151., 159.],\n", + " [258., 245., 194., 161., 240., 181., 183., 149., 245., 256., 184.,\n", + " 150., 138., 145., 146., 154., 124., 124., 126., 131., 139., 144., 145., 153.],\n", + " [231., 196., 232., 157., 208., 183., 170., 149., 201., 215., 239.,\n", + " 151., 134., 141., 142., 150., 120., 120., 122., 127., 135., 140., 141., 149.],\n", + " [166., 150., 155., 226., 166., 149., 149., 169., 160., 147., 170.,\n", + " 221., 133., 140., 141., 150., 119., 119., 122., 126., 135., 139., 141., 149.],\n", + " [357., 289., 237., 165., 271., 245., 201., 160., 196., 236., 194.,\n", + " 161., 171., 178., 179., 188., 157., 157., 160., 164., 173., 177., 179., 187.],\n", + " [325., 296., 214., 185., 267., 256., 215., 147., 236., 181., 184.,\n", + " 157., 166., 173., 174., 182., 152., 152., 154., 159., 167., 172., 173., 181.],\n", + " [263., 229., 263., 234., 208., 184., 239., 170., 194., 184., 170.,\n", + " 150., 159., 166., 167., 176., 145., 145., 148., 153., 161., 165., 167., 175.],\n", + " [186., 167., 166., 257., 169., 150., 151., 221., 161., 157., 150.,\n", + " 169., 153., 160., 161., 169., 139., 139., 141., 146., 154., 159., 160., 168.],\n", + " [169., 162., 157., 154., 143., 138., 134., 133., 171., 166., 159.,\n", + " 153., 151., 147., 141., 145., 188., 151., 142., 164., 213., 204., 162., 145.],\n", + " [176., 169., 164., 162., 150., 145., 141., 140., 178., 173., 166.,\n", + " 160., 147., 151., 189., 209., 137., 207., 191., 206., 149., 227., 208., 226.],\n", + " [178., 170., 165., 163., 151., 146., 142., 141., 179., 174., 167.,\n", + " 161., 141., 189., 157., 253., 136., 188., 210., 231., 155., 226., 239., 225.],\n", + " [186., 178., 173., 171., 160., 154., 150., 150., 188., 182., 176.,\n", + " 169., 145., 209., 253., 170., 147., 206., 251., 233., 164., 268., 362., 236.],\n", + " [156., 148., 143., 141., 129., 124., 120., 119., 157., 152., 145.,\n", + " 139., 188., 137., 136., 147., 151., 133., 138., 152., 192., 149., 139., 143.],\n", + " [156., 148., 143., 141., 129., 124., 120., 119., 157., 152., 145.,\n", + " 139., 151., 207., 188., 206., 133., 151., 179., 183., 145., 204., 183., 194.],\n", + " [158., 150., 145., 143., 132., 126., 122., 122., 160., 154., 148.,\n", + " 141., 142., 191., 210., 251., 138., 179., 157., 240., 145., 185., 208., 235.],\n", + " [163., 155., 150., 148., 137., 131., 127., 126., 164., 159., 153.,\n", + " 146., 164., 206., 231., 233., 152., 183., 240., 170., 160., 220., 293., 230.],\n", + " [171., 163., 158., 156., 145., 139., 135., 135., 173., 167., 161.,\n", + " 154., 213., 149., 155., 164., 192., 145., 145., 160., 151., 140., 142., 175.],\n", + " [175., 167., 163., 160., 149., 144., 140., 139., 177., 172., 165.,\n", + " 159., 204., 227., 226., 268., 149., 204., 185., 220., 140., 151., 175., 265.],\n", + " [177., 169., 164., 162., 151., 145., 141., 141., 179., 173., 167.,\n", + " 160., 162., 208., 239., 362., 139., 183., 208., 293., 142., 175., 157., 265.],\n", + " [185., 177., 172., 170., 159., 153., 149., 149., 187., 181., 175.,\n", + " 168., 145., 226., 225., 236., 143., 194., 235., 230., 175., 265., 265., 170.]])\n", + "\n", + "# Left/right symmetric version of the Time24x24 matrix\n", + "# (The original version was constructed with data from right-handed people.)\n", + "TimeSymmetric24x24 = np.ones((24,24))\n", + "\n", + "# Left: Right:\n", + "# 1 2 3 4 13 14 15 16 \n", + "# 5 6 7 8 17 18 19 20\n", + "# 9 10 11 12 21 22 23 24\n", + "\n", + "I = [1,2,3,4, 5,6,7,8, 9,10,11,12, 16,15,14,13, 20,19,18,17, 24,23,22,21]\n", + "J = [16,15,14,13, 20,19,18,17, 24,23,22,21, 1,2,3,4, 5,6,7,8, 9,10,11,12]\n", + "\n", + "for i1, I1 in enumerate(I):\n", + " for i2, I2 in enumerate(I):\n", + " J1 = J[i1] - 1\n", + " J2 = J[i2] - 1\n", + " #print(i1,i2,I1-1,I2-1,J1,J2)\n", + " avgvalue = (Time24x24[I1-1,I2-1] + Time24x24[J1,J2]) / 2 \n", + " TimeSymmetric24x24[I1-1,I2-1] = avgvalue\n", + " TimeSymmetric24x24[J1,J2] = avgvalue\n", + "\n", + "# Normalize matrix with min-max scaling to a range with maximum = 1:\n", + "newMin = speed_factor # np.min(TimeSymmetric24x24) / np.max(TimeSymmetric24x24)\n", + "newMax = 1.0\n", + "TimeSymmetric24x24 = newMin + (TimeSymmetric24x24 - np.min(TimeSymmetric24x24)) * (newMax - newMin) / (np.max(TimeSymmetric24x24) - np.min(TimeSymmetric24x24))\n", + "\n", + "# Convert relative interkey stroke times to relative speeds by subtracting from 1:\n", + "Speed24x24 = 1 - TimeSymmetric24x24 + np.min(TimeSymmetric24x24)\n", + "\n", + "# Print:\n", + "print_matrix_info(matrix_data=Speed24x24, matrix_label=\"Speed24x24\", nkeys=24, nlines=50)\n", + "heatmap(data=Speed24x24, title=\"Speed24x24\", xlabel=\"Key 1\", ylabel=\"Key 2\")\n", + "\n", + "# Print:\n", + "#print(repr(Speed24x24))\n", + "\n", + "# Save:\n", + "file = open(\"Speed24x24.txt\", \"w+\")\n", + "file.write(str(Speed24x24))\n", + "file.close()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "colab": {}, + "colab_type": "code", + "id": "TK3mj_z1DzRZ" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/arno.klein/anaconda3/lib/python3.8/site-packages/seaborn/distributions.py:2551: FutureWarning: `distplot` is a deprecated function and will be removed in a future version. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms).\n", + " warnings.warn(msg, FutureWarning)\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Histogram\n", + "#if apply_speed:\n", + "sns_plot = sns.distplot(Speed24x24)\n", + "sns_plot.figure.savefig(\"{0}_histogram.png\".format(\"Speed24x24\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "raw", + "id": "NtZcIyqSDzRf" + }, + "source": [ + "Output:\n", + "\n", + " Left: Right:\n", + " 1 2 3 4 13 14 15 16 \n", + " 5 6 7 8 17 18 19 20\n", + " 9 10 11 12 21 22 23 24\n", + "\n", + " Speed24x24 min = 0.0, max = 1.0\n", + " Speed24x24 key number pairs with minimum values:\n", + " 10 -> 1 (0.0)\n", + " 16 -> 23 (0.0)\n", + " 1 -> 10 (0.0)\n", + " 23 -> 16 (0.0)\n", + " 1 -> 9 (0.20935412026726052)\n", + " 16 -> 24 (0.20935412026726052)\n", + " 9 -> 1 (0.20935412026726052)\n", + " 24 -> 16 (0.20935412026726052)\n", + " 20 -> 23 (0.28285077951002224)\n", + " 23 -> 20 (0.28285077951002224)\n", + " 10 -> 5 (0.28285077951002224)\n", + " 5 -> 10 (0.28285077951002224)\n", + " 15 -> 23 (0.33853006681514475)\n", + " 23 -> 15 (0.33853006681514475)\n", + " 10 -> 2 (0.33853006681514475)\n", + " 2 -> 10 (0.33853006681514475)\n", + " 11 -> 1 (0.3474387527839644)\n", + " 22 -> 16 (0.3474387527839644)\n", + " 16 -> 22 (0.3474387527839644)\n", + " 1 -> 11 (0.3474387527839644)\n", + " 9 -> 2 (0.3853006681514477)\n", + " 15 -> 24 (0.3853006681514477)\n", + " 2 -> 9 (0.3853006681514477)\n", + " 24 -> 15 (0.3853006681514477)\n", + " 19 -> 16 (0.3964365256124721)\n", + " 1 -> 6 (0.3964365256124721)\n", + " 16 -> 19 (0.3964365256124721)\n", + " 6 -> 1 (0.3964365256124721)\n", + " 20 -> 24 (0.4142538975501113)\n", + " 10 -> 9 (0.4142538975501113)\n", + " 24 -> 23 (0.4142538975501113)\n", + " 5 -> 9 (0.4142538975501113)\n", + " 23 -> 24 (0.4142538975501113)\n", + " 9 -> 10 (0.4142538975501113)\n", + " 9 -> 5 (0.4142538975501113)\n", + " 24 -> 20 (0.4142538975501113)\n", + " 5 -> 1 (0.41870824053452116)\n", + " 20 -> 16 (0.41870824053452116)\n", + " 16 -> 20 (0.41870824053452116)\n", + " 1 -> 5 (0.41870824053452116)\n", + " 3 -> 11 (0.43875278396436523)\n", + " 14 -> 22 (0.43875278396436523)\n", + " 22 -> 14 (0.43875278396436523)\n", + " 11 -> 3 (0.43875278396436523)\n", + " 6 -> 5 (0.4610244988864143)\n", + " 6 -> 9 (0.4610244988864143)\n", + " 19 -> 24 (0.4610244988864143)\n", + " 20 -> 19 (0.4610244988864143)\n", + " 19 -> 20 (0.4610244988864143)\n", + " 24 -> 19 (0.4610244988864143)\n", + " Speed24x24 key number pairs with maximum values:\n", + " 17 -> 8 (1.0)\n", + " 8 -> 17 (1.0)\n", + " 17 -> 7 (0.9977728285077951)\n", + " 18 -> 8 (0.9977728285077951)\n", + " 7 -> 17 (0.9977728285077951)\n", + " 8 -> 18 (0.9977728285077951)\n", + " 7 -> 18 (0.9955456570155902)\n", + " 18 -> 7 (0.9955456570155902)\n", + " 17 -> 6 (0.9821826280623608)\n", + " 7 -> 19 (0.9821826280623608)\n", + " 18 -> 6 (0.9821826280623608)\n", + " 19 -> 8 (0.9821826280623608)\n", + " 6 -> 18 (0.9821826280623608)\n", + " 19 -> 7 (0.9821826280623608)\n", + " 6 -> 17 (0.9821826280623608)\n", + " 8 -> 19 (0.9821826280623608)\n", + " 6 -> 19 (0.9688195991091314)\n", + " 19 -> 6 (0.9688195991091314)\n", + " 17 -> 5 (0.9621380846325167)\n", + " 5 -> 17 (0.9621380846325167)\n", + " 20 -> 8 (0.9621380846325167)\n", + " 8 -> 20 (0.9621380846325167)\n", + " 5 -> 18 (0.9599109131403119)\n", + " 7 -> 20 (0.9599109131403119)\n", + " 20 -> 7 (0.9599109131403119)\n", + " 18 -> 5 (0.9599109131403119)\n", + " 6 -> 20 (0.9443207126948775)\n", + " 19 -> 5 (0.9443207126948775)\n", + " 5 -> 19 (0.9443207126948775)\n", + " 20 -> 6 (0.9443207126948775)\n", + " 20 -> 5 (0.9198218262806236)\n", + " 8 -> 13 (0.9198218262806236)\n", + " 21 -> 8 (0.9198218262806236)\n", + " 21 -> 7 (0.9198218262806236)\n", + " 18 -> 12 (0.9198218262806236)\n", + " 17 -> 12 (0.9198218262806236)\n", + " 8 -> 21 (0.9198218262806236)\n", + " 7 -> 21 (0.9198218262806236)\n", + " 13 -> 8 (0.9198218262806236)\n", + " 17 -> 4 (0.9198218262806236)\n", + " 5 -> 20 (0.9198218262806236)\n", + " 12 -> 17 (0.9198218262806236)\n", + " 12 -> 18 (0.9198218262806236)\n", + " 4 -> 17 (0.9198218262806236)\n", + " 4 -> 18 (0.9175946547884187)\n", + " 18 -> 4 (0.9175946547884187)\n", + " 13 -> 7 (0.9175946547884187)\n", + " 7 -> 13 (0.9175946547884187)\n", + " 21 -> 6 (0.9064587973273942)\n", + " 19 -> 12 (0.9064587973273942)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "tFfuA8zMDzRg" + }, + "source": [ + "## Strength matrix \n", + "\n", + "### 24x24 relative finger position STRENGTH matrix\n", + "\n", + "Finger strengths are based on peak keyboard reaction forces (in newtons) from Table 4 of
\n", + "\"Keyboard Reaction Force and Finger Flexor Electromyograms during Computer Keyboard Work\"
\n", + "BJ Martin, TJ Armstrong, JA Foulke, S Natarajan, Human Factors,1996,38(4),654-664:\n", + " \n", + " middle 2.36\n", + " index 2.26\n", + " ring 2.02\n", + " little 1.84\n", + " \n", + " 2.36/1.84 = 1.28\n", + " 2.36/2.02 = 1.17\n", + "\n", + "For reference, Table 1 of \"Ergonomic keyboard layout designed for the Filipino language\", 2016 (doi: 10.1007/978-3-319-41694-6_41) presents \"average finger strength of Filipinos [n=30, ages 16-36] measured in pounds\":\n", + " \n", + " L R\n", + " little 3.77 4.27\n", + " ring 4.54 5.08\n", + " middle 5.65 6.37\n", + " index 6.09 6.57\n", + " \n", + " 6.57/4.27 = 1.54\n", + " 6.09/3.77 = 1.62\n", + " 6.37/5.08 = 1.25\n", + " 5.65/4.54 = 1.24\n", + " \n", + "We won't use these results as I don't feel they represent relative strength relevant for typing: \"Respondents were asked to sit in upright position, with their wrists resting on a flat surface. A pinch gauge was placed within each finger's reach. The respondents were asked to exert maximum pressure on the device.\"\n", + " \n", + "The following does not take into account order of key pairs (see Flow matrix).\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "if apply_strength:\n", + "\n", + " # Normalize by the highest peak force (middle finger):\n", + " middle_force = 2.36\n", + " index_force = 2.26\n", + " ring_force = 2.02\n", + " little_force = 1.84\n", + " middle_norm = 1.0\n", + " index_norm = index_force / middle_force\n", + " ring_norm = ring_force / middle_force\n", + " little_norm = little_force / middle_force\n", + "\n", + " # Relative left/right hand strength (assume equal):\n", + " lf = 1.0\n", + " rf = 1.0\n", + " \n", + " strengths24 = np.array((lf * little_norm, lf * ring_norm, lf * middle_norm, lf * index_norm,\n", + " lf * little_norm, lf * ring_norm, lf * middle_norm, lf * index_norm,\n", + " lf * little_norm, lf * ring_norm, lf * middle_norm, lf * index_norm,\n", + " rf * index_norm, rf * middle_norm, rf * ring_norm, rf * little_norm,\n", + " rf * index_norm, rf * middle_norm, rf * ring_norm, rf * little_norm,\n", + " rf * index_norm, rf * middle_norm, rf * ring_norm, rf * little_norm))\n", + "\n", + " # Create a finger-pair position strength matrix by adding pairs of strength values:\n", + " Strength24x24 = np.zeros((24, 24))\n", + " for i in range(24):\n", + " Strength24x24[i,:] = strengths24\n", + " Strength24x24 = (Strength24x24 + Strength24x24.transpose())\n", + "\n", + " # Normalize matrix with min-max scaling to a range with maximum = 1:\n", + " newMin = strength_factor # np.min(Strength24x24) / np.max(Strength24x24)\n", + " newMax = 1.0\n", + " Strength24x24 = newMin + (Strength24x24 - np.min(Strength24x24)) * (newMax - newMin) / (np.max(Strength24x24) - np.min(Strength24x24))\n", + "\n", + " # Print:\n", + " print_matrix_info(matrix_data=Strength24x24, matrix_label=\"Strength24x24\", nkeys=24, nlines=10)\n", + " heatmap(data=Strength24x24, title=\"Strength24x24\", xlabel=\"Key 1\", ylabel=\"Key 2\")\n", + "\n", + " # Save:\n", + " file = open(\"Strength24x24.txt\", \"w+\")\n", + " file.write(str(Strength24x24))\n", + " file.close()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 265 + }, + "colab_type": "code", + "id": "qz7jPlfBDzRo", + "outputId": "d9e44ba2-d677-4b88-fe9c-306a2cb85a27" + }, + "outputs": [], + "source": [ + "if apply_strength:\n", + "\n", + " # Histogram\n", + " sns_plot = sns.distplot(Strength24x24)\n", + " sns_plot.figure.savefig(\"{0}_histogram.png\".format(\"Strength24x24\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "if apply_strength:\n", + "\n", + " penalty = 1.0 # Penalty for lateral (index, little) finger placement (1 = no penalty)\n", + "\n", + " strengths32 = np.array((lf * little_norm, lf * ring_norm, lf * middle_norm, lf * index_norm,\n", + " lf * little_norm, lf * ring_norm, lf * middle_norm, lf * index_norm,\n", + " lf * little_norm, lf * ring_norm, lf * middle_norm, lf * index_norm,\n", + " rf * index_norm, rf * middle_norm, rf * ring_norm, rf * little_norm,\n", + " rf * index_norm, rf * middle_norm, rf * ring_norm, rf * little_norm,\n", + " rf * index_norm, rf * middle_norm, rf * ring_norm, rf * little_norm,\n", + " lf * index_norm * penalty, lf * index_norm * penalty, lf * index_norm * penalty,\n", + " rf * index_norm * penalty, rf * index_norm * penalty, rf * index_norm * penalty,\n", + " rf * little_norm * penalty, rf * little_norm * penalty))\n", + "\n", + " # Create a finger-pair position strength matrix by adding pairs of strength values:\n", + " Strength32x32 = np.zeros((32, 32))\n", + " for i in range(32):\n", + " Strength32x32[i,:] = strengths32\n", + " Strength32x32 = (Strength32x32 + Strength32x32.transpose())\n", + "\n", + " # Normalize matrix with min-max scaling to a range with maximum = 1:\n", + " newMin = strength_factor # np.min(Strength32x32) / np.max(Strength32x32)\n", + " newMax = 1.0\n", + " Strength32x32 = newMin + (Strength32x32 - np.min(Strength32x32)) * (newMax - newMin) / (np.max(Strength32x32) - np.min(Strength32x32))\n", + "\n", + " # Print:\n", + " print_matrix_info(matrix_data=Strength32x32, matrix_label=\"Strength32x32\", nkeys=32, nlines=10)\n", + " heatmap(data=Strength32x32, title=\"Strength32x32\", xlabel=\"Key 1\", ylabel=\"Key 2\")\n", + "\n", + " # Save:\n", + " file = open(\"Strength32x32.txt\", \"w+\")\n", + " file.write(str(Strength32x32))\n", + " file.close()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "if apply_strength:\n", + "\n", + " # Histogram\n", + " sns_plot = sns.distplot(Strength32x32)\n", + " sns_plot.figure.savefig(\"{0}_histogram.png\".format(\"Strength32x32\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "raw", + "id": "0kL0XyVFDzRx" + }, + "source": [ + "### Strength output\n", + "\n", + " Left: Right:\n", + " 1 2 3 4 13 14 15 16 \n", + " 5 6 7 8 17 18 19 20\n", + " 9 10 11 12 21 22 23 24\n", + "\n", + "Strength24x24 min = 0.9, max = 1.0\n", + "Strength24x24 key number pairs with minimum values:\n", + "\n", + " 1 -> 1 (0.9)\n", + " 5 -> 9 (0.9)\n", + " 5 -> 16 (0.9)\n", + " 5 -> 20 (0.9)\n", + " 5 -> 24 (0.9)\n", + " 9 -> 1 (0.9)\n", + " 9 -> 5 (0.9)\n", + " 9 -> 9 (0.9)\n", + " 9 -> 16 (0.9)\n", + " 9 -> 20 (0.9)\n", + "\n", + "Strength24x24 key number pairs with maximum values:\n", + "\n", + " 18 -> 11 (1.0)\n", + " 22 -> 14 (1.0)\n", + " 3 -> 14 (1.0)\n", + " 7 -> 18 (1.0)\n", + " 18 -> 7 (1.0)\n", + " 18 -> 14 (1.0)\n", + " 3 -> 18 (1.0)\n", + " 18 -> 18 (1.0)\n", + " 22 -> 22 (1.0)\n", + " 18 -> 22 (1.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "Dnn5-8S5DzRy" + }, + "source": [ + "## Flow matrix
\n", + "\n", + "The Flow24x24 matrix takes into account ease of transition between ordered pairs of keys\n", + "\n", + "#### Dvorak et al. (1936) defined eleven criteria for the design and evaluation of keyboard layouts:\n", + "1. Deviation from the balance of hand and finger loads should be as low as possible.\n", + "2. Percentage of tapping with the same fingers should be as low as possible.\n", + "3. Percentage of tapping that includes top row should be as low as possible.\n", + "4. Percentage of tapping that includes bottom row should be as low as possible.\n", + "5. Percentage of tapping in the home row should be as high as possible.\n", + "6. Percentage of tapping by alternating hands should be as high as possible.\n", + "7. Percentage of hurdles with the same finger should be as low as possible.\n", + "8. Percentage of hurdles with adjacent fingers should be as low as possible.\n", + "9. Percentage of hurdles with remote fingers should be as low as possible.\n", + "10. Percentage of reach with the same finger should be as low as possible.\n", + "11. Percentage of reach with adjacent fingers should be as low as possible.\n", + "\n", + "#### Synopsis of above criteria for pairwise key presses when touch typing:\n", + "1. Alternate between hands.\n", + "2. Balance finger loads, and avoid using the same finger.\n", + "3. Avoid the upper and lower rows, and avoid skipping over the home row.\n", + "4. Avoid tapping adjacent rows with the same or adjacent fingers.\n", + "\n", + "#### The approach here advocates the following related criteria:\n", + "1. Assign letters to keys that don't require lateral finger movements.\n", + "2. **Promote alternating between hands over uncomfortable transitions with the same hand.**\n", + "3. Assign the most common letters to the most comfortable keys.\n", + "4. Arrange letters so that more frequent bigrams are easier to type.\n", + "5. Promote little-to-index-finger roll-ins over index-to-little-finger roll-outs.\n", + "6. Balance finger loads according to their relative strength.\n", + "7. Avoid stretching shorter fingers up and longer fingers down.\n", + "8. **Avoid using the same finger.**\n", + "9. **Avoid the upper and lower rows.**\n", + "10. **Avoid skipping over the home row.**\n", + "11. Assign the most common punctuation to keys in the middle of the keyboard.\n", + "12. Assign easy-to-remember symbols to the Shift-number keys.\n", + " \n", + "### Factors to penalize difficult key transitions\n", + "\n", + "Difficult key positions:\n", + " \n", + " - side_top: shorter (index or little) finger on top row\n", + " - center_bottom: longer (middle or ring) finger on bottom row\n", + "\n", + "Difficult key transitions:\n", + " \n", + " - roll_out: roll out from index to little finger (or other similarly outward directed pair)\n", + " - same_finger: use same finger twice for a non-repeating letter\n", + " - side_up_1away_down: rindex above middle finger, or little above ring finger\n", + " - side_up_2away_down: index above ring finger, or little above middle finger\n", + " - ring_up_middle_down: ring above middle finger\n", + " - not_home_row: at least one key not on home row\n", + " - skip_home_row: one key on top row, the other on bottom row\n", + "\n", + "Examples:\n", + "\n", + " Left: Right:\n", + " 1 2 3 4 13 14 15 16 \n", + " 5 6 7 8 17 18 19 20\n", + " 9 10 11 12 21 22 23 24\n", + "\n", + " key 10 to key 1: same_hand * roll_out * not_home_row * skip_home_row * side_top \n", + " * side_up_1away_down * center_bottom = 0.9^6 = 0.531441\n", + " \n", + " key 9 to key 1: same_hand * same_finger * not_home_row * skip_home_row \n", + " * side_top = 0.81 * 0.9^3 = 0.59049\n", + "\n", + " key 2 to key 7: same_hand * not_home_row * ring_up_middle_down = 0.9^2 = 0.81\n", + " \n", + " key 2 to key 6: same_hand * same_finger * not_home_row = 0.81 * 0.9 = 0.729\n", + "\n", + " key 12 to key 2: same_hand * roll_out * not_home_row * skip_home_row = 0.9^3 = 0.729\n", + "\n", + " key 12 to key 1: same_hand * roll_out * not_home_row * skip_home_row \n", + " * side_top = 0.9^4 = 0.6561\n", + " \n", + " key 11 to key 2: same_hand * roll_out * not_home_row * skip_home_row \n", + " * center_bottom * ring_up_middle_down = 0.9^5 = 0.59049\n", + "\n", + " key 10 to key 2: same_hand * same_finger * not_home_row * skip_home_row \n", + " * center_bottom = 0.81 * 0.9^3 = 0.59049\n", + "\n", + " key 9 to key 1: same_hand * same_finger * not_home_row * skip_home_row \n", + " * side_top = 0.81 * 0.9^3 = 0.59049" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "# Penalizing factors for 24 keys (1 = no penalty; set to less than 1 to penalize):\n", + "same_hand = 1.0 # Taken care of by splitting up the most frequent letters across left/right sides above\n", + "same_finger = 0.81 # use same finger twice for a non-repeating letter (worse than 2 fingers)\n", + "roll_out = 0.9 # roll out from index to little finger\n", + "not_home_row = 0.9 # at least one key not on home row\n", + "skip_home_row = 0.9 # one key on top row, the other on bottom row\n", + "side_top = 0.9 # either index or little finger on top row\n", + "side_up_1away_down = 0.9 # index above middle, or little above ring \n", + "side_up_2away_down = 0.9 # index above ring, or little above middle\n", + "side_up_3away_down = 1.0 # index above little, or little above index -- assumed to be negligible\n", + "center_bottom = 0.9 # either middle or ring finger on bottom row\n", + "ring_up_middle_down = 0.9 # ring above middle\n", + "\n", + "# Penalizing factor for 32 keys:\n", + "lateral = 0.9 # lateral movement of (index or little) finger outside of 8 vertical columns\n", + "\n", + "# Left: Right:\n", + "# 1 2 3 4 25 28 13 14 15 16 31 \n", + "# 5 6 7 8 26 29 17 18 19 20 32\n", + "# 9 10 11 12 27 30 21 22 23 24" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 24 keys:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 695 + }, + "colab_type": "code", + "id": "qx1eL9whDzSE", + "outputId": "8b9eff1d-450c-4ca3-bd6c-5d67591dcac0" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Flow24x24 min = 0.5314410000000002, max = 1.0\n", + "Flow24x24 key number pairs with minimum values:\n", + " 13 -> 23 (0.5314410000000002)\n", + " 10 -> 1 (0.5314410000000002)\n", + " 13 -> 22 (0.5314410000000002)\n", + " 23 -> 16 (0.5314410000000002)\n", + " 4 -> 11 (0.5314410000000002)\n", + " 4 -> 10 (0.5314410000000002)\n", + " 22 -> 16 (0.5314410000000002)\n", + " 11 -> 1 (0.5314410000000002)\n", + " 2 -> 10 (0.5904900000000002)\n", + " 4 -> 12 (0.5904900000000002)\n", + "Flow24x24 key number pairs with maximum values:\n", + " 5 -> 18 (1.0)\n", + " 20 -> 18 (1.0)\n", + " 5 -> 17 (1.0)\n", + " 5 -> 19 (1.0)\n", + " 5 -> 20 (1.0)\n", + " 19 -> 17 (1.0)\n", + " 19 -> 18 (1.0)\n", + " 19 -> 19 (1.0)\n", + " 6 -> 6 (1.0)\n", + " 6 -> 7 (1.0)\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "def create_24x24_flow_matrix(same_hand, same_finger, roll_out, not_home_row, skip_home_row, side_top, side_up_1away_down, side_up_2away_down, side_up_3away_down, center_bottom, ring_up_middle_down):\n", + "\n", + " all_24_keys = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16, 17,18,19,20, 21,22,23,24]\n", + "\n", + " # Create a matrix and multiply by flow factors that promote easy interkey transitions:\n", + " T = np.ones((24, 24))\n", + "\n", + " # 7. Promote alternating between hands over uncomfortable transitions with the same hand.\n", + " if same_hand < 1.0:\n", + " for i in range(0,12):\n", + " for j in range(0,12):\n", + " T[i,j] *= same_hand\n", + " for i in range(12,24):\n", + " for j in range(12,24):\n", + " T[i,j] *= same_hand\n", + "\n", + " # 8. Promote little-to-index-finger roll-ins over index-to-little-finger roll_outs.\n", + " if roll_out < 1.0:\n", + "\n", + " # same-row roll-outs:\n", + " roll_ins = [[1,2],[2,3],[3,4], [5,6],[6,7],[7,8], [9,10],[10,11],[11,12],\n", + " [16,15],[15,14],[14,13], [20,19],[19,18],[18,17], [24,23],[23,22],[22,21]]\n", + " for x in roll_ins:\n", + " T[x[1]-1, x[0]-1] *= roll_out\n", + "\n", + " # same-row roll-outs, skipping keys:\n", + " roll_ins_skip_keys = [[1,3],[2,4],[1,4], [5,7],[6,8],[5,8], [9,11],[10,12],[9,12],\n", + " [16,14],[15,13],[16,13], [20,18],[19,17],[20,17], [24,22],[23,21],[24,21]]\n", + " for x in roll_ins_skip_keys:\n", + " T[x[1]-1, x[0]-1] *= roll_out\n", + "\n", + " # adjacent-row roll-outs:\n", + " roll_ins_adj_rows = [[1,6],[1,7],[1,8],[2,7],[2,8],[3,8], [5,2],[5,3],[5,4],[6,3],[6,4],[7,4],\n", + " [5,10],[5,11],[5,12],[6,11],[6,12],[7,12], [9,6],[9,7],[9,8],[10,7],[10,8],[11,8],\n", + " [16,19],[16,18],[16,17],[15,18],[15,17],[14,17], [20,15],[20,14],[20,13],[19,14],[19,13],[18,13],\n", + " [20,23],[20,22],[20,21],[19,22],[19,21],[18,21], [24,19],[24,18],[24,17],[23,18],[23,17],[22,17]]\n", + " for x in roll_ins_adj_rows:\n", + " T[x[1]-1, x[0]-1] *= roll_out\n", + "\n", + " # upper<->lower row roll-outs:\n", + " roll_ins_skip_home = [[1,10],[1,11],[1,12],[2,11],[2,12],[3,12], [9,2],[9,3],[9,4],[10,3],[10,4],[11,4],\n", + " [16,23],[16,22],[16,21],[15,22],[15,21],[14,21], [24,15],[24,14],[24,13],[23,14],[23,13],[22,13]]\n", + " for x in roll_ins_skip_home:\n", + " T[x[1]-1, x[0]-1] *= roll_out\n", + "\n", + " # 9. Avoid stretching shorter fingers up and longer fingers down.\n", + " if side_top:\n", + " for x in all_24_keys:\n", + " for y in [1,4,13,16]:\n", + " T[x-1, y-1] *= side_top\n", + " T[y-1, x-1] *= side_top\n", + " if center_bottom:\n", + " for x in all_24_keys:\n", + " for y in [10,11,22,23]:\n", + " T[x-1, y-1] *= center_bottom\n", + " T[y-1, x-1] *= center_bottom\n", + "\n", + " if side_up_1away_down < 1.0 or side_up_2away_down < 1.0 or side_up_3away_down < 1.0 or ring_up_middle_down < 1.0:\n", + " side_up_1away_downs = [[1,6], [1,10], [5,10], [7,4], [11,4], [11,8], \n", + " [16,19],[16,23],[20,23], [18,13],[22,13],[22,17]]\n", + " side_up_2away_downs = [[1,7], [1,11], [5,11], [6,4], [10,4], [10,8], \n", + " [16,18],[16,22],[20,22], [19,13],[23,13],[23,17]]\n", + " side_up_3away_downs = [[1,8], [1,12], [5,12], [5,4], [9,4], [9,8], \n", + " [16,17],[16,21],[20,21], [20,13],[24,13],[24,17]]\n", + " ring_up_middle_downs = [[2,7],[6,11],[2,11], [15,18],[19,22],[15,22]]\n", + " if side_up_1away_down < 1.0:\n", + " for x in side_up_1away_downs:\n", + " T[x[0]-1, x[1]-1] *= side_up_1away_down\n", + " T[x[1]-1, x[0]-1] *= side_up_1away_down\n", + " if side_up_2away_down < 1.0:\n", + " for x in side_up_2away_downs:\n", + " T[x[0]-1, x[1]-1] *= side_up_2away_down\n", + " T[x[1]-1, x[0]-1] *= side_up_2away_down\n", + " if side_up_3away_down < 1.0:\n", + " for x in side_up_3away_downs:\n", + " T[x[0]-1, x[1]-1] *= side_up_3away_down\n", + " T[x[1]-1, x[0]-1] *= side_up_3away_down\n", + " if ring_up_middle_down < 1.0:\n", + " for x in ring_up_middle_downs:\n", + " T[x[0]-1, x[1]-1] *= ring_up_middle_down\n", + " T[x[1]-1, x[0]-1] *= ring_up_middle_down\n", + "\n", + " # 10. Avoid using the same finger.\n", + " if same_finger < 1.0:\n", + " same_fingers = [[1,5],[5,9],[1,9], [2,6],[6,10],[2,10], [3,7],[7,11],[3,11], [4,8],[8,12],[4,12],\n", + " [13,17],[17,21],[13,21], [14,18],[18,22],[14,22], [15,19],[19,23],[15,23], [16,20],[20,24],[16,24]] \n", + " for x in same_fingers:\n", + " T[x[0]-1, x[1]-1] *= same_finger\n", + " T[x[1]-1, x[0]-1] *= same_finger\n", + "\n", + " # 11. Avoid the upper and lower rows.\n", + " if not_home_row < 1.0:\n", + " not_home_row_keys = [1,2,3,4, 9,10,11,12, 13,14,15,16, 21,22,23,24]\n", + " home_row_keys = [5,6,7,8, 17,18,19,20]\n", + " for x in not_home_row_keys:\n", + " for y in not_home_row_keys:\n", + " T[x-1, y-1] *= not_home_row\n", + " for x in not_home_row_keys:\n", + " for y in home_row_keys:\n", + " T[x-1, y-1] *= not_home_row\n", + " T[y-1, x-1] *= not_home_row\n", + "\n", + " # 12. Avoid skipping over the home row.\n", + " if skip_home_row < 1.0:\n", + " skip_home_rows_left = [[1,2,3,4], [9,10,11,12]] \n", + " skip_home_rows_right = [[13,14,15,16], [21,22,23,24]] \n", + " for x in skip_home_rows_left[0]:\n", + " for y in skip_home_rows_left[1]:\n", + " T[x-1, y-1] *= skip_home_row\n", + " T[y-1, x-1] *= skip_home_row\n", + " for x in skip_home_rows_right[0]:\n", + " for y in skip_home_rows_right[1]:\n", + " T[x-1, y-1] *= skip_home_row\n", + " T[y-1, x-1] *= skip_home_row\n", + "\n", + " Flow24x24 = T\n", + "\n", + " # Normalize matrix with min-max scaling to a range with maximum = 1:\n", + " newMin = np.min(Flow24x24) / np.max(Flow24x24)\n", + " newMax = 1.0\n", + " Flow24x24 = newMin + (Flow24x24 - np.min(Flow24x24)) * (newMax - newMin) / (np.max(Flow24x24) - np.min(Flow24x24))\n", + "\n", + " return Flow24x24\n", + "\n", + "Flow24x24 = create_24x24_flow_matrix(same_hand, same_finger, roll_out, not_home_row, skip_home_row, side_top, side_up_1away_down, side_up_2away_down, side_up_3away_down, center_bottom, ring_up_middle_down)\n", + "\n", + "# Print:\n", + "print_matrix_info(matrix_data=Flow24x24, matrix_label=\"Flow24x24\", nkeys=24, nlines=10)\n", + "heatmap(data=Flow24x24, title=\"Flow24x24\", xlabel=\"Key 1\", ylabel=\"Key 2\")\n", + "\n", + "# Save:\n", + "file = open(\"Flow24x24.txt\", \"w+\")\n", + "file.write(str(Flow24x24))\n", + "file.close()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 265 + }, + "colab_type": "code", + "id": "F6wZ4iRLDzSM", + "outputId": "147c2189-b464-4202-fd34-0e8a5665291f" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/arno.klein/anaconda3/lib/python3.8/site-packages/seaborn/distributions.py:2551: FutureWarning: `distplot` is a deprecated function and will be removed in a future version. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms).\n", + " warnings.warn(msg, FutureWarning)\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Histogram\n", + "sns_plot = sns.distplot(Flow24x24)\n", + "sns_plot.figure.savefig(\"{0}_histogram.png\".format(\"Flow24x24\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 32 keys:\n", + "\n", + " Left: Right:\n", + " 1 2 3 4 25 28 13 14 15 16 31 \n", + " 5 6 7 8 26 29 17 18 19 20 32\n", + " 9 10 11 12 27 30 21 22 23 24\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 695 + }, + "colab_type": "code", + "id": "qx1eL9whDzSE", + "outputId": "8b9eff1d-450c-4ca3-bd6c-5d67591dcac0" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Flow32x32 min = 0.43046721000000016, max = 1.0\n", + "Flow32x32 key number pairs with minimum values:\n", + " 25 -> 12 (0.43046721000000016)\n", + " 28 -> 21 (0.43046721000000016)\n", + " 24 -> 31 (0.43046721000000016)\n", + " 12 -> 25 (0.4782969000000001)\n", + " 27 -> 25 (0.4782969000000001)\n", + " 21 -> 28 (0.4782969000000001)\n", + " 25 -> 27 (0.4782969000000001)\n", + " 30 -> 28 (0.4782969000000001)\n", + " 28 -> 30 (0.4782969000000001)\n", + " 31 -> 24 (0.4782969000000001)\n", + "Flow32x32 key number pairs with maximum values:\n", + " 7 -> 18 (1.0)\n", + " 17 -> 6 (1.0)\n", + " 6 -> 19 (1.0)\n", + " 6 -> 20 (1.0)\n", + " 19 -> 5 (1.0)\n", + " 19 -> 6 (1.0)\n", + " 19 -> 7 (1.0)\n", + " 19 -> 8 (1.0)\n", + " 19 -> 17 (1.0)\n", + " 19 -> 18 (1.0)\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "def create_32x32_flow_matrix(same_hand, same_finger, roll_out, not_home_row, skip_home_row, side_top, side_up_1away_down, side_up_2away_down, side_up_3away_down, center_bottom, ring_up_middle_down):\n", + "\n", + " all_32_keys = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16, 17,18,19,20, 21,22,23,24, \n", + " 25,26,27, 28,29,30, 31,32]\n", + "\n", + " # Create a matrix and multiply by flow factors that promote easy interkey transitions:\n", + " T = np.ones((32, 32))\n", + "\n", + " # Penalize (index, little) finger lateral movements:\n", + " if lateral < 1.0:\n", + " for x in all_32_keys:\n", + " for y in [25,26,27,28,29,30,31,32]:\n", + " T[x-1, y-1] *= lateral\n", + " T[y-1, x-1] *= lateral \n", + "\n", + " # 7. Promote alternating between hands over uncomfortable transitions with the same hand.\n", + " if same_hand < 1.0:\n", + " for i in [1,2,3,4,5,6,7,8,9,10,11,12, 25,26,27]:\n", + " for j in [1,2,3,4,5,6,7,8,9,10,11,12, 25,26,27]:\n", + " T[i-1,j-1] *= same_hand\n", + " for i in [13,14,15,16,17,18,19,20,21,22,23,24, 28,29,30,31,32]:\n", + " for j in [13,14,15,16,17,18,19,20,21,22,23,24, 28,29,30,31,32]:\n", + " T[i-1,j-1] *= same_hand\n", + "\n", + " # 8. Promote little-to-index-finger roll-ins over index-to-little-finger roll_outs.\n", + " if roll_out < 1.0:\n", + "\n", + " # same-row roll-outs:\n", + " roll_ins = [[1,2],[2,3],[3,4], [5,6],[6,7],[7,8], [9,10],[10,11],[11,12],\n", + " [4,25],[8,26],[12,27],\n", + " [16,15],[15,14],[14,13], [20,19],[19,18],[18,17], [24,23],[23,22],[22,21],\n", + " [13,28],[17,29],[21,30],[31,16],[32,20]]\n", + " for x in roll_ins:\n", + " T[x[1]-1, x[0]-1] *= roll_out\n", + "\n", + " # same-row roll-outs, skipping keys:\n", + " roll_ins_skip_keys = [[1,3],[2,4],[1,4], [5,7],[6,8],[5,8], [9,11],[10,12],[9,12],\n", + " [1,25],[2,25],[3,25],\n", + " [5,26],[6,26],[7,26],\n", + " [9,27],[10,27],[11,27],\n", + " [9,30],[10,30],[11,30],[12,30],\n", + " [16,14],[15,13],[16,13], [20,18],[19,17],[20,17], [24,22],[23,21],[24,21],\n", + " [16,28],[15,28],[14,28],\n", + " [20,29],[19,29],[18,29],\n", + " [24,30],[23,30],[22,30],\n", + " [31,15],[31,14],[31,13],[31,28],\n", + " [32,19],[32,18],[32,17],[32,29]]\n", + " for x in roll_ins_skip_keys:\n", + " T[x[1]-1, x[0]-1] *= roll_out\n", + "\n", + " # adjacent-row roll-outs:\n", + " roll_ins_adj_rows = [[1,6],[1,7],[1,8],[2,7],[2,8],[3,8], [5,2],[5,3],[5,4],[6,3],[6,4],[7,4],\n", + " [5,10],[5,11],[5,12],[6,11],[6,12],[7,12], [9,6],[9,7],[9,8],[10,7],[10,8],[11,8],\n", + " [5,25],[6,25],[7,25],[8,25],[5,27],[6,27],[7,27],[8,27],\n", + " [1,26],[2,26],[3,26],[4,26],[9,26],[10,26],[11,26],[12,26],\n", + " [16,19],[16,18],[16,17],[15,18],[15,17],[14,17], [20,15],[20,14],[20,13],[19,14],[19,13],[18,13],\n", + " [20,23],[20,22],[20,21],[19,22],[19,21],[18,21], [24,19],[24,18],[24,17],[23,18],[23,17],[22,17],\n", + " [16,29],[15,29],[14,29],[13,29],[24,29],[23,29],[22,29],[21,29],\n", + " [20,28],[19,28],[18,28],[17,28],[20,30],[19,30],[18,30],[17,30],\n", + " [31,20],[31,19],[31,18],[31,17],[31,29],[32,16],[32,15],[32,14],[32,13],[32,28],\n", + " [32,24],[32,23],[32,22],[32,21],[32,30]]\n", + " for x in roll_ins_adj_rows:\n", + " T[x[1]-1, x[0]-1] *= roll_out\n", + "\n", + " # Left: Right:\n", + " # 1 2 3 4 25 28 13 14 15 16 31 \n", + " # 5 6 7 8 26 29 17 18 19 20 32\n", + " # 9 10 11 12 27 30 21 22 23 24\n", + "\n", + " # upper<->lower row roll-outs:\n", + " roll_ins_skip_home = [[1,10],[1,11],[1,12],[1,27],[2,11],[2,12],[2,27],[3,12],[3,27],[4,27], \n", + " [9,2],[9,3],[9,4],[9,25],[10,3],[10,4],[10,25],[11,4],[11,25],[12,25],\n", + " [16,23],[16,22],[16,21],[16,30],[15,22],[15,21],[15,30],[14,21],[14,30],[13,30],\n", + " [24,15],[24,14],[24,13],[24,28],[23,14],[23,13],[23,28],[22,13],[22,28],[21,28],\n", + " [31,24],[31,23],[31,22],[31,21],[31,30]]\n", + " for x in roll_ins_skip_home:\n", + " T[x[1]-1, x[0]-1] *= roll_out\n", + "\n", + " # 9. Avoid stretching shorter fingers up and longer fingers down.\n", + " if side_top:\n", + " for x in all_32_keys:\n", + " for y in [1,4,25, 28,13,16,31]:\n", + " T[x-1, y-1] *= side_top\n", + " T[y-1, x-1] *= side_top\n", + "\n", + " if center_bottom:\n", + " for x in all_32_keys:\n", + " for y in [10,11,22,23]:\n", + " T[x-1, y-1] *= center_bottom\n", + " T[y-1, x-1] *= center_bottom\n", + "\n", + " if side_up_1away_down < 1.0 or side_up_2away_down < 1.0 or side_up_3away_down < 1.0 or ring_up_middle_down < 1.0:\n", + " side_up_1away_downs = [[1,6], [1,10], [5,10], [7,4], [11,4], [11,8],\n", + " [8,25],[12,25],[12,26], [17,28],[21,28],[21,29], \n", + " [20,31],[24,31],[24,32],\n", + " [16,19],[16,23],[20,23], [18,13],[22,13],[22,17]]\n", + " side_up_2away_downs = [[1,7], [1,11], [5,11], [6,4], [10,4], [10,8], \n", + " [7,25], [11,25], [11,26], [3,26], [3,27], [7,27],\n", + " [16,18],[16,22],[20,22], [19,13],[23,13],[23,17],\n", + " [14,29],[14,30],[18,30], [22,29],[22,28],[18,28],\n", + " [31,19],[31,23],[32,23]]\n", + " side_up_3away_downs = [[1,8], [1,12], [5,12], [5,4], [9,4], [9,8],\n", + " [2,26], [2,27], [6,27], [6,25], [10,25],[10,26],\n", + " [16,17],[16,21],[20,21], [20,13],[24,13],[24,17],\n", + " [15,29],[15,30],[19,30], [19,28],[23,28],[23,29],\n", + " [31,18],[31,22],[32,22], [32,14]]\n", + " ring_up_middle_downs = [[2,7],[6,11],[2,11], [15,18],[19,22],[15,22]]\n", + " if side_up_1away_down < 1.0:\n", + " for x in side_up_1away_downs:\n", + " T[x[0]-1, x[1]-1] *= side_up_1away_down\n", + " T[x[1]-1, x[0]-1] *= side_up_1away_down\n", + " if side_up_2away_down < 1.0:\n", + " for x in side_up_2away_downs:\n", + " T[x[0]-1, x[1]-1] *= side_up_2away_down\n", + " T[x[1]-1, x[0]-1] *= side_up_2away_down\n", + " if side_up_3away_down < 1.0:\n", + " for x in side_up_3away_downs:\n", + " T[x[0]-1, x[1]-1] *= side_up_3away_down\n", + " T[x[1]-1, x[0]-1] *= side_up_3away_down\n", + " if ring_up_middle_down < 1.0:\n", + " for x in ring_up_middle_downs:\n", + " T[x[0]-1, x[1]-1] *= ring_up_middle_down\n", + " T[x[1]-1, x[0]-1] *= ring_up_middle_down\n", + "\n", + " # 10. Avoid using the same finger.\n", + " if same_finger < 1.0:\n", + " same_fingers = [[1,5],[5,9],[1,9], [2,6],[6,10],[2,10], [3,7],[7,11],[3,11], [4,8],[8,12],[4,12],\n", + " [25,26],[26,27],[25,27],[28,29],[29,30],[28,30],[31,32],\n", + " [4,25],[4,26],[4,27],[8,25],[8,26],[8,27],[12,25],[12,26],[12,27],\n", + " [13,28],[13,29],[13,30],[17,28],[17,29],[17,30],[21,28],[21,29],[21,30],\n", + " [31,16],[31,20],[31,24],[32,16],[32,20],[32,24],\n", + " [13,17],[17,21],[13,21], [14,18],[18,22],[14,22], [15,19],[19,23],[15,23], [16,20],[20,24],[16,24]] \n", + " for x in same_fingers:\n", + " T[x[0]-1, x[1]-1] *= same_finger\n", + " T[x[1]-1, x[0]-1] *= same_finger\n", + "\n", + " # 11. Avoid the upper and lower rows.\n", + " if not_home_row < 1.0:\n", + " not_home_row_keys = [1,2,3,4,25, 9,10,11,12,27, 28,13,14,15,16,31, 30,21,22,23,24]\n", + " home_row_keys = [5,6,7,8,26, 29,17,18,19,20,32]\n", + " for x in not_home_row_keys:\n", + " for y in not_home_row_keys:\n", + " T[x-1, y-1] *= not_home_row\n", + " for x in not_home_row_keys:\n", + " for y in home_row_keys:\n", + " T[x-1, y-1] *= not_home_row\n", + " T[y-1, x-1] *= not_home_row\n", + "\n", + " # 12. Avoid skipping over the home row.\n", + " if skip_home_row < 1.0:\n", + " skip_home_rows_left = [[1,2,3,4,25], [9,10,11,12,27]] \n", + " skip_home_rows_right = [[28,13,14,15,16,31], [30,21,22,23,24]] \n", + " for x in skip_home_rows_left[0]:\n", + " for y in skip_home_rows_left[1]:\n", + " T[x-1, y-1] *= skip_home_row\n", + " T[y-1, x-1] *= skip_home_row\n", + " for x in skip_home_rows_right[0]:\n", + " for y in skip_home_rows_right[1]:\n", + " T[x-1, y-1] *= skip_home_row\n", + " T[y-1, x-1] *= skip_home_row\n", + "\n", + " Flow32x32 = T\n", + "\n", + " # Normalize matrix with min-max scaling to a range with maximum = 1:\n", + " newMin = np.min(Flow32x32) / np.max(Flow32x32)\n", + " newMax = 1.0\n", + " Flow32x32 = newMin + (Flow32x32 - np.min(Flow32x32)) * (newMax - newMin) / (np.max(Flow32x32) - np.min(Flow32x32))\n", + "\n", + " return Flow32x32\n", + " \n", + "Flow32x32 = create_32x32_flow_matrix(same_hand, same_finger, roll_out, not_home_row, skip_home_row, side_top, side_up_1away_down, side_up_2away_down, side_up_3away_down, center_bottom, ring_up_middle_down)\n", + "\n", + "# Print:\n", + "print_matrix_info(matrix_data=Flow32x32, matrix_label=\"Flow32x32\", nkeys=32, nlines=10)\n", + "heatmap(data=Flow32x32, title=\"Flow32x32\", xlabel=\"Key 1\", ylabel=\"Key 2\")\n", + "\n", + "# Save:\n", + "file = open(\"Flow32x32.txt\", \"w+\")\n", + "file.write(str(Flow32x32))\n", + "file.close()\n", + "\n", + "# Left: Right:\n", + "# 1 2 3 4 25 28 13 14 15 16 31 \n", + "# 5 6 7 8 26 29 17 18 19 20 32\n", + "# 9 10 11 12 27 30 21 22 23 24" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 265 + }, + "colab_type": "code", + "id": "F6wZ4iRLDzSM", + "outputId": "147c2189-b464-4202-fd34-0e8a5665291f" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/arno.klein/anaconda3/lib/python3.8/site-packages/seaborn/distributions.py:2551: FutureWarning: `distplot` is a deprecated function and will be removed in a future version. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms).\n", + " warnings.warn(msg, FutureWarning)\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Histogram\n", + "sns_plot = sns.distplot(Flow32x32)\n", + "sns_plot.figure.savefig(\"{0}_histogram.png\".format(\"Flow32x32\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "raw", + "id": "GQWWDBJXDzSS" + }, + "source": [ + "### Flow output\n", + "\n", + " Left: Right:\n", + " 1 2 3 4 13 14 15 16 \n", + " 5 6 7 8 17 18 19 20\n", + " 9 10 11 12 21 22 23 24\n", + "\n", + " \n", + " Flow24x24 min = 0.5314410000000002, max = 1.0\n", + " Flow24x24 key number pairs with minimum values:\n", + " 13 -> 23 (0.5314410000000002)\n", + " 10 -> 1 (0.5314410000000002)\n", + " 13 -> 22 (0.5314410000000002)\n", + " 23 -> 16 (0.5314410000000002)\n", + " 4 -> 11 (0.5314410000000002)\n", + " 4 -> 10 (0.5314410000000002)\n", + " 22 -> 16 (0.5314410000000002)\n", + " 11 -> 1 (0.5314410000000002)\n", + " 2 -> 10 (0.5904900000000002)\n", + " 4 -> 12 (0.5904900000000002)\n", + " Flow24x24 key number pairs with maximum values:\n", + " 5 -> 18 (1.0)\n", + " 20 -> 18 (1.0)\n", + " 5 -> 17 (1.0)\n", + " 5 -> 19 (1.0)\n", + " 5 -> 20 (1.0)\n", + " 19 -> 17 (1.0)\n", + " 19 -> 18 (1.0)\n", + " 19 -> 19 (1.0)\n", + " 6 -> 6 (1.0)\n", + " 6 -> 7 (1.0)\n", + "\n", + " Flow32x32 min = 0.43046721000000016, max = 1.0\n", + " Flow32x32 key number pairs with minimum values:\n", + " 25 -> 12 (0.43046721000000016)\n", + " 28 -> 21 (0.43046721000000016)\n", + " 24 -> 31 (0.43046721000000016)\n", + " 12 -> 25 (0.4782969000000001)\n", + " 27 -> 25 (0.4782969000000001)\n", + " 21 -> 28 (0.4782969000000001)\n", + " 25 -> 27 (0.4782969000000001)\n", + " 30 -> 28 (0.4782969000000001)\n", + " 28 -> 30 (0.4782969000000001)\n", + " 31 -> 24 (0.4782969000000001)\n", + " Flow32x32 key number pairs with maximum values:\n", + " 7 -> 18 (1.0)\n", + " 17 -> 6 (1.0)\n", + " 6 -> 19 (1.0)\n", + " 6 -> 20 (1.0)\n", + " 19 -> 5 (1.0)\n", + " 19 -> 6 (1.0)\n", + " 19 -> 7 (1.0)\n", + " 19 -> 8 (1.0)\n", + " 19 -> 17 (1.0)\n", + " 19 -> 18 (1.0)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "WMvP493uDzSU" + }, + "source": [ + "## Combine Speed, Strength, and Flow matrices " + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 695 + }, + "colab_type": "code", + "id": "UP7FUBR2DzSX", + "outputId": "5dc11788-2c69-4f69-ab60-a07ac17e092f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Factors24x24 min = 0.5314410000000002, max = 1.0\n", + "Factors24x24 key number pairs with minimum values:\n", + " 13 -> 23 (0.5314410000000002)\n", + " 10 -> 1 (0.5314410000000002)\n", + " 13 -> 22 (0.5314410000000002)\n", + " 23 -> 16 (0.5314410000000002)\n", + " 4 -> 11 (0.5314410000000002)\n", + " 4 -> 10 (0.5314410000000002)\n", + " 22 -> 16 (0.5314410000000002)\n", + " 11 -> 1 (0.5314410000000002)\n", + " 2 -> 10 (0.5904900000000002)\n", + " 4 -> 12 (0.5904900000000002)\n", + "Factors24x24 key number pairs with maximum values:\n", + " 5 -> 18 (1.0)\n", + " 20 -> 18 (1.0)\n", + " 5 -> 17 (1.0)\n", + " 5 -> 19 (1.0)\n", + " 5 -> 20 (1.0)\n", + " 19 -> 17 (1.0)\n", + " 19 -> 18 (1.0)\n", + " 19 -> 19 (1.0)\n", + " 6 -> 6 (1.0)\n", + " 6 -> 7 (1.0)\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# 24 keys:\n", + "Factors24x24 = Flow24x24\n", + "if apply_strength:\n", + " Factors24x24 = Strength24x24 * Factors24x24\n", + "if apply_speed:\n", + " Factors24x24 = Speed24x24 * Factors24x24\n", + "\n", + "# Print:\n", + "print_matrix_info(matrix_data=Factors24x24, matrix_label=\"Factors24x24\", nkeys=24, nlines=10)\n", + "heatmap(data=Factors24x24, title=\"Factors24x24\", xlabel=\"Key 1\", ylabel=\"Key 2\")\n", + "\n", + "# Save:\n", + "file = open(\"Factors24x24.txt\", \"w+\")\n", + "file.write(str(Factors24x24))\n", + "file.close()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 265 + }, + "colab_type": "code", + "id": "mXoSOaalDzSc", + "outputId": "d1f78386-db18-4028-e9de-8338b7590a2f" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/arno.klein/anaconda3/lib/python3.8/site-packages/seaborn/distributions.py:2551: FutureWarning: `distplot` is a deprecated function and will be removed in a future version. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms).\n", + " warnings.warn(msg, FutureWarning)\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Histogram\n", + "sns_plot = sns.distplot(Factors24x24)\n", + "sns_plot.figure.savefig(\"{0}_histogram.png\".format(\"Factors24x24\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Factors32x32 min = 0.43046721000000016, max = 1.0\n", + "Factors32x32 key number pairs with minimum values:\n", + " 25 -> 12 (0.43046721000000016)\n", + " 28 -> 21 (0.43046721000000016)\n", + " 24 -> 31 (0.43046721000000016)\n", + " 12 -> 25 (0.4782969000000001)\n", + " 27 -> 25 (0.4782969000000001)\n", + " 21 -> 28 (0.4782969000000001)\n", + " 25 -> 27 (0.4782969000000001)\n", + " 30 -> 28 (0.4782969000000001)\n", + " 28 -> 30 (0.4782969000000001)\n", + " 31 -> 24 (0.4782969000000001)\n", + "Factors32x32 key number pairs with maximum values:\n", + " 7 -> 18 (1.0)\n", + " 17 -> 6 (1.0)\n", + " 6 -> 19 (1.0)\n", + " 6 -> 20 (1.0)\n", + " 19 -> 5 (1.0)\n", + " 19 -> 6 (1.0)\n", + " 19 -> 7 (1.0)\n", + " 19 -> 8 (1.0)\n", + " 19 -> 17 (1.0)\n", + " 19 -> 18 (1.0)\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# 32 keys:\n", + "Factors32x32 = Flow32x32\n", + "if apply_strength:\n", + " Factors32x32 = Strength32x32 * Factors32x32\n", + "if apply_speed:\n", + " Factors32x32 = Speed32x32 * Factors32x32\n", + "\n", + "# Print:\n", + "print_matrix_info(matrix_data=Factors32x32, matrix_label=\"Factors32x32\", nkeys=32, nlines=10)\n", + "heatmap(data=Factors32x32, title=\"Factors32x32\", xlabel=\"Key 1\", ylabel=\"Key 2\")\n", + "\n", + "# Save:\n", + "file = open(\"Factors32x32.txt\", \"w+\")\n", + "file.write(str(Factors32x32))\n", + "file.close()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 265 + }, + "colab_type": "code", + "id": "mXoSOaalDzSc", + "outputId": "d1f78386-db18-4028-e9de-8338b7590a2f" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/arno.klein/anaconda3/lib/python3.8/site-packages/seaborn/distributions.py:2551: FutureWarning: `distplot` is a deprecated function and will be removed in a future version. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms).\n", + " warnings.warn(msg, FutureWarning)\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXgAAAD4CAYAAADmWv3KAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAAAjxElEQVR4nO3deXxV5Z3H8c8v+wJJCFkJYQ1LWAVBEFARQRG3Vttq1draxVZt7V47th3baWdqZzqdWrso1e7aOlXHqrVuuICoKGvYt7CFBEhCdrLe+8wfCQoWyE1yT5aT7/v1ygty77n3+XKBb8499znPMeccIiLiPxE9HUBERLyhghcR8SkVvIiIT6ngRUR8SgUvIuJTUT0d4ERpaWluxIgRPR1DRKTPWLNmTZlzLv1U9/Wqgh8xYgSrV6/u6RgiIn2Gme073X06RCMi4lMqeBERn1LBi4j4lApeRMSnVPAiIj6lghcR8SkVvIiIT6ngRUR8SgUvIuJTvepMVhE52SOr9nf4MdfPGuZBEumLtAcvIuJTKngREZ9SwYuI+JQKXkTEp1TwIiI+pYIXEfEpTZMUOUFHpyVqSqL0ZtqDFxHxKRW8iIhPqeBFRHxKBS8i4lMqeBERn1LBi4j4lApeRMSnPC14M/uymW02s01m9mczi/NyPBEReY9nBW9mOcAdwAzn3CQgErjOq/FERORkXh+iiQLizSwKSACKPR5PRETaeFbwzrmDwI+B/UAJUOWce+H925nZLWa22sxWl5aWehVHRKTf8fIQzSDgKmAkMARINLMb37+dc26pc26Gc25Genq6V3FERPodLw/RLAT2OOdKnXPNwBPAHA/HExGRE3hZ8PuB2WaWYGYGXARs9XA8ERE5gZfH4FcBjwFrgY1tYy31ajwRETmZp+vBO+fuBu72cgwRETk1nckqIuJTKngREZ9SwYuI+JQKXkTEp1TwIiI+pYIXEfEpFbyIiE+p4EVEfEoFLyLiUyp4ERGfUsGLiPiUCl5ExKdU8CIiPqWCFxHxKRW8iIhPqeBFRHxKBS8i4lMqeBERn1LBi4j4lApeRMSnVPAiIj6lghcR8SkVvIiIT6ngRUR8SgUvIuJTKngREZ9SwYuI+JQKXkTEp1TwIiI+pYIXEfEpFbyIiE+p4EVEfEoFLyLiUyp4ERGfUsGLiPiUCl5ExKdU8CIiPqWCFxHxKU8L3sxSzOwxM9tmZlvN7FwvxxMRkfdEefz89wLPOec+ZGYxQILH44mISBvPCt7MkoDzgU8AOOeagCavxhMRkZN5eYhmFFAK/NbM1pnZg2aW6OF4IiJyAi8LPgqYDvzKOTcNqAO++f6NzOwWM1ttZqtLS0s9jCMi0r94WfBFQJFzblXb94/RWvgncc4tdc7NcM7NSE9P9zCOiEj/4lnBO+cOAQfMbFzbTRcBW7waT0RETub1LJovAA+3zaApBG72eDwREWnjacE759YDM7wcQ0RETk1nsoqI+JQKXkTEp7w+Bi8iPvPIqv0d2v76WcM8SiLt0R68iIhPqeBFRHxKBS8i4lMqeBERn1LBi4j4lApeRMSnVPAiIj6lghcR8amQCt7MHjezy8xMPxBERPqIUAv7V8D1wE4zu8fMxnuYSUREwiCkgnfOveScu4HWC3bsBV40szfM7GYzi/YyoIiIdE7Ih1zMbDCtF9D+NLAOuJfWwn/Rk2QiItIlIS02ZmZPAOOBPwJXOOdK2u561MxWexVOREQ6L9TVJB90zj174g1mFuuca3TO6YIeIiK9UKiHaH5witveDGcQEREJrzPuwZtZFpADxJvZNMDa7koCEjzOJiIiXdDeIZpLaP1gdSjwkxNurwHu8iiTiIiEwRkL3jn3e+D3ZnaNc+7xbsokIiJh0N4hmhudc38CRpjZV95/v3PuJ6d4mIiI9ALtHaJJbPt1gNdBREQkvNo7RPNA26/f6544IiISLqEuNvafZpZkZtFmtszMyszsRq/DiYhI54U6D/5i51w1cDlQBIwFvu5ZKhER6bJQC/74gmJLgD875456lEdERMIk1KUKnjazbUA9cJuZpQMN3sUSEZGuCqngnXPfNLMfAdXOuYCZ1QFXeRtN5GSPrNrf4cdcP2uYB0lE+oZQ9+AB8mmdD3/iY/4Q5jwiIhImoS4X/EdgNLAeCLTd7FDBi4j0WqHuwc8AJjjnnJdhREQkfEKdRbMJyPIyiIiIhFeoe/BpwBYzextoPH6jc+5KT1KJiEiXhVrw3/UyhIiIhF+o0yRfM7PhwBjn3EtmlgBEehtNRES6ItS1aD4DPAY80HZTDvCkR5lERCQMQv2Q9XZgLlAN4JzbCWR4FUpERLou1IJvdM41Hf+m7WSnkKZMmlmkma0zs2c6E1BERDon1IJ/zczuovXi24uAvwJPh/jYLwJbOxNOREQ6L9SC/yZQCmwEPgs8C3y7vQeZ2VDgMuDBzgYUEZHOCXUWTdDMngSedM6VduD5fwp8AxjY8WgiItIVZ9yDt1bfNbMyYBuw3cxKzexf23tiM7scOOKcW9POdreY2WozW11a2pGfHSIicibtHaL5Eq2zZ2Y65wY751KBWcBcM/tyO4+dC1xpZnuBvwALzOxP79/IObfUOTfDOTcjPT29w38AERE5tfYK/ibgo865PcdvcM4VAje23Xdazrl/cc4Ndc6NAK4DXnbO6TquIiLdpL2Cj3bOlb3/xrbj8NGn2F5ERHqJ9j5kberkfSdxzr0KvBrq9iIi0nXtFfxUM6s+xe0GxHmQR0REwuSMBe+c04JiIiJ9VEeuySoivUAg6CgoqmTjwSqS46OZlJPM6PQBPR1LeiEVvEgnNLUEKa1ppKq+meT47ptv0NAc4Dcr91BUUU9KQjR7yup4e89RlkzOZm5eWrflkL5BBS/SAUHnWLb1CG8VllPfHOAXr+7i4gmZ3HPNFFITYzwduzkQ5A9v7qO4sp6PzBjKlKEptAQc/7v6AH/fWEJ8TCTThw3yNIP0LaGuRSPS7wWd4/E1Rbyy/Qij0hO5dkYut80fzavbS1ly7wr2lx/zdPznNx9ib3kdH56Ry1m5g4gwIyYqgutnDWN4agLPFBRT3dDsaQbpW1TwIiF6fvMh1h2oZNGETG6YNZypuSl8Y/F4nrhtDseaWvjMH1ZT29jiydj7jx7jzd3lzBqZytShKSfdF2HG1dOH0hJwPFNQ4sn40jep4EVCsK+8jtd3lnHOiFQuHHfytW4m5STzixums6u0lrue2Bj2sYPO8eS6gyTFR3PJxKxTbpM+MJbzxqSz6WAVOw7XhD2D9E0qeJF2tASDPLamiJSEaC6dfOqCPW9MOncsGMNTG4p5ZduRsI6/8WAVh6obuHRSFnHRp5+5PHf0YKIjjftf2x3W8aXvUsGLtOOdPUcpr2viqrNyiI06fcHeOn80eRkD+PaTmzjWFJ5DNYFg64e6mUmxTMpJPuO2CbFRnDMilb+tL6aowtvPA6RvUMGLnEFjS4BXtpcyMi2RMRlnnmseExXBv39gEgcr63loxZ4zbhuqgqJKymobuWh8JhFm7W4/Ny8N5xyPvnMgLONL36aCFzmDtwqPUtvYwiUTMrEQCnbWqMEsmpDJA8sLKa9t7NLYLYEgy7YdITs5jglDkkJ6TEpCDOePTeexNUUEgiFdNll8TAUvchotwSBv7C4jL2MAwwYnhvy4OxeP41hTC/e9vKtL4z+x7iBH65pYmB/a3vtxH5mRS0lVAyt26gI6/Z0KXuQ0NhZVUdPQwtzRHTtDNC9jINfOzOXhVfs6PTe+ORDkZ8t2kpMSz/isjl3x8qL8DAYlRPPX1UWdGlv8QwUvcgrOOVbuLiN9QCxjMju+zsuXFo4lMsL4rxe2d2r8x9YUUVRRz8L80A4NnSg2KpIrpw7hpa2HqfNoXr70DSp4kVPYW36M4soG5uQN7tDhkeMyk+L41LyRPL2hmI1FVR16bGNLgPuW7WTasBTGduKHC8CSydk0tgR5ZXt4p2xK36KCFzmFlbvKiI+OZFpu59d2+ewFoxmUEM09z23FudA/8PzL2wcormrgK4vGdnjv/bgZI1JJGxDLPzYe6tTjxR9U8CLvU17byNaSamaNTCUmqvP/RZLiovnCgjGs3FXO8p3/dOXLU6puaObeZTuZPSqVeV1YHTIywrhkYiavbD9CfVOg088jfZsKXuR93iwsJ8KM2aMGd/m5bpg9jNzUeP7971toagm2u/39r+7maF0T31oyodN778ctmZzNsaYAr+3QbJr+SgUvcoKG5gBr9lUwKSeJpDCs8x4bFcndl09kx+FaHmhnCYFdR2p56PU9XHXWECYPPfNZq6GYNTKVQQnR/GOTFiDrr1TwIidYu7+CxpYgczo4NfJMFk7I5PIp2dz38i62lpzqEsetJzV99a8biI+J5FtL8sMyblRkBBdPyGLZ1iM0tugwTX+kghdpEww63txdTu6geHJTE8L63HdfMZGUhGg+/fvVHKlpOOk+5xw//Mc2Nhyo5AcfmERGUviuZ3/p5CxqG1t4PcTPAMRfVPAibV7dcYTyuibmeHDpu/SBsTz08ZkcrWviYw++zbZDrXvy9U0Bvv/MVh56fQ+fmDOCy6cMCeu4c0ankRQXxbOaTdMv6ZJ9Im1+u3IvSXFRTBrS9ePfpzJ5aDJLbzqbLz+6nivue50xGQM5VN3A0bomPn7ucO6+YkLYx4yJimDhhExe3HKI5sBkoiO1T9ef6G9bBNh5uIYVO8uYNWowkRFdm71yJueNSef5L53PzXNHkpUcx7mjBvPoLbP57pUTuzxr5nQunZRNdUMLbxWWe/L80ntpD14E+M3KvcRERTBzRKrnYw0eEMtdYfogNRTnjUkjISaS5zYd4rwx6d02rvQ87cFLv3eoqoHH1xRxzfShDIj13z5PXHQkF47L4PnNh7WEcD+jgpd+74Hluwk4x23zR/d0FM9cMimLstpG1u2v6Oko0o1U8NKvHalp4M9v7+eD03LCPjWyN7lwXDoxkRE8t0mzafoTFbz0az95YQeBoOPzF+b1dBRPDYyLZt6YNJ7bfKhDC59J36aCl35rS3E1j64+wE3njmBEWuhXbOqrFk/Koqiins3Fpz6bVvxHBS/9UiDouPupTSTHR3PHgjE9HadbLMzPJDLCdJimH1HBS7/04IpC3tlbwbcvm0ByQtcXFesLUhNjmDUylX9sKtFhmn7Cf3PCRNqxdn8F//3CDhZPzOKa6Tk9HadbLZmczbef3MSWkmomhumMXeccW0tq2FBUScWxJlISYjhnRCp5GZ27GpWEj/bgpV/ZdaSGT/7uHbJT4viPqyd7dvZob3XZ5GyiI43/W3swLM9X3xTg4VX7+dOqfRSW1hIXFcm+sjp+s3IPj605oHn3PUx78BI2j6za36Htr581zKMkp/bm7nI+/8haoiKMP3zyHFITY7p1/N5gUGIM88dl8LcNxXzz0vFEdWFtmmNNLTy4Yg+lNY1cOimLOaPTiIwwmgNBXtl2hFd3lOIc3DBrGBEeLv8gp6c9ePG9g5X1fPvJjdz40CpSEqL5yy3nMnyw/2fNnM7V03IorWlk5e7Or03T1BLk92/spbS2kY/PGcF5Y9LfXcMnOjKCiydmsTA/k3UHKvnlq7vCFV06SHvw4juVx5rYU1bHnrI6li7fzd7yY0RFGB89J5c7F49nYFz/+FD1dBbkZ7T+oHt7PxeM7dzaNE9tKKaoop4bZg077bH2C8elc7i6gXuX7eTiiVmMzRzYldjSCSp46fOCzlFYWkdBUSW7SmupPNYMQHx0JHPz0rhx9nAunpDFsMH+PVO1I2KjIrl2Ri4Pvr6H4sp6hqTEd+jxq/ceZe3+ChaMz2DCGT6oNTOumDqEg5X1fOOxAp64dY4O1XQzzwrezHKBPwBZQBBY6py716vxpP9xzrG5uJqXth7mSE0jsVER5GUMYF5eGiPTEslMiuPG2cN7OmavdOPs4fx6RSF/emsf31g8PuTHbS2p5qkNxYxOT2TB+Ix2tx8QG8W3luTz1b9u4JmNJVw5NbwXNJEz83IPvgX4qnNurZkNBNaY2YvOuS0ejin9RF1jC0+uP8jm4moyBsbykRm5TBySpAtahCg3NYGF+Zn85Z0D3H5hHokhrKJZ09DMbQ+vJT4mko/MyCUixBlIH5yWw69XFPI/L+5gyaSsLn2wKx3j2SvtnCtxzq1t+30NsBXoX5OOxROlNY386rXdbDtUw+KJWdxx0RjOyk1RuXfQ5+aP5mhdEw+u2NPuts45/uWJjewrr+O6mcM69DlGRITx1YvHsaesjsfXFnUlsnRQt/yPMLMRwDRg1Snuu8XMVpvZ6tLS0u6II31YcWU997+2m8bmALecN4rzx6aHvCcpJ5s+bBCLJ2axdPluymobz7jtH9/axzMFJXztknGM7MS6PQvzM5ick8wDrxUS1Nz4buN5wZvZAOBx4EvOuX9a5cg5t9Q5N8M5NyM9XVebkdM7VNXAQ6/vITYqglvn5/l6ed/u8o3F42hoCfK9p7ecdvmCV7Yd4XtPb+Gi8Rl87vzOrZlvZnzm/FEUltWxbNuRrkSWDvC04M0smtZyf9g594SXY4m/Halu4Pdv7iU60vjUvJH98iQlL4xKH8BXFo3l6Q3F/Hbl3n+6/41dZdz+yFrGZw3k3o9O69IsmCWTsshJiefXywu7kFg6wrOCt9ZzwB8CtjrnfuLVOOJ/Dc0BPvPHNRxrauGmc0cweEBsT0fylVsvGM2iCZn84O9b+NFz26huaKairomfv7yTj/3mbXJS4vntJ2Z2+XKGUZER3Dx3BG/vPcqmg1VhSi9n4uUe/FzgY8ACM1vf9rXEw/HEh5xzfP2xAgqKKrl2Rm6H52xL+yIijJ9eexYfPjuXX726mynffYHpP3iRH7+wg4X5GTxx2xwykuLCMtaHz84lLjqChzu4rIV0jmfTJJ1zrwP69Eu65GfLdvH0hmLuXDye5Pj+fQaqlxJjo/jRh6Zw9fQc1h+opK4pwKWTssjPTgrrOMkJ0VwxZQh/W3+Qu5borGKvaV6Z9FrPFBTzPy/t4OrpOXzuglE9HadfmDVqMJ+9YDRfWTQ27OV+3A2zh3OsKcCT64s9eX55j5YqkF5pw4FKvvq/G5gxfBA/7IfL+vrZ1KHJTBySxMNv7ePGWcPC8nfb21cy7Snag5dep6jiGJ/6/WoykmK5/2NnExsV2dORJIzMjBtmDWfboRrW7q/s6Ti+poKXXqW6oZlP/u4dGlsC/PYTM0nTjBlfuuqsIQyIjeLhVft6OoqvqeCl12gOBLn94bUUltZx/41nk5eh5WX9KjE2ig9Oy+GZghIq6pp6Oo5vqeClV2gJBPnyo+tZsbOMH3xgEnPz0no6knjs+lnDaGoJan0aD6ngpcc1B4Kty8kWlPAvl47nunP6xwdg/V1+dhLTh6XwyNv7T7tMgnSNCl56VG1jC5/6/Wr+tr6Ybywex2cv6NxaJ9I33TBrOIWldbxVeLSno/iSCl56zM7DNVz589d5fWcp91w9mdvm5/V0JOlml03JJjk+Wh+2ekQFL90uEHQs31HK5fe9TnV9Mw9/erYOy/RTcdGRXDN9KM9vPtTuksXScSp46TZB59hSXMXPlu3kuc2HuGBsOs/ecR7njh7c09GkB10/K5fmgOOvq/Vha7jpTFbxXFNLkLX7K3hjdxlltU2kDYjhxlnD+f4HJuoMVSEvYyCzRqbyyNv7+Oz5o3Rh7jBSwYtnquubeauwnFV7jlLfHCAnJZ5rZ+QyKSeZyAhTucu7bpg9nDv+vI7XdpRyYQgX85bQqOD7ke5ar+NwdQPLd5RSUFRF0Dnys5OYl5fG8MEJKnU5pcUTs8hKiuOh1/eo4MNIBS9hU1xZzyvbj7CluJqoSGPmyFTmjh6sC3RIu2KiIrhpznD+87ntbDtUzfgsb1ay7G/0Iat02YGjx7jjz+v4+Su72F1ay/xx6XzjkvFcOXWIyl1Cdv05w4iPjuTBFXt6OopvaA9eOq2moZmfv7yL367cS0QEXDgunfPGpBMXrdUfpeNSEmK4dmYuf3prH1+8aIwuqh4G2oOXDgsGHX9dfYALf/waS1cUcuVZQ3jla/NZNCFL5S5dcuv80UREGL98dVdPR/EF7cFLh2w4UMndT21m/YFKpg1L4aGPz2BqbkpPxxKfyEyK47qZuTyyaj+3zc/TXnwXaQ9eQlJW28idjxXwgV+upKiinv/+8FQe/9wclbuE3W3z84iKNO55bltPR+nztAcvZ1Tb2MJvX9/D0hWF1DcF+Mx5o/jCgjxdLFk8k5Ucx+cuGM1PX9rJx889yjkjU3s6Up+lgpdTamgO8MBru7n/td1UHGtmYX4m37x0PHkZA3o6mvQDnz1/NP/7zgG+8+QmnvrCXF22sZNU8HKSsppG3iwsZ+3+ChpbglwwNp2vLBqrQzHSreJjIvnBByfxyd+t5r9f2MFdS/J7OlKfpIIXjjW1sPFgFRsOVLK3/BiRZkwZmsx3r5yoYpces2B8JjfMGsavVxQye1QqC8Zndun5mlqC1Da20BIIUlbbSGpCjO/XvVHB91NNLUG2HapmQ1EVOw7VEHCO9AGxLJqQyYzhgxgYF61ylx73rcvy2VBUyW0Pr+XhT8/m7OGDQn5sIOjYdaSGrSU1FJbVUl7bxPHrRv102U6S46OZOSKVK6Zmc8lEf07xVcH3I82BINsP1bDxYBXbDlXTHHAMjIvi3NGDmZqbwpDkOK0VI71KQkwUv7v5HK751Rvc9NAq/uvDU1kyOfu02zvnOFTdwLr9law/UEltYwsxURGMTktkam4KKfHRREVGMCE7ia0l1azYWcZLWw+TNiCW2+aP5sbZw4mJ8s/kQhW8zzW2BFi+o4xnCor5x6ZDNLUESYiJZNqwQUzOSWZkWiIRKnXpxdIGxPLoLedy68NruO3htVw8IZNPzRvJWcNSiI2KpKklyMHKeraWVLOxqIrS2kYizRiXNZDpwwYxNmsAUREnl/bxhfSCQccbu8v5xSu7+LdntvDI2/v54dWTmTnCHzN3VPC9REdXeoTTr/bY1BJk5a4yni4o5sXNh6lpbCElIZopOclMGZrCyLREIn1+7FH8JSs5jkdvOZdfvbqbh14v5IUth4mONOKiI6lvCtASdBgwMj2ROXmDmTQkmcTY9ustIsKYNyaNeWPSeHnbYb7z5GaufeBNvrBgDHdcNKbP/z9RwftESyDIG7vLeaagmOc3H6aqvpmBcVFcMimLy6dkMzcvTVfMkT4tJiqCLy4cwyfnjWDlrjIKiqpoaG59R1pa28iotMQunZ+xYHwms748mO/8bRP3LtvJW4Xl3HvdNLKS48L4p+heKvg+LBB0rNpTzjMFJTy36RBH65oYEBvFogmZXD4lm3lj0jR/WHxnYFw0iydls3jSe8fiO/MO+FQSY6P4yUfOYu7oNL7zt00s+dkK7vvoNObmpYXl+bubCr6PaQkG2VNax5aSav7npR2U1jQSHx3JwgmZXDY5m/njtJqjSFddc/ZQpuamcOuf1vCxh1bxtUvGcesFo/vcJAQVfB9Q3xRg++EatpZUs+NwDY0tQaIjjYX5mVw+ZQgLxmcQH6NSFwmnvIwBPHn7XO58vID/fG476/dX8uOPTCWpDy3ToYLvpSqONbG1pJqtJdXsKasj6GBAbBSTc5KZkJ3E6IwBfHzOiJ6OKeJribFR3PfRaUwbNoj/eHYrV/18JfffeDbjsgb2dLSQqOB7CeccxVUN75Z6SVUDAOkDYzlvTDr52UkMHRSvKY0i3czM+NS8kUzOSeb2R9bygV+s5IdXT+YD03J6Olq7VPA9qKklyFuF5by45TBPbSimqr4ZA4YPTuDSSVnkZyeRpkveifQK54xM5e9fmMftj6zlS4+u5/nNh/jeVRPJGNh7Z9mo4LtZaU0jK3aW8vK2I7y2vZSaxhbioyMZmZbIwvxMxmUNZEAI83dFpPtlJMXxyGdms3R5Ifcu28kbu8v59mX5XDN9aK9c10ZN4rH6pgDr9lewfGcZy3eUsqWkGmg9O++yKdksmpDJ3Lw0nlh7sIeTikgooiMjuP3CPC6ZmMWdjxfw9ccKeHDFHr68aAyXTMzqVTNtVPBhFAw6iirq2VBUyZp9FazdX8GW4mpago6oCOPs4YP4+iXjuGBsOhOyk3rlT3wRCU1exgD++tlzebqgmHtf2snn/rSW/OwkrpuZyxVTh5CaGNPTEb0teDNbDNwLRAIPOufu8XK87uCco+JYMwcr6jlYeYz9R4+x43AtOw7XsPNwLfXNAQCiI42hgxKYl5fGsMEJjBycSGzb/PSCoioKiqp68o8hImEQEWFcdVYOl03O5qkNxSxdXsjdT23m+89s4YKx6cwbk8Y5I1MZn5XUI8seeFbwZhYJ/AJYBBQB75jZU865LV6NeZxzjqBrPdMz6Fq/Wn/fupcddI7mgONYUwv1zQEamgPUNwWpbw60fjW1UHmsmaPHmqioa6LiWDMVdU0crWuipKrh3RI/Ln1gLOMyB3LdObmMzRzIxCFJbDhQ1efXsRCR0ERFRnD19KFcPX0oW0uq+b91B/l7QQnLth0BYGBsFKMzBjAqLZHhgxNJGxjDoIQYUhKiGZTQ+nsvlkTwcg/+HGCXc64QwMz+AlwFhL3gp/3bC9Q1BlqL3Dmca/8xoYiJjGBQYutfQGpiDPnZSVw4PoOclHiGpMQzdFDrV0rCP78V23SwOjwhRKRPyc9OIj87ibuW5HOwsp539hxlzb4KCstqeauwnCfW/fPnbamJMaz9zqKwZzEXrjZ8/xObfQhY7Jz7dNv3HwNmOec+/77tbgFuaft2HLDdk0BdlwaU9XSIM+jt+UAZw6G35wNlDJdQMw53zqWf6g4v9+BPdXzin36aOOeWAks9zBEWZrbaOTejp3OcTm/PB8oYDr09HyhjuIQjo5eXLikCck/4fihQ7OF4IiJyAi8L/h1gjJmNNLMY4DrgKQ/HExGRE3h2iMY512Jmnweep3Wa5G+cc5u9Gq8b9PbDSL09HyhjOPT2fKCM4dLljJ59yCoiIj3LP5cPFxGRk6jgRUR8SgV/AjNbbGbbzWyXmX3zDNvNNLNA21z/btVeRjObb2ZVZra+7etfe1vGE3KuN7PNZvZab8pnZl8/4fXb1PZ3ndrLMiab2dNmtqHtNby5O/OFmHGQmf2fmRWY2dtmNqmb8/3GzI6Y2abT3G9m9rO2/AVmNr0784WYcbyZvWlmjWb2tQ4P4JzTV+vnEJHAbmAUEANsACacZruXgWeBD/W2jMB84Jne/DoCKbSe0Tys7fuM3pTvfdtfAbzcC1/Du4Aftf0+HTgKxPSyjP8F3N32+/HAsm5+Hc8HpgObTnP/EuAftJ6zMxtY1Z35QsyYAcwE/h34WkefX3vw73l3aQXnXBNwfGmF9/sC8DhwpDvDtQk1Y08KJeP1wBPOuf0AzrnufC07+hp+FPhztyR7TygZHTDQWtemHUBrwbf0sowTgGUAzrltwAgzy+yugM655bS+LqdzFfAH1+otIMXMsrsnXav2Mjrnjjjn3gGaO/P8Kvj35AAHTvi+qO22d5lZDvBB4P5uzHWidjO2Obftrfs/zGxi90R7VygZxwKDzOxVM1tjZjd1W7rQX0PMLAFYTOsP9O4USsafA/m0njy4Efiicy7YPfGA0DJuAK4GMLNzgOG0nvDYW4T8b6Gv0nrw7wllaYWfAnc65wI9tKh/KBnX0ro2Ra2ZLQGeBMZ4HewEoWSMAs4GLgLigTfN7C3n3A6vwxHiEhptrgBWOufOtBfohVAyXgKsBxYAo4EXzWyFc667VrkLJeM9wL1mtp7WH0Lr6N53Ge3pyL+FPkkF/55QllaYAfylrdzTgCVm1uKce7JbEoaQ8cT/4M65Z83sl2aW5pzrroWVQnkdi4Ay51wdUGdmy4GpQHcUfEeW0LiO7j88A6FlvBm4x7UeqN1lZntoPc79dvdEDPnf4s3Q+oEmsKftq7fw/XIqOkTznnaXVnDOjXTOjXDOjQAeA27rxnIPKaOZZbX9Zzr+tjgCKO9NGYG/AeeZWVTbYZBZwNZelA8zSwYuaMva3ULJuJ/Wd0C0HdceBxT2poxmltJ2H8CngeXd+A4jFE8BN7XNppkNVDnnSno6VDhpD76NO83SCmb2ubb7e+q4+7tCzPgh4FYzawHqgeva9vJ6TUbn3FYzew4oAIK0Xu3rlNPEeiJf26YfBF5oe5fRrULM+H3gd2a2kdZDDXd247u0UDPmA38wswCts6Y+1V35AMzsz7TOKkszsyLgbiD6hHzP0jqTZhdwjLZ3G70po5llAauBJCBoZl+idbZSSD8otVSBiIhP6RCNiIhPqeBFRHxKBS8i4lMqeBERn1LBi4j4lApeRMSnVPAiIj71/+NJZM13SecoAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Histogram\n", + "sns_plot = sns.distplot(Factors32x32)\n", + "sns_plot.figure.savefig(\"{0}_histogram.png\".format(\"Factors32x32\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "raw", + "id": "TtqGHKbjDzSj" + }, + "source": [ + "### Combined output\n", + "\n", + " Left: Right:\n", + " 1 2 3 4 13 14 15 16 \n", + " 5 6 7 8 17 18 19 20\n", + " 9 10 11 12 21 22 23 24\n", + "\n", + " Factors24x24 min = 0.4874949173076925, max = 1.0\n", + " Factors24x24 key number pairs with minimum values:\n", + " 10 -> 1 (0.4874949173076925)\n", + " 23 -> 16 (0.4874949173076925)\n", + " 22 -> 16 (0.5048689500000002)\n", + " 11 -> 1 (0.5048689500000002)\n", + " 4 -> 10 (0.5089569576923079)\n", + " 13 -> 23 (0.5089569576923079)\n", + " 4 -> 11 (0.5263309903846156)\n", + " 13 -> 22 (0.5263309903846156)\n", + " 24 -> 16 (0.5314410000000002)\n", + " 16 -> 24 (0.5314410000000002)\n", + " Factors24x24 key number pairs with maximum values:\n", + " 18 -> 7 (1.0)\n", + " 7 -> 7 (1.0)\n", + " 7 -> 18 (1.0)\n", + " 18 -> 18 (1.0)\n", + " 7 -> 17 (0.9903846153846154)\n", + " 18 -> 17 (0.9903846153846154)\n", + " 18 -> 8 (0.9903846153846154)\n", + " 7 -> 8 (0.9903846153846154)\n", + " 17 -> 7 (0.9903846153846154)\n", + " 8 -> 18 (0.9903846153846154)\n", + "\n", + " Left: Right:\n", + " 1 2 3 4 25 28 13 14 15 16 31 \n", + " 5 6 7 8 26 29 17 18 19 20 32\n", + " 9 10 11 12 27 30 21 22 23 24\n", + "\n", + " Factors32x32 min = 0.38742048900000015, max = 1.0\n", + " Factors32x32 key number pairs with minimum values:\n", + " 24 -> 31 (0.38742048900000015)\n", + " 25 -> 12 (0.42218899442307706)\n", + " 28 -> 21 (0.42218899442307706)\n", + " 31 -> 24 (0.4304672100000001)\n", + " 16 -> 31 (0.43046721000000016)\n", + " 20 -> 31 (0.43046721000000016)\n", + " 23 -> 31 (0.43874542557692325)\n", + " 30 -> 28 (0.46909888269230776)\n", + " 30 -> 13 (0.46909888269230776)\n", + " 28 -> 30 (0.46909888269230776)\n", + " Factors32x32 key number pairs with maximum values:\n", + " 18 -> 7 (1.0)\n", + " 7 -> 18 (1.0)\n", + " 7 -> 7 (1.0)\n", + " 18 -> 18 (1.0)\n", + " 7 -> 8 (0.9903846153846154)\n", + " 8 -> 18 (0.9903846153846154)\n", + " 7 -> 17 (0.9903846153846154)\n", + " 17 -> 7 (0.9903846153846154)\n", + " 18 -> 17 (0.9903846153846154)\n", + " 18 -> 8 (0.9903846153846154)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 1: Define the shape of the key layout to minimize lateral finger movements\n", + "\n", + "We will assign 24 letters to 8 columns of keys separated by two middle columns reserved for punctuation. These 8 columns require no lateral finger movements when touch typing, since there is one column per finger. The most comfortable keys include the left and right home rows (keys 5-8 and 17-20), the top-center keys (2,3 and 14,15) that allow the longer middle and ring fingers to uncurl upwards, as well as the bottom corner keys (9,12 and 21,24) that allow the shorter fingers to curl downwards. We will assign the two least frequent letters, Z and Q, to the two hardest-to-reach keys lying outside the 24-key columns in the upper right:\n", + "\n", + " Left: Right:\n", + " 1 2 3 4 13 14 15 16 Z/Q\n", + " 5 6 7 8 17 18 19 20 Q/Z\n", + " 9 10 11 12 21 22 23 24" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "REInHU9tdYLP" + }, + "source": [ + "## Step 2: Arrange the most frequent letters based on comfort and bigram frequencies \n", + "\n", + "We will assign letters to keys by choosing the arrangement with the highest score according to our scoring model. However, there are over four hundred septillion, or four hundred trillion trillion (26! = 403,291,461,126,605,635,584,000,000, or 4.032914611 E+26) possible arrangements of 26 letters (24! = 6.204484017 E+23), so we will arrange the letters in stages, based on ergonomic principles.\n", + " \n", + "In prior experiments using the methods below, all vowels consistently automatically clustered together. Below, we will arrange vowels on one side and the most frequent consonants to the other side to encourage balance and alternation across hands. Since aside from the letters Z and Q there is symmetry across left and right sides, we will decide later which side the vowels and which side the most frequent consonants should go.\n", + "\n", + "### Vowels\n", + " \n", + "**E**, T, **A, O, I**, N, S, R, H, L, D, C, **U**, M, F, P, G, W, **Y**, B, V, K, X, J, Q, Z\n", + "\n", + "The high-frequency bigrams that contain these vowels are listed below in bold, with more than 10 billion instances:\n", + "\n", + "**OU, IO, EA, IE**, AI, IA, EI, UE, UA, AU, UI, OI, EO, OA, OE \n", + " \n", + " OU 24531132241\n", + " IO 23542263265\n", + " EA 19403941063\n", + " IE 10845731320\n", + " AI 8922759715\n", + " IA 8072199471 \n", + " EI 5169898489\n", + " UE 4158448570 \n", + " UA 3844138094 \n", + " AU 3356322923\n", + " UI 2852182384\n", + " OI 2474275212\n", + " EO 2044268477\n", + " OA 1620913259\n", + " OE 1089254517 \n", + " \n", + "We will assign the vowels (E,A,O,I,U) to the most comfortable keys (keys 5-8, 2-3, 12) of one side, with the letter E, the most frequent in the English language, assigned to either of the strongest keys (7 and 8, the middle and index fingers on the left home row). We will arrange the vowels such that any top-frequency bigram (more than 1 billion instances in Peter Norvig's analysis of Google data) reads from left to right (ex: TH, not HT) for ease of typing (roll-in from little to index finger vs. roll-out from index to little finger). These constraints lead to comfortable and efficient layouts:\n", + " \n", + " (1) - O U -\n", + " I - E A \n", + "\n", + " (2) - - U - \n", + " I O E A \n", + "\n", + " (3) - - - - \n", + " I O E A\n", + " - - - U\n", + " \n", + " (4) - O - - \n", + " I - E A\n", + " - - - U \n", + "\n", + " (5) - - O - \n", + " I - E A\n", + " - - - U \n", + "\n", + " (6) - - O - \n", + " - I E A\n", + " - - - U \n", + "\n", + "### Consonants\n", + "\n", + "Next, to populate the home row on the other side of the keyboard, we examine all possible sequences of four letters from the eight most frequent consonants (T,N,S,R,H,L,D,C), covering half the alphabet, where each letter has at least 100 billion (at least 3% of) instances in Peter Norvig's analysis:\n", + "\n", + "E, **T**, A, O, I, **N, S, R, H, L, D, C**, U, M, F, P, G, W, Y, B, V, K, X, J, Q, Z\n", + "\n", + "These eight consonants are included among the highest frequency bigrams, listed below in bold, with more than 10 billion instances:\n", + "\n", + "**TH, ND, ST, NT, CH, NS, CT, TR, RS, NC**, (RT), SH, LD, RD, LS, DS, LT, (TL), RL, HR, NL, (SL)\n", + " \n", + " TH 100272945963 3.56% \n", + " ND 38129777631 1.35%\n", + " ST 29704461829 1.05%\n", + " NT 29359771944 1.04%\n", + " CH 16854985236 0.60%\n", + " NS 14350320288 \n", + " CT 12997849406\n", + " TR 12006693396 \n", + " RS 11180732354 \n", + " NC 11722631112\n", + " RT 10198055461 \n", + "\n", + "To maximize the number of bigrams we can comfortably type, we select 4-consonant sequences that contain the maximum number (5) of high-frequency (>1 billion instances) bigrams. For example, RNST contains NS, ST, RS, NT, and RT. We also restrict T to the strongest (middle or index) fingers, because T is the most frequent consonant:\n", + "\n", + " NSTH: NS, NT, ST, SH, TH\n", + " NCTH: NC, NT, CT, CH, TH\n", + " NRST: NS, NT, RS, RT, ST\n", + " RNST: RS, RT, NS, NT, ST\n", + "\n", + "The resulting 6 arrangements of 5 vowels on the left and 6 arrangements of 4 consonants on the right gives us 24 layouts, each with 15 unassigned keys (letters on the right side are reversed, in case Hand 2 is assigned to the right hand):\n", + "\n", + " Hand 1 Hand 2\n", + " -OU- I-EA ---- ---- HTSN ----\n", + " -OU- I-EA ---- ---- HTCN ----\n", + " -OU- I-EA ---- ---- TSRN ----\n", + " -OU- I-EA ---- ---- TSNR ----\n", + " --U- IOEA ---- ---- HTSN ----\n", + " --U- IOEA ---- ---- HTCN ----\n", + " --U- IOEA ---- ---- TSRN ----\n", + " --U- IOEA ---- ---- TSNR ----\n", + " ---- IOEA ---U ---- HTSN ----\n", + " ---- IOEA ---U ---- HTCN ----\n", + " ---- IOEA ---U ---- TSRN ----\n", + " ---- IOEA ---U ---- TSNR ----\n", + " -O-- I-EA ---U ---- HTSN ----\n", + " -O-- I-EA ---U ---- HTCN ----\n", + " -O-- I-EA ---U ---- TSRN ----\n", + " -O-- I-EA ---U ---- TSNR ----\n", + " --O- I-EA ---U ---- HTSN ----\n", + " --O- I-EA ---U ---- HTCN ----\n", + " --O- I-EA ---U ---- TSRN ----\n", + " --O- I-EA ---U ---- TSNR ----\n", + " --O- -IEA ---U ---- HTSN ----\n", + " --O- -IEA ---U ---- HTCN ----\n", + " --O- -IEA ---U ---- TSRN ----\n", + " --O- -IEA ---U ---- TSNR ----\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 3: Optimize assignment of the remaining letters \n", + " \n", + "We want to assign the 15 missing letters to the unassigned keys in each of the above 30 layouts based on our scoring model. That would mean scoring all possible arrangements for each layout and choosing the arrangement with the highest score, but since there are over 1.3 trillion possible ways of arranging 15 letters (15! = 1,307,674,368,000), we will break up the assignment into two stages: first for the most frequent remaining letters, and second for the least frequent remaining letters. \n", + " \n", + "### Most frequent letters\n", + "First we will compute scores for every possible arrangement of the 5 most frequent remaining letters among those in bold below for the most comfortable of the remaining positions (3,14,15,21, and either 2 or 6 or 12):\n", + "\n", + "E, T, A, O, I, N, **S, R, H, L, D, C**, U, **M**, F, P, G, W, Y, B, V, K, X, J, Q, Z\n", + "\n", + " Hand 1: Hand 2:\n", + " - 2 3 - - 14 15 -\n", + " x 6 x x x x x x\n", + " - - - 12 21 - - -\n", + " \n", + "Since there are 5! = 120 possible combinations, and we have 24 layouts, we need to score and evaluate 2,800 combinations. \n", + " \n", + "To score each arrangement of letters, we construct a frequency matrix of each ordered pair of letters (bigram), and multiply this frequency matrix by our speed-strength-flow matrix to compute a score. " + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Topmost of 120 permutations: 0.10354632973004214\n", + "['O' 'U' 'I' 'C' 'E' 'A' 'D' 'M' 'L' 'H' 'T' 'S' 'N' 'R']\n", + "Topmost of 120 permutations: 0.1034637534264725\n", + "['O' 'U' 'I' 'S' 'E' 'A' 'D' 'L' 'M' 'H' 'T' 'C' 'N' 'R']\n", + "Topmost of 120 permutations: 0.10431198384100161\n", + "['O' 'U' 'I' 'H' 'E' 'A' 'D' 'C' 'L' 'T' 'S' 'R' 'N' 'M']\n", + "Topmost of 120 permutations: 0.10433967881938948\n", + "['O' 'U' 'I' 'H' 'E' 'A' 'D' 'C' 'L' 'T' 'S' 'N' 'R' 'M']\n", + "Topmost of 120 permutations: 0.10367502054396106\n", + "['C' 'U' 'I' 'O' 'E' 'A' 'D' 'M' 'L' 'H' 'T' 'S' 'N' 'R']\n", + "Topmost of 120 permutations: 0.10312811950603755\n", + "['M' 'U' 'I' 'O' 'E' 'A' 'D' 'L' 'S' 'H' 'T' 'C' 'N' 'R']\n", + "Topmost of 120 permutations: 0.103800444248957\n", + "['H' 'U' 'I' 'O' 'E' 'A' 'D' 'C' 'L' 'T' 'S' 'R' 'N' 'M']\n", + "Topmost of 120 permutations: 0.10382813922734487\n", + "['H' 'U' 'I' 'O' 'E' 'A' 'D' 'C' 'L' 'T' 'S' 'N' 'R' 'M']\n", + "Topmost of 120 permutations: 0.10350129337069507\n", + "['C' 'M' 'I' 'O' 'E' 'A' 'U' 'D' 'L' 'H' 'T' 'S' 'N' 'R']\n", + "Topmost of 120 permutations: 0.10289025726759064\n", + "['D' 'M' 'I' 'O' 'E' 'A' 'U' 'L' 'S' 'H' 'T' 'C' 'N' 'R']\n", + "Topmost of 120 permutations: 0.10363099824178612\n", + "['H' 'M' 'I' 'O' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'R' 'N' 'D']\n", + "Topmost of 120 permutations: 0.10365869322017397\n", + "['H' 'M' 'I' 'O' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'N' 'R' 'D']\n", + "Topmost of 120 permutations: 0.10334836255362674\n", + "['O' 'M' 'I' 'C' 'E' 'A' 'U' 'D' 'L' 'H' 'T' 'S' 'N' 'R']\n", + "Topmost of 120 permutations: 0.10325469239888893\n", + "['O' 'M' 'I' 'S' 'E' 'A' 'U' 'D' 'L' 'H' 'T' 'C' 'N' 'R']\n", + "Topmost of 120 permutations: 0.1040847131637929\n", + "['O' 'M' 'I' 'H' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'R' 'N' 'D']\n", + "Topmost of 120 permutations: 0.10411240814218077\n", + "['O' 'M' 'I' 'H' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'N' 'R' 'D']\n", + "Topmost of 120 permutations: 0.1036874236589209\n", + "['C' 'O' 'I' 'R' 'E' 'A' 'U' 'D' 'L' 'H' 'T' 'S' 'N' 'M']\n", + "Topmost of 120 permutations: 0.10341981245057436\n", + "['M' 'O' 'I' 'S' 'E' 'A' 'U' 'D' 'L' 'H' 'T' 'C' 'N' 'R']\n", + "Topmost of 120 permutations: 0.10426359859556522\n", + "['M' 'O' 'I' 'H' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'R' 'N' 'D']\n", + "Topmost of 120 permutations: 0.10429129357395309\n", + "['M' 'O' 'I' 'H' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'N' 'R' 'D']\n", + "Topmost of 120 permutations: 0.10358961876200685\n", + "['C' 'O' 'R' 'I' 'E' 'A' 'U' 'D' 'L' 'H' 'T' 'S' 'N' 'M']\n", + "Topmost of 120 permutations: 0.10324874217517697\n", + "['M' 'O' 'S' 'I' 'E' 'A' 'U' 'D' 'L' 'H' 'T' 'C' 'N' 'R']\n", + "Topmost of 120 permutations: 0.10426111283602428\n", + "['M' 'O' 'H' 'I' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'R' 'N' 'D']\n", + "Topmost of 120 permutations: 0.10428880781441215\n", + "['M' 'O' 'H' 'I' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'N' 'R' 'D']\n" + ] + } + ], + "source": [ + "data_matrix = Factors24x24\n", + "keys16 = [2,3, 5,6,7,8, 12, 14,15, 17,18,19,20, 21]\n", + "letters24 = ['E','T','A','O','I','N','S','R','H','L','D','C','U','M','F','P','G','W','Y','B','V','K','X','J']\n", + "verbose = False\n", + "ntop = 0\n", + "\n", + "# -OU- I-EA ---- ---- HTSN ----\n", + "letters = ['O','U', 'I','','E','A', '', '','', 'H','T','S','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -OU- I-EA ---- ---- HTCN ----\n", + "letters = ['O','U', 'I','','E','A', '', '','', 'H','T','C','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -OU- I-EA ---- ---- TSRN ----\n", + "letters = ['O','U', 'I','','E','A', '', '','', 'T','S','R','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -OU- I-EA ---- ---- TSNR ----\n", + "letters = ['O','U', 'I','','E','A', '', '','', 'T','S','N','R', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# --U- IOEA ---- ---- HTSN ----\n", + "letters = ['','U', 'I','O','E','A', '', '','', 'H','T','S','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --U- IOEA ---- ---- HTCN ----\n", + "letters = ['','U', 'I','O','E','A', '', '','', 'H','T','C','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --U- IOEA ---- ---- TSRN ----\n", + "letters = ['','U', 'I','O','E','A', '', '','', 'T','S','R','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --U- IOEA ---- ---- TSNR ----\n", + "letters = ['','U', 'I','O','E','A', '', '','', 'T','S','N','R', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# ---- IOEA ---U ---- HTSN ----\n", + "letters = ['','', 'I','O','E','A', 'U', '','', 'H','T','S','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# ---- IOEA ---U ---- HTCN ----\n", + "letters = ['','', 'I','O','E','A', 'U', '','', 'H','T','C','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# ---- IOEA ---U ---- TSRN ----\n", + "letters = ['','', 'I','O','E','A', 'U', '','', 'T','S','R','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# ---- IOEA ---U ---- TSNR ----\n", + "letters = ['','', 'I','O','E','A', 'U', '','', 'T','S','N','R', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# -O-- I-EA ---U ---- HTSN ----\n", + "letters = ['O','', 'I','','E','A', 'U', '','', 'H','T','S','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -O-- I-EA ---U ---- HTCN ----\n", + "letters = ['O','', 'I','','E','A', 'U', '','', 'H','T','C','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -O-- I-EA ---U ---- TSRN ----\n", + "letters = ['O','', 'I','','E','A', 'U', '','', 'T','S','R','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -O-- I-EA ---U ---- TSNR ----\n", + "letters = ['O','', 'I','','E','A', 'U', '','', 'T','S','N','R', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# --O- I-EA ---U ---- HTSN ----\n", + "letters = ['','O', 'I','','E','A', 'U', '','', 'H','T','S','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- I-EA ---U ---- HTCN ----\n", + "letters = ['','O', 'I','','E','A', 'U', '','', 'H','T','C','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- I-EA ---U ---- TSRN ----\n", + "letters = ['','O', 'I','','E','A', 'U', '','', 'T','S','R','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- I-EA ---U ---- TSNR ----\n", + "letters = ['','O', 'I','','E','A', 'U', '','', 'T','S','N','R', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# --O- -IEA ---U ---- HTSN ----\n", + "letters = ['','O', '','I','E','A', 'U', '','', 'H','T','S','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- -IEA ---U ---- HTCN ----\n", + "letters = ['','O', '','I','E','A', 'U', '','', 'H','T','C','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- -IEA ---U ---- TSRN ----\n", + "letters = ['','O', '','I','E','A', 'U', '','', 'T','S','R','N', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- -IEA ---U ---- TSNR ----\n", + "letters = ['','O', '','I','E','A', 'U', '','', 'T','S','N','R', '']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys16, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Top-scoring layouts with the most frequent letters\n", + "\n", + "Each result below represents the top-scoring layout for one of the 16 vowel/consonant initializations above:\n", + "\n", + " Topmost of 120 permutations: 0.10354632973004214\n", + " ['O' 'U' 'I' 'C' 'E' 'A' 'D' 'M' 'L' 'H' 'T' 'S' 'N' 'R']\n", + " Topmost of 120 permutations: 0.1034637534264725\n", + " ['O' 'U' 'I' 'S' 'E' 'A' 'D' 'L' 'M' 'H' 'T' 'C' 'N' 'R']\n", + " Topmost of 120 permutations: 0.10431198384100161\n", + " ['O' 'U' 'I' 'H' 'E' 'A' 'D' 'C' 'L' 'T' 'S' 'R' 'N' 'M']\n", + " Topmost of 120 permutations: 0.10433967881938948\n", + " ['O' 'U' 'I' 'H' 'E' 'A' 'D' 'C' 'L' 'T' 'S' 'N' 'R' 'M']\n", + " Topmost of 120 permutations: 0.10367502054396106\n", + " ['C' 'U' 'I' 'O' 'E' 'A' 'D' 'M' 'L' 'H' 'T' 'S' 'N' 'R']\n", + " Topmost of 120 permutations: 0.10312811950603755\n", + " ['M' 'U' 'I' 'O' 'E' 'A' 'D' 'L' 'S' 'H' 'T' 'C' 'N' 'R']\n", + " Topmost of 120 permutations: 0.103800444248957\n", + " ['H' 'U' 'I' 'O' 'E' 'A' 'D' 'C' 'L' 'T' 'S' 'R' 'N' 'M']\n", + " Topmost of 120 permutations: 0.10382813922734487\n", + " ['H' 'U' 'I' 'O' 'E' 'A' 'D' 'C' 'L' 'T' 'S' 'N' 'R' 'M']\n", + " Topmost of 120 permutations: 0.10350129337069507\n", + " ['C' 'M' 'I' 'O' 'E' 'A' 'U' 'D' 'L' 'H' 'T' 'S' 'N' 'R']\n", + " Topmost of 120 permutations: 0.10289025726759064\n", + " ['D' 'M' 'I' 'O' 'E' 'A' 'U' 'L' 'S' 'H' 'T' 'C' 'N' 'R']\n", + " Topmost of 120 permutations: 0.10363099824178612\n", + " ['H' 'M' 'I' 'O' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'R' 'N' 'D']\n", + " Topmost of 120 permutations: 0.10365869322017397\n", + " ['H' 'M' 'I' 'O' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'N' 'R' 'D']\n", + " Topmost of 120 permutations: 0.10334836255362674\n", + " ['O' 'M' 'I' 'C' 'E' 'A' 'U' 'D' 'L' 'H' 'T' 'S' 'N' 'R']\n", + " Topmost of 120 permutations: 0.10325469239888893\n", + " ['O' 'M' 'I' 'S' 'E' 'A' 'U' 'D' 'L' 'H' 'T' 'C' 'N' 'R']\n", + " Topmost of 120 permutations: 0.1040847131637929\n", + " ['O' 'M' 'I' 'H' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'R' 'N' 'D']\n", + " Topmost of 120 permutations: 0.10411240814218077\n", + " ['O' 'M' 'I' 'H' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'N' 'R' 'D']\n", + " Topmost of 120 permutations: 0.1036874236589209\n", + " ['C' 'O' 'I' 'R' 'E' 'A' 'U' 'D' 'L' 'H' 'T' 'S' 'N' 'M']\n", + " Topmost of 120 permutations: 0.10341981245057436\n", + " ['M' 'O' 'I' 'S' 'E' 'A' 'U' 'D' 'L' 'H' 'T' 'C' 'N' 'R']\n", + " Topmost of 120 permutations: 0.10426359859556522\n", + " ['M' 'O' 'I' 'H' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'R' 'N' 'D']\n", + " Topmost of 120 permutations: 0.10429129357395309\n", + " ['M' 'O' 'I' 'H' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'N' 'R' 'D']\n", + " Topmost of 120 permutations: 0.10358961876200685\n", + " ['C' 'O' 'R' 'I' 'E' 'A' 'U' 'D' 'L' 'H' 'T' 'S' 'N' 'M']\n", + " Topmost of 120 permutations: 0.10324874217517697\n", + " ['M' 'O' 'S' 'I' 'E' 'A' 'U' 'D' 'L' 'H' 'T' 'C' 'N' 'R']\n", + " Topmost of 120 permutations: 0.10426111283602428\n", + " ['M' 'O' 'H' 'I' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'R' 'N' 'D']\n", + " Topmost of 120 permutations: 0.10428880781441215\n", + " ['M' 'O' 'H' 'I' 'E' 'A' 'U' 'C' 'L' 'T' 'S' 'N' 'R' 'D']\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Least frequent, non-little-finger letters\n", + "Second, we will compute scores for every possible arrangement of the 6 next frequent letters in bold below for the least comfortable, remaining non-little-finger positions (4,10,11, and 13,22,23), after substituting in the results above:\n", + "\n", + "E, T, A, O, I, N, S, R, H, L, D, C, U, M, **F, P, G, W, Y, B**, V, K, X, J, Q, Z\n", + "\n", + " Hand 1: Hand 2:\n", + " - x x 4 13 x x -\n", + " x x x x x x x x\n", + " - 10 11 x x 22 23 - \n", + "\n", + "Since there are 6! = 720 possible combinations, and we have 24 layouts, we need to score and evaluate 17,280 combinations." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Topmost of 720 permutations: 0.06059097992127725\n", + "['O' 'U' 'P' 'I' 'C' 'E' 'A' 'G' 'Y' 'D' 'B' 'M' 'L' 'H' 'T' 'S' 'N' 'R'\n", + " 'W' 'F']\n", + "Topmost of 720 permutations: 0.06054988388256497\n", + "['O' 'U' 'F' 'I' 'S' 'E' 'A' 'G' 'Y' 'D' 'B' 'L' 'M' 'H' 'T' 'C' 'N' 'R'\n", + " 'W' 'P']\n", + "Topmost of 720 permutations: 0.06095871482723801\n", + "['O' 'U' 'P' 'I' 'H' 'E' 'A' 'B' 'Y' 'D' 'G' 'C' 'L' 'T' 'S' 'R' 'N' 'M'\n", + " 'F' 'W']\n", + "Topmost of 720 permutations: 0.06094461680728127\n", + "['O' 'U' 'P' 'I' 'H' 'E' 'A' 'G' 'Y' 'D' 'F' 'C' 'L' 'T' 'S' 'N' 'R' 'M'\n", + " 'W' 'B']\n", + "Topmost of 720 permutations: 0.06065744446856356\n", + "['C' 'U' 'G' 'I' 'O' 'E' 'A' 'P' 'Y' 'D' 'B' 'M' 'L' 'H' 'T' 'S' 'N' 'R'\n", + " 'W' 'F']\n", + "Topmost of 720 permutations: 0.06038342454252149\n", + "['M' 'U' 'G' 'I' 'O' 'E' 'A' 'W' 'Y' 'D' 'B' 'L' 'S' 'H' 'T' 'C' 'N' 'R'\n", + " 'F' 'P']\n", + "Topmost of 720 permutations: 0.06070105942147268\n", + "['H' 'U' 'P' 'I' 'O' 'E' 'A' 'B' 'Y' 'D' 'G' 'C' 'L' 'T' 'S' 'R' 'N' 'M'\n", + " 'F' 'W']\n", + "Topmost of 720 permutations: 0.06070489065942671\n", + "['H' 'U' 'G' 'I' 'O' 'E' 'A' 'P' 'Y' 'D' 'F' 'C' 'L' 'T' 'S' 'N' 'R' 'M'\n", + " 'W' 'B']\n", + "Topmost of 720 permutations: 0.06057313695315791\n", + "['C' 'M' 'Y' 'I' 'O' 'E' 'A' 'G' 'W' 'U' 'B' 'D' 'L' 'H' 'T' 'S' 'N' 'R'\n", + " 'P' 'F']\n", + "Topmost of 720 permutations: 0.06027758538670779\n", + "['D' 'M' 'Y' 'I' 'O' 'E' 'A' 'G' 'W' 'U' 'B' 'L' 'S' 'H' 'T' 'C' 'N' 'R'\n", + " 'F' 'P']\n", + "Topmost of 720 permutations: 0.060586538626395736\n", + "['H' 'M' 'G' 'I' 'O' 'E' 'A' 'B' 'Y' 'U' 'P' 'C' 'L' 'T' 'S' 'R' 'N' 'D'\n", + " 'F' 'W']\n", + "Topmost of 720 permutations: 0.060626747095398434\n", + "['H' 'M' 'G' 'I' 'O' 'E' 'A' 'B' 'Y' 'U' 'P' 'C' 'L' 'T' 'S' 'N' 'R' 'D'\n", + " 'F' 'W']\n", + "Topmost of 720 permutations: 0.06049515131520192\n", + "['O' 'M' 'W' 'I' 'C' 'E' 'A' 'G' 'Y' 'U' 'B' 'D' 'L' 'H' 'T' 'S' 'N' 'R'\n", + " 'P' 'F']\n", + "Topmost of 720 permutations: 0.060456852517911275\n", + "['O' 'M' 'W' 'I' 'S' 'E' 'A' 'G' 'Y' 'U' 'B' 'D' 'L' 'H' 'T' 'C' 'N' 'R'\n", + " 'F' 'P']\n", + "Topmost of 720 permutations: 0.06081357762684941\n", + "['O' 'M' 'F' 'I' 'H' 'E' 'A' 'B' 'Y' 'U' 'G' 'C' 'L' 'T' 'S' 'R' 'N' 'D'\n", + " 'W' 'P']\n", + "Topmost of 720 permutations: 0.060842965093341965\n", + "['O' 'M' 'F' 'I' 'H' 'E' 'A' 'G' 'Y' 'U' 'P' 'C' 'L' 'T' 'S' 'N' 'R' 'D'\n", + " 'W' 'B']\n", + "Topmost of 720 permutations: 0.06066047894329213\n", + "['C' 'O' 'W' 'I' 'R' 'E' 'A' 'B' 'Y' 'U' 'G' 'D' 'L' 'H' 'T' 'S' 'N' 'M'\n", + " 'P' 'F']\n", + "Topmost of 720 permutations: 0.06055514669032194\n", + "['M' 'O' 'W' 'I' 'S' 'E' 'A' 'G' 'Y' 'U' 'B' 'D' 'L' 'H' 'T' 'C' 'N' 'R'\n", + " 'F' 'P']\n", + "Topmost of 720 permutations: 0.060921449687836055\n", + "['M' 'O' 'F' 'I' 'H' 'E' 'A' 'B' 'Y' 'U' 'G' 'C' 'L' 'T' 'S' 'R' 'N' 'D'\n", + " 'W' 'P']\n", + "Topmost of 720 permutations: 0.0609480043019952\n", + "['M' 'O' 'F' 'I' 'H' 'E' 'A' 'G' 'Y' 'U' 'P' 'C' 'L' 'T' 'S' 'N' 'R' 'D'\n", + " 'W' 'B']\n", + "Topmost of 720 permutations: 0.06059194910263152\n", + "['C' 'O' 'W' 'R' 'I' 'E' 'A' 'B' 'Y' 'U' 'G' 'D' 'L' 'H' 'T' 'S' 'N' 'M'\n", + " 'P' 'F']\n", + "Topmost of 720 permutations: 0.06045079648353467\n", + "['M' 'O' 'Y' 'S' 'I' 'E' 'A' 'W' 'G' 'U' 'B' 'D' 'L' 'H' 'T' 'C' 'N' 'R'\n", + " 'F' 'P']\n", + "Topmost of 720 permutations: 0.06090265938927255\n", + "['M' 'O' 'P' 'H' 'I' 'E' 'A' 'B' 'Y' 'U' 'G' 'C' 'L' 'T' 'S' 'R' 'N' 'D'\n", + " 'F' 'W']\n", + "Topmost of 720 permutations: 0.06092982031337283\n", + "['M' 'O' 'Y' 'H' 'I' 'E' 'A' 'B' 'G' 'U' 'P' 'C' 'L' 'T' 'S' 'N' 'R' 'D'\n", + " 'F' 'W']\n" + ] + } + ], + "source": [ + "data_matrix = Factors24x24\n", + "keys20 = [2,3,4, 5,6,7,8, 10,11,12, 13,14,15, 17,18,19,20, 21,22,23]\n", + "letters24 = ['E','T','A','O','I','N','S','R','H','L','D','C','U','M','F','P','G','W','Y','B','V','K','X','J']\n", + "verbose = False\n", + "ntop = 0\n", + "\n", + "# -OU- I-EA ---- ---- HTSN ----\n", + "letters = ['O','U','', 'I','C','E','A', '','','D', '','M','L', 'H','T','S','N', 'R','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -OU- I-EA ---- ---- HTCN ----\n", + "letters = ['O','U','', 'I','S','E','A', '','','D', '','L','M', 'H','T','C','N', 'R','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -OU- I-EA ---- ---- TSRN ----\n", + "letters = ['O','U','', 'I','H','E','A', '','','D', '','C','L', 'T','S','R','N', 'M','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -OU- I-EA ---- ---- TSNR ----\n", + "letters = ['O','U','', 'I','H','E','A', '','','D', '','C','L', 'T','S','N','R', 'M','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# --U- IOEA ---- ---- HTSN ----\n", + "letters = ['C','U','', 'I','O','E','A', '','','D', '','M','L', 'H','T','S','N', 'R','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --U- IOEA ---- ---- HTCN ----\n", + "letters = ['M','U','', 'I','O','E','A', '','','D', '','L','S', 'H','T','C','N', 'R','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --U- IOEA ---- ---- TSRN ----\n", + "letters = ['H','U','', 'I','O','E','A', '','','D', '','C','L', 'T','S','R','N', 'M','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --U- IOEA ---- ---- TSNR ----\n", + "letters = ['H','U','', 'I','O','E','A', '','','D', '','C','L', 'T','S','N','R', 'M','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# ---- IOEA ---U ---- HTSN ----\n", + "letters = ['C','M','', 'I','O','E','A', '','','U', '','D','L', 'H','T','S','N', 'R','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# ---- IOEA ---U ---- HTCN ----\n", + "letters = ['D','M','', 'I','O','E','A', '','','U', '','L','S', 'H','T','C','N', 'R','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# ---- IOEA ---U ---- TSRN ----\n", + "letters = ['H','M','', 'I','O','E','A', '','','U', '','C','L', 'T','S','R','N', 'D','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# ---- IOEA ---U ---- TSNR ----\n", + "letters = ['H','M','', 'I','O','E','A', '','','U', '','C','L', 'T','S','N','R', 'D','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# -O-- I-EA ---U ---- HTSN ----\n", + "letters = ['O','M','', 'I','C','E','A', '','','U', '','D','L', 'H','T','S','N', 'R','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -O-- I-EA ---U ---- HTCN ----\n", + "letters = ['O','M','', 'I','S','E','A', '','','U', '','D','L', 'H','T','C','N', 'R','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -O-- I-EA ---U ---- TSRN ----\n", + "letters = ['O','M','', 'I','H','E','A', '','','U', '','C','L', 'T','S','R','N', 'D','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -O-- I-EA ---U ---- TSNR ----\n", + "letters = ['O','M','', 'I','H','E','A', '','','U', '','C','L', 'T','S','N','R', 'D','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# --O- I-EA ---U ---- HTSN ----\n", + "letters = ['C','O','', 'I','R','E','A', '','','U', '','D','L', 'H','T','S','N', 'M','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- I-EA ---U ---- HTCN ----\n", + "letters = ['M','O','', 'I','S','E','A', '','','U', '','D','L', 'H','T','C','N', 'R','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- I-EA ---U ---- TSRN ----\n", + "letters = ['M','O','', 'I','H','E','A', '','','U', '','C','L', 'T','S','R','N', 'D','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- I-EA ---U ---- TSNR ----\n", + "letters = ['M','O','', 'I','H','E','A', '','','U', '','C','L', 'T','S','N','R', 'D','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# --O- -IEA ---U ---- HTSN ----\n", + "letters = ['C','O','', 'R','I','E','A', '','','U', '','D','L', 'H','T','S','N', 'M','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- -IEA ---U ---- HTCN ----\n", + "letters = ['M','O','', 'S','I','E','A', '','','U', '','D','L', 'H','T','C','N', 'R','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- -IEA ---U ---- TSRN ----\n", + "letters = ['M','O','', 'H','I','E','A', '','','U', '','C','L', 'T','S','R','N', 'D','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- -IEA ---U ---- TSNR ----\n", + "letters = ['M','O','', 'H','I','E','A', '','','U', '','C','L', 'T','S','N','R', 'D','','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys20, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Least frequent, little-finger letters\n", + "Third, we will compute scores for every possible arrangement of the least frequent letters (aside from Q and Z) in bold below for the least comfortable remaining positions (1,9, and 16,24), after substituting in the results above:\n", + "\n", + "E, T, A, O, I, N, S, R, H, L, D, C, U, M, F, P, G, W, Y, B, **V, K, X, J**, Q, Z\n", + "\n", + " Hand 1: Hand 2:\n", + " 1 x x x x x x 16\n", + " x x x x x x x x\n", + " 9 x x x x x x 24 \n", + "\n", + "Since there are 4! = 24 possible combinations, and we have 24 layouts, we need to score and evaluate 576 combinations." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Topmost of 24 permutations: 0.04386188325527588\n", + "['J' 'O' 'U' 'P' 'I' 'C' 'E' 'A' 'K' 'G' 'Y' 'D' 'B' 'M' 'L' 'X' 'H' 'T'\n", + " 'S' 'N' 'R' 'W' 'F' 'V']\n", + "Topmost of 24 permutations: 0.04537998980085214\n", + "['X' 'O' 'U' 'P' 'I' 'S' 'E' 'A' 'K' 'G' 'Y' 'D' 'B' 'L' 'M' 'V' 'H' 'T'\n", + " 'C' 'N' 'R' 'W' 'P' 'F']\n", + "Topmost of 24 permutations: 0.044122306597775926\n", + "['J' 'O' 'U' 'P' 'I' 'H' 'E' 'A' 'K' 'B' 'Y' 'D' 'G' 'C' 'L' 'X' 'T' 'S'\n", + " 'R' 'N' 'M' 'F' 'W' 'V']\n", + "Topmost of 24 permutations: 0.04411397824123789\n", + "['J' 'O' 'U' 'P' 'I' 'H' 'E' 'A' 'K' 'G' 'Y' 'D' 'F' 'C' 'L' 'X' 'T' 'S'\n", + " 'N' 'R' 'M' 'W' 'B' 'V']\n", + "Topmost of 24 permutations: 0.04390375268960288\n", + "['J' 'C' 'U' 'G' 'I' 'O' 'E' 'A' 'K' 'P' 'Y' 'D' 'B' 'M' 'L' 'X' 'H' 'T'\n", + " 'S' 'N' 'R' 'W' 'F' 'V']\n", + "Topmost of 24 permutations: 0.04371759133567598\n", + "['J' 'M' 'U' 'G' 'I' 'O' 'E' 'A' 'K' 'W' 'Y' 'D' 'B' 'L' 'S' 'X' 'H' 'T'\n", + " 'C' 'N' 'R' 'F' 'P' 'V']\n", + "Topmost of 24 permutations: 0.043943671402986856\n", + "['J' 'H' 'U' 'P' 'I' 'O' 'E' 'A' 'K' 'B' 'Y' 'D' 'G' 'C' 'L' 'X' 'T' 'S'\n", + " 'R' 'N' 'M' 'F' 'W' 'V']\n", + "Topmost of 24 permutations: 0.043947725277342614\n", + "['J' 'H' 'U' 'G' 'I' 'O' 'E' 'A' 'K' 'P' 'Y' 'D' 'F' 'C' 'L' 'X' 'T' 'S'\n", + " 'N' 'R' 'M' 'W' 'B' 'V']\n", + "Topmost of 24 permutations: 0.043837241835192456\n", + "['J' 'C' 'M' 'Y' 'I' 'O' 'E' 'A' 'K' 'G' 'W' 'U' 'B' 'D' 'L' 'X' 'H' 'T'\n", + " 'S' 'N' 'R' 'P' 'F' 'V']\n", + "Topmost of 24 permutations: 0.043642061019609484\n", + "['J' 'D' 'M' 'Y' 'I' 'O' 'E' 'A' 'K' 'G' 'W' 'U' 'B' 'L' 'S' 'X' 'H' 'T'\n", + " 'C' 'N' 'R' 'F' 'P' 'V']\n", + "Topmost of 24 permutations: 0.04386153892070535\n", + "['J' 'H' 'M' 'G' 'I' 'O' 'E' 'A' 'K' 'B' 'Y' 'U' 'P' 'C' 'L' 'X' 'T' 'S'\n", + " 'R' 'N' 'D' 'F' 'W' 'V']\n", + "Topmost of 24 permutations: 0.04388871885019119\n", + "['J' 'H' 'M' 'G' 'I' 'O' 'E' 'A' 'K' 'B' 'Y' 'U' 'P' 'C' 'L' 'X' 'T' 'S'\n", + " 'N' 'R' 'D' 'F' 'W' 'V']\n", + "Topmost of 24 permutations: 0.04378742675546332\n", + "['J' 'O' 'M' 'W' 'I' 'C' 'E' 'A' 'K' 'G' 'Y' 'U' 'B' 'D' 'L' 'X' 'H' 'T'\n", + " 'S' 'N' 'R' 'P' 'F' 'V']\n", + "Topmost of 24 permutations: 0.04376325294473924\n", + "['J' 'O' 'M' 'W' 'I' 'S' 'E' 'A' 'K' 'G' 'Y' 'U' 'B' 'D' 'L' 'X' 'H' 'T'\n", + " 'C' 'N' 'R' 'F' 'P' 'V']\n", + "Topmost of 24 permutations: 0.044014573433390734\n", + "['J' 'O' 'M' 'F' 'I' 'H' 'E' 'A' 'K' 'B' 'Y' 'U' 'G' 'C' 'L' 'X' 'T' 'S'\n", + " 'R' 'N' 'D' 'W' 'P' 'V']\n", + "Topmost of 24 permutations: 0.044040828070154275\n", + "['J' 'O' 'M' 'F' 'I' 'H' 'E' 'A' 'K' 'G' 'Y' 'U' 'P' 'C' 'L' 'X' 'T' 'S'\n", + " 'N' 'R' 'D' 'W' 'B' 'V']\n", + "Topmost of 24 permutations: 0.043894526542958195\n", + "['J' 'C' 'O' 'W' 'I' 'R' 'E' 'A' 'K' 'B' 'Y' 'U' 'G' 'D' 'L' 'X' 'H' 'T'\n", + " 'S' 'N' 'M' 'P' 'F' 'V']\n", + "Topmost of 24 permutations: 0.0438315127866911\n", + "['J' 'M' 'O' 'W' 'I' 'S' 'E' 'A' 'K' 'G' 'Y' 'U' 'B' 'D' 'L' 'X' 'H' 'T'\n", + " 'C' 'N' 'R' 'F' 'P' 'V']\n", + "Topmost of 24 permutations: 0.04408948458685367\n", + "['J' 'M' 'O' 'F' 'I' 'H' 'E' 'A' 'K' 'B' 'Y' 'U' 'G' 'C' 'L' 'X' 'T' 'S'\n", + " 'R' 'N' 'D' 'W' 'P' 'V']\n", + "Topmost of 24 permutations: 0.04411377196505236\n", + "['J' 'M' 'O' 'F' 'I' 'H' 'E' 'A' 'K' 'G' 'Y' 'U' 'P' 'C' 'L' 'X' 'T' 'S'\n", + " 'N' 'R' 'D' 'W' 'B' 'V']\n", + "Topmost of 24 permutations: 0.04385282966215732\n", + "['J' 'C' 'O' 'W' 'R' 'I' 'E' 'A' 'K' 'B' 'Y' 'U' 'G' 'D' 'L' 'X' 'H' 'T'\n", + " 'S' 'N' 'M' 'P' 'F' 'V']\n", + "Topmost of 24 permutations: 0.0437633589738791\n", + "['J' 'M' 'O' 'Y' 'S' 'I' 'E' 'A' 'K' 'W' 'G' 'U' 'B' 'D' 'L' 'X' 'H' 'T'\n", + " 'C' 'N' 'R' 'F' 'P' 'V']\n", + "Topmost of 24 permutations: 0.044090508241772575\n", + "['J' 'M' 'O' 'P' 'H' 'I' 'E' 'A' 'K' 'B' 'Y' 'U' 'G' 'C' 'L' 'X' 'T' 'S'\n", + " 'R' 'N' 'D' 'F' 'W' 'V']\n", + "Topmost of 24 permutations: 0.044108443462888704\n", + "['J' 'M' 'O' 'Y' 'H' 'I' 'E' 'A' 'K' 'B' 'G' 'U' 'P' 'C' 'L' 'X' 'T' 'S'\n", + " 'N' 'R' 'D' 'F' 'W' 'V']\n" + ] + } + ], + "source": [ + "data_matrix = Factors24x24\n", + "keys24 = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16, 17,18,19,20, 21,22,23,24]\n", + "letters24 = ['E','T','A','O','I','N','S','R','H','L','D','C','U','M','F','P','G','W','Y','B','V','K','X','J']\n", + "verbose = False\n", + "ntop = 0\n", + "\n", + "# -OU- I-EA ---- ---- HTSN ----\n", + "letters = ['','O','U','P', 'I','C','E','A', '','G','Y','D', 'B','M','L','', 'H','T','S','N', 'R','W','F','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -OU- I-EA ---- ---- HTCN ----\n", + "letters = ['','O','U','P', 'I','S','E','A', '','G','Y','D', 'B','L','M','', 'H','T','C','N', 'R','W','P','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -OU- I-EA ---- ---- TSRN ----\n", + "letters = ['','O','U','P', 'I','H','E','A', '','B','Y','D', 'G','C','L','', 'T','S','R','N', 'M','F','W','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -OU- I-EA ---- ---- TSNR ----\n", + "letters = ['','O','U','P', 'I','H','E','A', '','G','Y','D', 'F','C','L','', 'T','S','N','R', 'M','W','B','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# --U- IOEA ---- ---- HTSN ----\n", + "letters = ['','C','U','G', 'I','O','E','A', '','P','Y','D', 'B','M','L','', 'H','T','S','N', 'R','W','F','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --U- IOEA ---- ---- HTCN ----\n", + "letters = ['','M','U','G', 'I','O','E','A', '','W','Y','D', 'B','L','S','', 'H','T','C','N', 'R','F','P','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --U- IOEA ---- ---- TSRN ----\n", + "letters = ['','H','U','P', 'I','O','E','A', '','B','Y','D', 'G','C','L','', 'T','S','R','N', 'M','F','W','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --U- IOEA ---- ---- TSNR ----\n", + "letters = ['','H','U','G', 'I','O','E','A', '','P','Y','D', 'F','C','L','', 'T','S','N','R', 'M','W','B','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# ---- IOEA ---U ---- HTSN ----\n", + "letters = ['','C','M','Y', 'I','O','E','A', '','G','W','U', 'B','D','L','', 'H','T','S','N', 'R','P','F','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# ---- IOEA ---U ---- HTCN ----\n", + "letters = ['','D','M','Y', 'I','O','E','A', '','G','W','U', 'B','L','S','', 'H','T','C','N', 'R','F','P','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# ---- IOEA ---U ---- TSRN ----\n", + "letters = ['','H','M','G', 'I','O','E','A', '','B','Y','U', 'P','C','L','', 'T','S','R','N', 'D','F','W','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# ---- IOEA ---U ---- TSNR ----\n", + "letters = ['','H','M','G', 'I','O','E','A', '','B','Y','U', 'P','C','L','', 'T','S','N','R', 'D','F','W','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# -O-- I-EA ---U ---- HTSN ----\n", + "letters = ['','O','M','W', 'I','C','E','A', '','G','Y','U', 'B','D','L','', 'H','T','S','N', 'R','P','F','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -O-- I-EA ---U ---- HTCN ----\n", + "letters = ['','O','M','W', 'I','S','E','A', '','G','Y','U', 'B','D','L','', 'H','T','C','N', 'R','F','P','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -O-- I-EA ---U ---- TSRN ----\n", + "letters = ['','O','M','F', 'I','H','E','A', '','B','Y','U', 'G','C','L','', 'T','S','R','N', 'D','W','P','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# -O-- I-EA ---U ---- TSNR ----\n", + "letters = ['','O','M','F', 'I','H','E','A', '','G','Y','U', 'P','C','L','', 'T','S','N','R', 'D','W','B','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# --O- I-EA ---U ---- HTSN ----\n", + "letters = ['','C','O','W', 'I','R','E','A', '','B','Y','U', 'G','D','L','', 'H','T','S','N', 'M','P','F','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- I-EA ---U ---- HTCN ----\n", + "letters = ['','M','O','W', 'I','S','E','A', '','G','Y','U', 'B','D','L','', 'H','T','C','N', 'R','F','P','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- I-EA ---U ---- TSRN ----\n", + "letters = ['','M','O','F', 'I','H','E','A', '','B','Y','U', 'G','C','L','', 'T','S','R','N', 'D','W','P','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- I-EA ---U ---- TSNR ----\n", + "letters = ['','M','O','F', 'I','H','E','A', '','G','Y','U', 'P','C','L','', 'T','S','N','R', 'D','W','B','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "\n", + "\n", + "# --O- -IEA ---U ---- HTSN ----\n", + "letters = ['','C','O','W', 'R','I','E','A', '','B','Y','U', 'G','D','L','', 'H','T','S','N', 'M','P','F','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- -IEA ---U ---- HTCN ----\n", + "letters = ['','M','O','Y', 'S','I','E','A', '','W','G','U', 'B','D','L','', 'H','T','C','N', 'R','F','P','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- -IEA ---U ---- TSRN ----\n", + "letters = ['','M','O','P', 'H','I','E','A', '','B','Y','U', 'G','C','L','', 'T','S','R','N', 'D','F','W','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + "# --O- -IEA ---U ---- TSNR ----\n", + "letters = ['','M','O','Y', 'H','I','E','A', '','B','G','U', 'P','C','L','', 'T','S','N','R', 'D','F','W','']\n", + "top_permutation, letter_permutations, scores = permute_optimize(letters, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Optimized layouts with fixed initializations\n", + "\n", + "Each result below represents the top-scoring layout for one of the 24 vowel/consonant initializations above, sorted by descending score:\n", + "\n", + "E, T, A, O, I, N, **S, R, H, L, D, C**, U, **M**, F, P, G, W, Y, B, V, K, X, J, Q, Z\n", + "\n", + " X O U P B L M V Q\n", + " I S E A H T C N Z\n", + " K G Y D R W P F\n", + "\n", + " J O U P G C L X Q\n", + " I H E A T S R N Z\n", + " K B Y D M F W V\n", + "\n", + " 0.04537998980085214 XOUPISEAKGYDBLMVHTCNRWPF\n", + " 0.044122306597775926 JOUPIHEAKBYDGCLXTSRNMFWV\n", + " 0.04411397824123789 JOUPIHEAKGYDFCLXTSNRMWBV\n", + " 0.04411377196505236 JMOFIHEAKGYUPCLXTSNRDWBV\n", + " 0.044108443462888704 JMOYHIEAKBGUPCLXTSNRDFWV\n", + " 0.044090508241772575 JMOPHIEAKBYUGCLXTSRNDFWV\n", + " 0.04408948458685367 JMOFIHEAKBYUGCLXTSRNDWPV\n", + " 0.044040828070154275 JOMFIHEAKGYUPCLXTSNRDWBV\n", + " 0.044014573433390734 JOMFIHEAKBYUGCLXTSRNDWPV\n", + " 0.043947725277342614 JHUGIOEAKPYDFCLXTSNRMWBV\n", + " 0.043943671402986856 JHUPIOEAKBYDGCLXTSRNMFWV\n", + " 0.04390375268960288 JCUGIOEAKPYDBMLXHTSNRWFV\n", + " 0.043894526542958195 JCOWIREAKBYUGDLXHTSNMPFV\n", + " 0.04388871885019119 JHMGIOEAKBYUPCLXTSNRDFWV\n", + " 0.04386188325527588 JOUPICEAKGYDBMLXHTSNRWFV\n", + " 0.04386153892070535 JHMGIOEAKBYUPCLXTSRNDFWV\n", + " 0.04385282966215732 JCOWRIEAKBYUGDLXHTSNMPFV\n", + " 0.043837241835192456 JCMYIOEAKGWUBDLXHTSNRPFV\n", + " 0.0438315127866911 JMOWISEAKGYUBDLXHTCNRFPV\n", + " 0.04378742675546332 JOMWICEAKGYUBDLXHTSNRPFV\n", + " 0.0437633589738791 JMOYSIEAKWGUBDLXHTCNRFPV\n", + " 0.04376325294473924 JOMWISEAKGYUBDLXHTCNRFPV\n", + " 0.04371759133567598 JMUGIOEAKWYDBLSXHTCNRFPV\n", + " 0.043642061019609484 JDMYIOEAKGWUBLSXHTCNRFPV\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Further optimize layouts by exchanging more letters\n", + "\n", + "If we relax the above fixed initializations and permit further exchange of letters, then we can search for even higher-scoring layouts. As a final optimization step we exchange letters, eight keys at a time in each of the above 30 layouts, to score a total of 21,772,800 more combinations (this step takes a long time to compute):\n", + "\n", + " 1-6. Exchange letters among non-home rows.\n", + " 1. Allow top and bottom rows to exchange letters on the left. \n", + " 2. Allow top and bottom rows to exchange letters on the right. \n", + " 3. Allow bottom rows to exchange letters.\n", + " 4. Allow top rows to exchange letters.\n", + " 5. Allow top left and bottom right rows to exchange letters. \n", + " 6. Allow top right and bottom left rows to exchange letters.\n", + " 7. Exchange letters in corners.\n", + " 8. Exchange letters in middle columns.\n", + " 9. Exchange letters in the home rows.\n", + " 10-19. Repeat 1-9." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Letters: \n", + "['Y', 'P', 'F', 'X', 'I', 'O', 'E', 'A', 'C', 'K', 'J', 'U', 'G', 'D', 'L', 'B', 'H', 'T', 'S', 'N', 'M', 'V', 'W', 'R']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04425243030191234\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'C' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'W' 'R']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04425790255141334\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'C' 'K' 'J' 'F' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04425790255141334\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'C' 'K' 'J' 'F' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04425790255141334\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'C' 'K' 'J' 'F' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04425790255141334\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'C' 'K' 'J' 'F' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044287262007440424\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'G' 'K' 'J' 'D' 'F' 'L' 'C' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.044287262007440424\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'G' 'K' 'J' 'D' 'F' 'L' 'C' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044287262007440424\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'G' 'K' 'J' 'D' 'F' 'L' 'C' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044287262007440424\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'G' 'K' 'J' 'D' 'F' 'L' 'C' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.044326388981555796\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'F' 'L' 'C' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044338195884679035\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'V' 'M' 'C' 'W' 'H' 'T'\n", + " 'S' 'N' 'L' 'B' 'F' 'R']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044338195884679035\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'V' 'M' 'C' 'W' 'H' 'T'\n", + " 'S' 'N' 'L' 'B' 'F' 'R']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044338195884679035\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'V' 'M' 'C' 'W' 'H' 'T'\n", + " 'S' 'N' 'L' 'B' 'F' 'R']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044338195884679035\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'V' 'M' 'C' 'W' 'H' 'T'\n", + " 'S' 'N' 'L' 'B' 'F' 'R']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044338195884679035\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'V' 'M' 'C' 'W' 'H' 'T'\n", + " 'S' 'N' 'L' 'B' 'F' 'R']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.044338195884679035\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'V' 'M' 'C' 'W' 'H' 'T'\n", + " 'S' 'N' 'L' 'B' 'F' 'R']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044338195884679035\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'V' 'M' 'C' 'W' 'H' 'T'\n", + " 'S' 'N' 'L' 'B' 'F' 'R']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044338195884679035\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'V' 'M' 'C' 'W' 'H' 'T'\n", + " 'S' 'N' 'L' 'B' 'F' 'R']\n", + "Letters: \n", + "['Y', 'P', 'F', 'X', 'I', 'O', 'E', 'A', 'H', 'K', 'J', 'U', 'G', 'M', 'D', 'W', 'R', 'T', 'S', 'N', 'C', 'V', 'B', 'L']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04434254699037444\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'M' 'D' 'W' 'R' 'T'\n", + " 'S' 'N' 'C' 'V' 'B' 'L']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04434729174390401\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'C' 'V' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04434729174390401\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'C' 'V' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04434729174390401\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'C' 'V' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04434729174390401\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'C' 'V' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04434746864084635\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'G' 'V' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.04434746864084635\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'G' 'V' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04434746864084635\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'G' 'V' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04435667809851987\n", + "['Y' 'P' 'U' 'X' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'G' 'V' 'D' 'C' 'F' 'T' 'S'\n", + " 'R' 'N' 'L' 'B' 'W' 'M']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.0443580198267655\n", + "['J' 'P' 'U' 'X' 'O' 'I' 'E' 'A' 'H' 'K' 'Y' 'G' 'V' 'D' 'C' 'F' 'T' 'S'\n", + " 'R' 'N' 'L' 'B' 'W' 'M']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04437823558973639\n", + "['J' 'P' 'U' 'X' 'O' 'I' 'E' 'A' 'H' 'K' 'Y' 'G' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04437823558973639\n", + "['J' 'P' 'U' 'X' 'O' 'I' 'E' 'A' 'H' 'K' 'Y' 'G' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04437823558973639\n", + "['J' 'P' 'U' 'X' 'O' 'I' 'E' 'A' 'H' 'K' 'Y' 'G' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04437823558973639\n", + "['J' 'P' 'U' 'X' 'O' 'I' 'E' 'A' 'H' 'K' 'Y' 'G' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044392581471695475\n", + "['J' 'P' 'U' 'X' 'O' 'I' 'E' 'A' 'H' 'K' 'Y' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.044392581471695475\n", + "['J' 'P' 'U' 'X' 'O' 'I' 'E' 'A' 'H' 'K' 'Y' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044392581471695475\n", + "['J' 'P' 'U' 'X' 'O' 'I' 'E' 'A' 'H' 'K' 'Y' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044392581471695475\n", + "['J' 'P' 'U' 'X' 'O' 'I' 'E' 'A' 'H' 'K' 'Y' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Letters: \n", + "['Y', 'P', 'F', 'X', 'I', 'O', 'E', 'A', 'M', 'K', 'J', 'U', 'G', 'D', 'L', 'B', 'H', 'T', 'C', 'N', 'S', 'V', 'W', 'R']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04407502305330888\n", + "['J' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'M' 'K' 'Y' 'F' 'G' 'D' 'L' 'B' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'R']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044085224102073384\n", + "['J' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'M' 'K' 'Y' 'F' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'B' 'R']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044085224102073384\n", + "['J' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'M' 'K' 'Y' 'F' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'B' 'R']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044085224102073384\n", + "['J' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'M' 'K' 'Y' 'F' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'B' 'R']\n", + "5. Allow top left and bottom right rows to exchange letters.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Topmost of 40320 permutations: 0.044085224102073384\n", + "['J' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'M' 'K' 'Y' 'F' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'B' 'R']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04411225862646526\n", + "['J' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'G' 'K' 'Y' 'D' 'F' 'L' 'M' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'B' 'R']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.04411225862646526\n", + "['J' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'G' 'K' 'Y' 'D' 'F' 'L' 'M' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'B' 'R']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04411225862646526\n", + "['J' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'G' 'K' 'Y' 'D' 'F' 'L' 'M' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'B' 'R']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04411225862646526\n", + "['J' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'G' 'K' 'Y' 'D' 'F' 'L' 'M' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'B' 'R']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04415411074534181\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'F' 'L' 'M' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'B' 'R']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044162132214259915\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'B' 'L' 'M' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'F' 'R']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044162132214259915\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'B' 'L' 'M' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'F' 'R']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044162132214259915\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'B' 'L' 'M' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'F' 'R']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044162132214259915\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'B' 'L' 'M' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'F' 'R']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044162132214259915\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'B' 'L' 'M' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'F' 'R']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.044162132214259915\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'B' 'L' 'M' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'F' 'R']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044162132214259915\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'B' 'L' 'M' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'F' 'R']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044162132214259915\n", + "['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'B' 'L' 'M' 'W' 'H' 'T'\n", + " 'C' 'N' 'S' 'V' 'F' 'R']\n", + "Letters: \n", + "['Y', 'P', 'F', 'X', 'I', 'O', 'E', 'A', 'H', 'K', 'J', 'U', 'G', 'M', 'D', 'W', 'R', 'T', 'C', 'N', 'S', 'V', 'B', 'L']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04417708021471907\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'M' 'D' 'W' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'B' 'L']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04418423434796516\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04418423434796516\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04418423434796516\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04418423434796516\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04418423434796516\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.04418423434796516\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04418423434796516\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044192316880743134\n", + "['Y' 'P' 'U' 'X' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'C' 'T'\n", + " 'R' 'N' 'S' 'V' 'W' 'M']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.0441930152502403\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'C' 'T'\n", + " 'R' 'N' 'S' 'V' 'W' 'M']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.0441930152502403\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'C' 'T'\n", + " 'R' 'N' 'S' 'V' 'W' 'M']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.0441930152502403\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'C' 'T'\n", + " 'R' 'N' 'S' 'V' 'W' 'M']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.0441930152502403\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'C' 'T'\n", + " 'R' 'N' 'S' 'V' 'W' 'M']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.0441930152502403\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'C' 'T'\n", + " 'R' 'N' 'S' 'V' 'W' 'M']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.0441930152502403\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'C' 'T'\n", + " 'R' 'N' 'S' 'V' 'W' 'M']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.0441930152502403\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'C' 'T'\n", + " 'R' 'N' 'S' 'V' 'W' 'M']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.0441930152502403\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'C' 'T'\n", + " 'R' 'N' 'S' 'V' 'W' 'M']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.0441930152502403\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'C' 'T'\n", + " 'R' 'N' 'S' 'V' 'W' 'M']\n", + "Letters: \n", + "['Y', 'P', 'F', 'X', 'I', 'O', 'E', 'A', 'H', 'K', 'J', 'U', 'G', 'C', 'M', 'W', 'T', 'S', 'R', 'N', 'D', 'V', 'B', 'L']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04438345122541933\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'M' 'W' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'B' 'L']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04439024138992323\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04439024138992323\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04439024138992323\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04439024138992323\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04439024138992323\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.04439024138992323\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04439024138992323\n", + "['Y' 'P' 'U' 'X' 'I' 'O' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04439191502989607\n", + "['Y' 'P' 'U' 'X' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Topmost of 40320 permutations: 0.04439261339939324\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04439261339939324\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04439261339939324\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04439261339939324\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04439261339939324\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04439261339939324\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.04439261339939324\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04439261339939324\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04439261339939324\n", + "['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Letters: \n", + "['Y', 'O', 'F', 'K', 'I', 'C', 'E', 'A', 'P', 'X', 'J', 'U', 'G', 'D', 'L', 'B', 'H', 'T', 'S', 'N', 'M', 'V', 'W', 'R']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04421851662375003\n", + "['Y' 'F' 'O' 'X' 'I' 'C' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'D' 'L' 'B' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'W' 'R']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04422398887325104\n", + "['Y' 'F' 'O' 'X' 'I' 'C' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04422398887325104\n", + "['Y' 'F' 'O' 'X' 'I' 'C' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04426813301343301\n", + "['Y' 'G' 'O' 'X' 'I' 'C' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04426813301343301\n", + "['Y' 'G' 'O' 'X' 'I' 'C' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04426813301343301\n", + "['Y' 'G' 'O' 'X' 'I' 'C' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.04426813301343301\n", + "['Y' 'G' 'O' 'X' 'I' 'C' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04426813301343301\n", + "['Y' 'G' 'O' 'X' 'I' 'C' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04432628779506045\n", + "['Y' 'G' 'O' 'X' 'H' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04434177448844831\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Letters: \n", + "['Y', 'O', 'F', 'X', 'I', 'H', 'E', 'A', 'P', 'K', 'J', 'U', 'G', 'M', 'D', 'W', 'R', 'T', 'S', 'N', 'C', 'V', 'B', 'L']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.044403150561759266\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'M' 'D' 'W' 'R' 'T'\n", + " 'S' 'N' 'C' 'V' 'B' 'L']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04440789531528883\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'D' 'C' 'V' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04440789531528883\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'D' 'C' 'V' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04443426457654777\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'V' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04443426457654777\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'V' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04443426457654777\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'V' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.04443426457654777\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'V' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04443426457654777\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'V' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04446396141033257\n", + "['Y' 'G' 'O' 'X' 'H' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'V' 'D' 'C' 'F' 'T' 'S'\n", + " 'R' 'N' 'L' 'B' 'W' 'M']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04447944810372044\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'C' 'F' 'T' 'S'\n", + " 'R' 'N' 'L' 'B' 'W' 'M']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044506277642691744\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'W' 'M']\n", + "Letters: \n", + "['Y', 'O', 'F', 'X', 'I', 'S', 'E', 'A', 'P', 'K', 'J', 'U', 'G', 'D', 'L', 'W', 'H', 'T', 'C', 'N', 'M', 'V', 'B', 'R']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.044148427246613386\n", + "['Y' 'F' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'D' 'L' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04416182881840806\n", + "['Y' 'F' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04416182881840806\n", + "['Y' 'F' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044200415547256\n", + "['Y' 'G' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044200415547256\n", + "['Y' 'G' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044200415547256\n", + "['Y' 'G' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.044200415547256\n", + "['Y' 'G' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044200415547256\n", + "['Y' 'G' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04432628779506045\n", + "['Y' 'G' 'O' 'X' 'H' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04434177448844831\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Letters: \n", + "['Y', 'O', 'F', 'X', 'I', 'H', 'E', 'A', 'P', 'K', 'J', 'U', 'G', 'M', 'D', 'W', 'R', 'T', 'C', 'N', 'S', 'V', 'B', 'L']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04423751312062356\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'M' 'D' 'W' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'B' 'L']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04424466725386965\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'D' 'L' 'B' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04424466725386965\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'D' 'L' 'B' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04425566669982141\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'B' 'D' 'L' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04425566669982141\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'B' 'D' 'L' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04425566669982141\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'B' 'D' 'L' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.04425566669982141\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'B' 'D' 'L' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04425566669982141\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'B' 'D' 'L' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04427893156244303\n", + "['Y' 'G' 'O' 'X' 'H' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'B' 'D' 'L' 'F' 'C' 'T'\n", + " 'N' 'R' 'S' 'V' 'W' 'M']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.0442944182558309\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'B' 'D' 'L' 'F' 'C' 'T'\n", + " 'N' 'R' 'S' 'V' 'W' 'M']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Letters: \n", + "['Y', 'O', 'F', 'X', 'I', 'H', 'E', 'A', 'P', 'K', 'J', 'U', 'G', 'C', 'M', 'W', 'T', 'S', 'R', 'N', 'D', 'V', 'B', 'L']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Topmost of 40320 permutations: 0.04444405479680415\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'C' 'M' 'W' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'B' 'L']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04445084496130805\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04445084496130805\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04446201615721932\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04446201615721932\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04446201615721932\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.04446201615721932\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04446201615721932\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04449079094930388\n", + "['Y' 'G' 'O' 'X' 'H' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'W' 'M']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.044506277642691744\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'W' 'M']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Letters: \n", + "['Y', 'F', 'O', 'K', 'I', 'C', 'E', 'A', 'P', 'G', 'J', 'U', 'B', 'D', 'L', 'W', 'H', 'T', 'S', 'N', 'M', 'V', 'X', 'R']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04423221813369335\n", + "['Y' 'G' 'O' 'F' 'I' 'C' 'E' 'A' 'P' 'K' 'J' 'U' 'B' 'D' 'L' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'X' 'R']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044234280881618744\n", + "['Y' 'G' 'O' 'F' 'I' 'C' 'E' 'A' 'P' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'X' 'B' 'R']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044235092064741285\n", + "['Y' 'G' 'O' 'F' 'I' 'C' 'E' 'A' 'P' 'X' 'J' 'U' 'V' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'K' 'B' 'R']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044235092064741285\n", + "['Y' 'G' 'O' 'F' 'I' 'C' 'E' 'A' 'P' 'X' 'J' 'U' 'V' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'K' 'B' 'R']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044267679827038636\n", + "['Y' 'G' 'O' 'K' 'I' 'C' 'E' 'A' 'P' 'X' 'J' 'U' 'V' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'F' 'B' 'R']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044267679827038636\n", + "['Y' 'G' 'O' 'K' 'I' 'C' 'E' 'A' 'P' 'X' 'J' 'U' 'V' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'F' 'B' 'R']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.044267679827038636\n", + "['Y' 'G' 'O' 'K' 'I' 'C' 'E' 'A' 'P' 'X' 'J' 'U' 'V' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'F' 'B' 'R']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044267679827038636\n", + "['Y' 'G' 'O' 'K' 'I' 'C' 'E' 'A' 'P' 'X' 'J' 'U' 'V' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'F' 'B' 'R']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04432194898346079\n", + "['Y' 'G' 'O' 'K' 'H' 'I' 'E' 'A' 'P' 'X' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Letters: \n", + "['Y', 'F', 'O', 'X', 'I', 'H', 'E', 'A', 'P', 'K', 'J', 'U', 'G', 'M', 'D', 'W', 'R', 'T', 'S', 'N', 'C', 'V', 'B', 'L']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.044403150561759266\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'M' 'D' 'W' 'R' 'T'\n", + " 'S' 'N' 'C' 'V' 'B' 'L']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04440789531528883\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'D' 'C' 'V' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04440789531528883\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'D' 'C' 'V' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04443426457654777\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'V' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04443426457654777\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'V' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "6. Allow top right and bottom left rows to exchange letters.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Topmost of 40320 permutations: 0.04443426457654777\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'V' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.04443426457654777\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'V' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04443426457654777\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'V' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'B' 'W' 'M']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04446396141033257\n", + "['Y' 'G' 'O' 'X' 'H' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'V' 'D' 'C' 'F' 'T' 'S'\n", + " 'R' 'N' 'L' 'B' 'W' 'M']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04447944810372044\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'C' 'F' 'T' 'S'\n", + " 'R' 'N' 'L' 'B' 'W' 'M']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044506277642691744\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'W' 'M']\n", + "Letters: \n", + "['Y', 'F', 'O', 'X', 'I', 'S', 'E', 'A', 'P', 'K', 'J', 'U', 'G', 'D', 'L', 'W', 'H', 'T', 'C', 'N', 'M', 'V', 'B', 'R']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.044148427246613386\n", + "['Y' 'F' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'D' 'L' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04416182881840806\n", + "['Y' 'F' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04416182881840806\n", + "['Y' 'F' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044200415547256\n", + "['Y' 'G' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044200415547256\n", + "['Y' 'G' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044200415547256\n", + "['Y' 'G' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.044200415547256\n", + "['Y' 'G' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044200415547256\n", + "['Y' 'G' 'O' 'X' 'I' 'S' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04432628779506045\n", + "['Y' 'G' 'O' 'X' 'H' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04434177448844831\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Letters: \n", + "['Y', 'F', 'O', 'X', 'I', 'H', 'E', 'A', 'P', 'K', 'J', 'U', 'G', 'M', 'D', 'W', 'R', 'T', 'C', 'N', 'S', 'V', 'B', 'L']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04423751312062356\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'M' 'D' 'W' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'B' 'L']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04424466725386965\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'D' 'L' 'B' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04424466725386965\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'D' 'L' 'B' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04425566669982141\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'B' 'D' 'L' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04425566669982141\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'B' 'D' 'L' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04425566669982141\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'B' 'D' 'L' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.04425566669982141\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'B' 'D' 'L' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04425566669982141\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'B' 'D' 'L' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'V' 'W' 'M']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04427893156244303\n", + "['Y' 'G' 'O' 'X' 'H' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'B' 'D' 'L' 'F' 'C' 'T'\n", + " 'N' 'R' 'S' 'V' 'W' 'M']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.0442944182558309\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'B' 'D' 'L' 'F' 'C' 'T'\n", + " 'N' 'R' 'S' 'V' 'W' 'M']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04430674825218268\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T'\n", + " 'N' 'R' 'S' 'B' 'F' 'L']\n", + "Letters: \n", + "['Y', 'F', 'O', 'X', 'I', 'H', 'E', 'A', 'P', 'K', 'J', 'U', 'G', 'C', 'M', 'W', 'T', 'S', 'R', 'N', 'D', 'V', 'B', 'L']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04444405479680415\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'C' 'M' 'W' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'B' 'L']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04445084496130805\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04445084496130805\n", + "['Y' 'F' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04446201615721932\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04446201615721932\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04446201615721932\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.04446201615721932\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04446201615721932\n", + "['Y' 'G' 'O' 'X' 'I' 'H' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04449079094930388\n", + "['Y' 'G' 'O' 'X' 'H' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'W' 'M']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.044506277642691744\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'W' 'M']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Letters: \n", + "['Y', 'F', 'O', 'X', 'C', 'I', 'E', 'A', 'P', 'K', 'J', 'U', 'G', 'D', 'L', 'B', 'H', 'T', 'S', 'N', 'M', 'V', 'W', 'R']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.044185593507059195\n", + "['Y' 'F' 'O' 'X' 'C' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'D' 'L' 'B' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'W' 'R']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044191065756560205\n", + "['Y' 'F' 'O' 'X' 'C' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044191065756560205\n", + "['Y' 'F' 'O' 'X' 'C' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04423609346110916\n", + "['Y' 'G' 'O' 'X' 'C' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04423609346110916\n", + "['Y' 'G' 'O' 'X' 'C' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04423609346110916\n", + "['Y' 'G' 'O' 'X' 'C' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.04423609346110916\n", + "['Y' 'G' 'O' 'X' 'C' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04423609346110916\n", + "['Y' 'G' 'O' 'X' 'C' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'S' 'N' 'M' 'V' 'B' 'R']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04432628779506045\n", + "['Y' 'G' 'O' 'X' 'H' 'I' 'E' 'A' 'P' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04434177448844831\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Letters: \n", + "['Y', 'P', 'O', 'X', 'H', 'I', 'E', 'A', 'D', 'K', 'J', 'U', 'G', 'M', 'C', 'B', 'R', 'T', 'S', 'N', 'L', 'V', 'W', 'F']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.044437536271711986\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'G' 'M' 'C' 'B' 'R' 'T'\n", + " 'S' 'N' 'L' 'V' 'W' 'F']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04444922565495196\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'W' 'G' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'V' 'B' 'M']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04444922565495196\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'W' 'G' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'V' 'B' 'M']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04444922565495196\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'W' 'G' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'V' 'B' 'M']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04444922565495196\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'W' 'G' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'V' 'B' 'M']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044472175864559774\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'W' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'V' 'B' 'M']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.044472175864559774\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'W' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'V' 'B' 'M']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044472175864559774\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'W' 'D' 'C' 'F' 'R' 'T'\n", + " 'S' 'N' 'L' 'V' 'B' 'M']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.0444797003714426\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'W' 'D' 'C' 'F' 'T' 'S'\n", + " 'R' 'N' 'L' 'V' 'B' 'M']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.0444797003714426\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'W' 'D' 'C' 'F' 'T' 'S'\n", + " 'R' 'N' 'L' 'V' 'B' 'M']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044506277642691744\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'W' 'M']\n", + "Letters: \n", + "['K', 'F', 'O', 'Y', 'S', 'I', 'E', 'A', 'P', 'X', 'J', 'U', 'G', 'D', 'L', 'W', 'H', 'T', 'C', 'N', 'M', 'V', 'B', 'R']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.044091018289433126\n", + "['K' 'F' 'O' 'Y' 'S' 'I' 'E' 'A' 'P' 'X' 'J' 'U' 'G' 'D' 'L' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044104419861227796\n", + "['K' 'F' 'O' 'Y' 'S' 'I' 'E' 'A' 'P' 'X' 'J' 'U' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044104419861227796\n", + "['K' 'F' 'O' 'Y' 'S' 'I' 'E' 'A' 'P' 'X' 'J' 'U' 'G' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044145359906558095\n", + "['K' 'G' 'O' 'Y' 'S' 'I' 'E' 'A' 'P' 'X' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044145359906558095\n", + "['K' 'G' 'O' 'Y' 'S' 'I' 'E' 'A' 'P' 'X' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044145359906558095\n", + "['K' 'G' 'O' 'Y' 'S' 'I' 'E' 'A' 'P' 'X' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.044145359906558095\n", + "['K' 'G' 'O' 'Y' 'S' 'I' 'E' 'A' 'P' 'X' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044145359906558095\n", + "['K' 'G' 'O' 'Y' 'S' 'I' 'E' 'A' 'P' 'X' 'J' 'U' 'F' 'L' 'D' 'W' 'H' 'T'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044324962378987705\n", + "['K' 'G' 'O' 'Y' 'H' 'I' 'E' 'A' 'P' 'X' 'J' 'U' 'F' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04434177448844831\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'V' 'B' 'R']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044344387643041445\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S'\n", + " 'C' 'N' 'M' 'F' 'B' 'R']\n", + "Letters: \n", + "['Y', 'P', 'O', 'X', 'H', 'I', 'E', 'A', 'D', 'K', 'J', 'U', 'G', 'M', 'F', 'V', 'R', 'T', 'C', 'N', 'L', 'W', 'B', 'S']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Topmost of 40320 permutations: 0.04427754299588433\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'G' 'M' 'F' 'V' 'R' 'T'\n", + " 'C' 'N' 'L' 'W' 'B' 'S']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04428538234749509\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'W' 'M' 'G' 'F' 'R' 'T'\n", + " 'C' 'N' 'L' 'V' 'B' 'S']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04428538234749509\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'W' 'M' 'G' 'F' 'R' 'T'\n", + " 'C' 'N' 'L' 'V' 'B' 'S']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04428538234749509\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'W' 'M' 'G' 'F' 'R' 'T'\n", + " 'C' 'N' 'L' 'V' 'B' 'S']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04428538234749509\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'W' 'M' 'G' 'F' 'R' 'T'\n", + " 'C' 'N' 'L' 'V' 'B' 'S']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04430562442526073\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'W' 'M' 'D' 'F' 'R' 'T'\n", + " 'C' 'N' 'L' 'V' 'B' 'S']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.04430562442526073\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'W' 'M' 'D' 'F' 'R' 'T'\n", + " 'C' 'N' 'L' 'V' 'B' 'S']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04430562442526073\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'W' 'M' 'D' 'F' 'R' 'T'\n", + " 'C' 'N' 'L' 'V' 'B' 'S']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04430562442526073\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'W' 'M' 'D' 'F' 'R' 'T'\n", + " 'C' 'N' 'L' 'V' 'B' 'S']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04430562442526073\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'W' 'M' 'D' 'F' 'R' 'T'\n", + " 'C' 'N' 'L' 'V' 'B' 'S']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04430774236516413\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'W' 'B' 'M']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04430774236516413\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'W' 'B' 'M']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04430774236516413\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'W' 'B' 'M']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04430774236516413\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'W' 'B' 'M']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04430774236516413\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'W' 'B' 'M']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.04430774236516413\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'W' 'B' 'M']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04430774236516413\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'W' 'B' 'M']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04430774236516413\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'F' 'R' 'T'\n", + " 'C' 'N' 'S' 'W' 'B' 'M']\n", + "Letters: \n", + "['Y', 'P', 'O', 'X', 'H', 'I', 'E', 'A', 'D', 'K', 'J', 'U', 'G', 'C', 'L', 'B', 'T', 'S', 'R', 'N', 'M', 'V', 'W', 'F']\n", + "1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.04448109215769123\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'M' 'V' 'W' 'F']\n", + "2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04448109215769123\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'M' 'V' 'W' 'F']\n", + "3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04448109215769123\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'M' 'V' 'W' 'F']\n", + "4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04448109215769123\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'M' 'V' 'W' 'F']\n", + "5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04448109215769123\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'M' 'V' 'W' 'F']\n", + "6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04448109215769123\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'D' 'K' 'J' 'U' 'G' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'M' 'V' 'W' 'F']\n", + "7. Corners.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "8. Middle columns.\n", + "Topmost of 40320 permutations: 0.044499663866691325\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'R' 'N' 'D' 'V' 'W' 'M']\n", + "9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.044506277642691744\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'W' 'M']\n", + "Repeat: 1. Allow top and bottom rows to exchange letters on the left.\n", + "Topmost of 40320 permutations: 0.044506277642691744\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'W' 'M']\n", + "Repeat: 2. Allow top and bottom rows to exchange letters on the right.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 3. Allow bottom rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 4. Allow top rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 5. Allow top left and bottom right rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 6. Allow top right and bottom left rows to exchange letters.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 7. Corners.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 8. Middle columns.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n", + "Repeat: 9. Left and right home rows.\n", + "Topmost of 40320 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n" + ] + } + ], + "source": [ + "data_matrix = Factors24x24\n", + "keys24 = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16, 17,18,19,20, 21,22,23,24]\n", + "letters24 = ['E','T','A','O','I','N','S','R','H','L','D','C','U','M','F','P','G','W','Y','B','V','K','X','J']\n", + "verbose = False\n", + "ntop = 0\n", + "\n", + "list_of_letters = [['Y','O','U','K','I','C','E','A','P','X','J','D','G','M','F','W','H','T','S','N','L','V','B','R'],\n", + " ['Y','O','U','X','I','H','E','A','P','K','J','D','G','M','C','B','R','T','S','N','L','V','W','F'],\n", + " ['Y','O','U','X','I','S','E','A','P','K','J','D','G','M','F','W','H','T','C','N','L','V','B','R'],\n", + " ['Y','O','U','X','I','H','E','A','P','K','J','D','G','M','F','V','R','T','C','N','L','W','B','S'],\n", + " ['Y','O','U','X','I','H','E','A','P','K','J','D','G','C','L','B','T','S','R','N','M','V','W','F'],\n", + " ['Y','C','U','K','I','O','E','A','P','X','J','F','G','D','L','B','H','T','S','N','M','V','W','R'],\n", + " ['Y','P','U','X','I','O','E','A','H','K','J','F','G','M','D','W','R','T','S','N','C','V','B','L'],\n", + " ['J','P','U','X','I','O','E','A','M','K','Y','F','G','D','L','B','H','T','C','N','S','V','W','R'],\n", + " ['Y','P','U','X','I','O','E','A','H','K','J','F','G','M','D','W','R','T','C','N','S','V','B','L'],\n", + " ['Y','P','U','X','I','O','E','A','H','K','J','F','G','C','M','W','T','S','R','N','D','V','B','L'],\n", + " ['Y','P','F','X','I','O','E','A','C','K','J','U','G','D','L','B','H','T','S','N','M','V','W','R'],\n", + " ['Y','P','F','X','I','O','E','A','H','K','J','U','G','M','D','W','R','T','S','N','C','V','B','L'],\n", + " ['Y','P','F','X','I','O','E','A','M','K','J','U','G','D','L','B','H','T','C','N','S','V','W','R'],\n", + " ['Y','P','F','X','I','O','E','A','H','K','J','U','G','M','D','W','R','T','C','N','S','V','B','L'],\n", + " ['Y','P','F','X','I','O','E','A','H','K','J','U','G','C','M','W','T','S','R','N','D','V','B','L'],\n", + " ['Y','O','F','K','I','C','E','A','P','X','J','U','G','D','L','B','H','T','S','N','M','V','W','R'],\n", + " ['Y','O','F','X','I','H','E','A','P','K','J','U','G','M','D','W','R','T','S','N','C','V','B','L'],\n", + " ['Y','O','F','X','I','S','E','A','P','K','J','U','G','D','L','W','H','T','C','N','M','V','B','R'],\n", + " ['Y','O','F','X','I','H','E','A','P','K','J','U','G','M','D','W','R','T','C','N','S','V','B','L'],\n", + " ['Y','O','F','X','I','H','E','A','P','K','J','U','G','C','M','W','T','S','R','N','D','V','B','L'],\n", + " ['Y','F','O','K','I','C','E','A','P','G','J','U','B','D','L','W','H','T','S','N','M','V','X','R'],\n", + " ['Y','F','O','X','I','H','E','A','P','K','J','U','G','M','D','W','R','T','S','N','C','V','B','L'],\n", + " ['Y','F','O','X','I','S','E','A','P','K','J','U','G','D','L','W','H','T','C','N','M','V','B','R'],\n", + " ['Y','F','O','X','I','H','E','A','P','K','J','U','G','M','D','W','R','T','C','N','S','V','B','L'],\n", + " ['Y','F','O','X','I','H','E','A','P','K','J','U','G','C','M','W','T','S','R','N','D','V','B','L'],\n", + " ['Y','F','O','X','C','I','E','A','P','K','J','U','G','D','L','B','H','T','S','N','M','V','W','R'],\n", + " ['Y','P','O','X','H','I','E','A','D','K','J','U','G','M','C','B','R','T','S','N','L','V','W','F'],\n", + " ['K','F','O','Y','S','I','E','A','P','X','J','U','G','D','L','W','H','T','C','N','M','V','B','R'],\n", + " ['Y','P','O','X','H','I','E','A','D','K','J','U','G','M','F','V','R','T','C','N','L','W','B','S'],\n", + " ['Y','P','O','X','H','I','E','A','D','K','J','U','G','C','L','B','T','S','R','N','M','V','W','F']]\n", + "\n", + "for letters in list_of_letters:\n", + " \n", + " print('Letters: ')\n", + " print(letters) \n", + "\n", + " top_permutation = letters\n", + "\n", + " s = ''\n", + " for i in [1,2]:\n", + " if i == 2:\n", + " s = \"Repeat: \"\n", + " \n", + " print(s + '1. Allow top and bottom rows to exchange letters on the left.') \n", + " top_permutation[0] = ''\n", + " top_permutation[1] = ''\n", + " top_permutation[2] = ''\n", + " top_permutation[3] = ''\n", + " top_permutation[8] = ''\n", + " top_permutation[9] = ''\n", + " top_permutation[10] = ''\n", + " top_permutation[11] = ''\n", + " top_permutation, letter_permutations, scores = permute_optimize(top_permutation, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + " top_permutation = top_permutation.tolist()\n", + "\n", + " print(s + '2. Allow top and bottom rows to exchange letters on the right.')\n", + " top_permutation[12] = ''\n", + " top_permutation[13] = ''\n", + " top_permutation[14] = ''\n", + " top_permutation[15] = ''\n", + " top_permutation[20] = ''\n", + " top_permutation[21] = ''\n", + " top_permutation[22] = ''\n", + " top_permutation[23] = ''\n", + " top_permutation, letter_permutations, scores = permute_optimize(top_permutation, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + " top_permutation = top_permutation.tolist()\n", + "\n", + " print(s + '3. Allow bottom rows to exchange letters.')\n", + " top_permutation[8] = ''\n", + " top_permutation[9] = ''\n", + " top_permutation[10] = ''\n", + " top_permutation[11] = ''\n", + " top_permutation[20] = ''\n", + " top_permutation[21] = ''\n", + " top_permutation[22] = ''\n", + " top_permutation[23] = ''\n", + " top_permutation, letter_permutations, scores = permute_optimize(top_permutation, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + " top_permutation = top_permutation.tolist()\n", + "\n", + " print(s + '4. Allow top rows to exchange letters.')\n", + " top_permutation[0] = ''\n", + " top_permutation[1] = ''\n", + " top_permutation[2] = ''\n", + " top_permutation[3] = ''\n", + " top_permutation[12] = ''\n", + " top_permutation[13] = ''\n", + " top_permutation[14] = ''\n", + " top_permutation[15] = ''\n", + " top_permutation, letter_permutations, scores = permute_optimize(top_permutation, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + " top_permutation = top_permutation.tolist()\n", + "\n", + " print(s + '5. Allow top left and bottom right rows to exchange letters.') \n", + " top_permutation[0] = ''\n", + " top_permutation[1] = ''\n", + " top_permutation[2] = ''\n", + " top_permutation[3] = ''\n", + " top_permutation[20] = ''\n", + " top_permutation[21] = ''\n", + " top_permutation[22] = ''\n", + " top_permutation[23] = ''\n", + " top_permutation, letter_permutations, scores = permute_optimize(top_permutation, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + " top_permutation = top_permutation.tolist()\n", + "\n", + " print(s + '6. Allow top right and bottom left rows to exchange letters.') \n", + " top_permutation[12] = ''\n", + " top_permutation[13] = ''\n", + " top_permutation[14] = ''\n", + " top_permutation[15] = ''\n", + " top_permutation[8] = ''\n", + " top_permutation[9] = ''\n", + " top_permutation[10] = ''\n", + " top_permutation[11] = ''\n", + " top_permutation, letter_permutations, scores = permute_optimize(top_permutation, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + " top_permutation = top_permutation.tolist()\n", + "\n", + " print(s + '7. Corners.') \n", + " top_permutation[0] = ''\n", + " top_permutation[3] = ''\n", + " top_permutation[8] = ''\n", + " top_permutation[11] = ''\n", + " top_permutation[12] = ''\n", + " top_permutation[15] = ''\n", + " top_permutation[20] = ''\n", + " top_permutation[23] = ''\n", + " top_permutation, letter_permutations, scores = permute_optimize(top_permutation, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + " top_permutation = top_permutation.tolist()\n", + "\n", + " print(s + '8. Middle columns.')\n", + " top_permutation[1] = ''\n", + " top_permutation[2] = ''\n", + " top_permutation[9] = ''\n", + " top_permutation[10] = ''\n", + " top_permutation[13] = ''\n", + " top_permutation[14] = ''\n", + " top_permutation[21] = ''\n", + " top_permutation[22] = ''\n", + " top_permutation, letter_permutations, scores = permute_optimize(top_permutation, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + " top_permutation = top_permutation.tolist()\n", + "\n", + " print(s + '9. Left and right home rows.') \n", + " top_permutation[4] = ''\n", + " top_permutation[5] = ''\n", + " top_permutation[6] = ''\n", + " top_permutation[7] = ''\n", + " top_permutation[16] = ''\n", + " top_permutation[17] = ''\n", + " top_permutation[18] = ''\n", + " top_permutation[19] = ''\n", + " top_permutation, letter_permutations, scores = permute_optimize(top_permutation, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n", + " top_permutation = top_permutation.tolist()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Optimized layouts after further exchange of letters (redundancies removed)\n", + "\n", + "The 30 initialized layouts reduce to 11:\n", + "\n", + " Topmost of 40320 permutations: 0.04451764837996277\n", + " ['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S' 'N' 'R' 'D' 'V' 'B' 'L']\n", + " Topmost of 40320 permutations: 0.044506277642691744\n", + " ['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'L' 'B' 'T' 'S' 'N' 'R' 'D' 'V' 'W' 'M']\n", + " Topmost of 40320 permutations: 0.044338195884679035\n", + " ['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'V' 'M' 'C' 'W' 'H' 'T' 'S' 'N' 'L' 'B' 'F' 'R']\n", + " Topmost of 40320 permutations: 0.04439261339939324\n", + " ['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S' 'R' 'N' 'D' 'V' 'W' 'M']\n", + " Topmost of 40320 permutations: 0.044392581471695475\n", + " ['J' 'P' 'U' 'X' 'O' 'I' 'E' 'A' 'H' 'K' 'Y' 'F' 'G' 'C' 'L' 'B' 'T' 'S' 'R' 'N' 'D' 'V' 'W' 'M']\n", + " Topmost of 40320 permutations: 0.044344387643041445\n", + " ['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S' 'C' 'N' 'M' 'F' 'B' 'R']\n", + " Topmost of 40320 permutations: 0.04434220552303007\n", + " ['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'W' 'D' 'L' 'B' 'T' 'C' 'S' 'N' 'M' 'F' 'V' 'R']\n", + " Topmost of 40320 permutations: 0.04430774236516413\n", + " ['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'F' 'R' 'T' 'C' 'N' 'S' 'W' 'B' 'M']\n", + " Topmost of 40320 permutations: 0.04430674825218268\n", + " ['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T' 'N' 'R' 'S' 'B' 'F' 'L']\n", + " Topmost of 40320 permutations: 0.0441930152502403\n", + " ['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'C' 'T' 'R' 'N' 'S' 'V' 'W' 'M']\n", + " Topmost of 40320 permutations: 0.044162132214259915\n", + " ['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'B' 'L' 'M' 'W' 'H' 'T' 'C' 'N' 'S' 'V' 'F' 'R']\n", + "\n", + "These 11 reduce to 9 layouts with unique home key letter assignments:\n", + "\n", + " Topmost of 40320 permutations: 0.04451764837996277\n", + " ['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S' 'N' 'R' 'D' 'V' 'B' 'L']\n", + " Topmost of 40320 permutations: 0.044338195884679035\n", + " ['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'V' 'M' 'C' 'W' 'H' 'T' 'S' 'N' 'L' 'B' 'F' 'R']\n", + " Topmost of 40320 permutations: 0.04439261339939324\n", + " ['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'C' 'L' 'B' 'T' 'S' 'R' 'N' 'D' 'V' 'W' 'M']\n", + " Topmost of 40320 permutations: 0.044344387643041445\n", + " ['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'W' 'T' 'S' 'C' 'N' 'M' 'F' 'B' 'R']\n", + " Topmost of 40320 permutations: 0.04434220552303007\n", + " ['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'W' 'D' 'L' 'B' 'T' 'C' 'S' 'N' 'M' 'F' 'V' 'R']\n", + " Topmost of 40320 permutations: 0.04430774236516413\n", + " ['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'L' 'D' 'F' 'R' 'T' 'C' 'N' 'S' 'W' 'B' 'M']\n", + " Topmost of 40320 permutations: 0.04430674825218268\n", + " ['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'V' 'D' 'M' 'W' 'C' 'T' 'N' 'R' 'S' 'B' 'F' 'L']\n", + " Topmost of 40320 permutations: 0.0441930152502403\n", + " ['X' 'P' 'U' 'Y' 'O' 'I' 'E' 'A' 'H' 'K' 'J' 'F' 'G' 'D' 'L' 'B' 'C' 'T' 'R' 'N' 'S' 'V' 'W' 'M']\n", + " Topmost of 40320 permutations: 0.044162132214259915\n", + " ['Y' 'G' 'U' 'X' 'I' 'O' 'E' 'A' 'P' 'K' 'J' 'D' 'B' 'L' 'M' 'W' 'H' 'T' 'C' 'N' 'S' 'V' 'F' 'R']\n", + "\n", + "The highest-scoring layout:\n", + "\n", + " Y P O X F C M W\n", + " H I E A T S N R\n", + " G K J U D V B L 0.04451764837996277 1\n", + "\n", + "### Assign letters Q and Z to keys 112 and 113" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "layout1 = ['Y','P','O','X', 'H','I','E','A', 'G','K','J','U', 'F','C','M','W', 'T','S','N','R', 'D','V','B','L', \"'\",',','-', '\"','.','?', 'Z','Q']\n", + "layout2 = ['Y','P','O','X', 'H','I','E','A', 'G','K','J','U', 'F','C','M','W', 'T','S','N','R', 'D','V','B','L', \"'\",',','-', '\"','.','?', 'Q','Z']\n", + "data_matrix = Factors32x32\n", + "s1 = score_layout(data_matrix, layout1, bigrams, bigram_frequencies, verbose=False)\n", + "s2 = score_layout(data_matrix, layout2, bigrams, bigram_frequencies, verbose=False)\n", + "print('Z,Q: {0}'.format(s1))\n", + "print('Q,Z: {0}'.format(s2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " Z,Q: 0.02513692748074413\n", + " Q,Z: 0.02513844670457776\n", + "\n", + "The Engram layout's letters:\n", + "\n", + " Y P O X F C M W Q\n", + " H I E A T S N R Z\n", + " G K J U D V B L\n", + "\n", + "\n", + "## Step 4: Stability Tests \n", + " \n", + "We will run three stability tests on the winning layouts:\n", + " \n", + " 1. Compare score of the winning layout after rearranging random letters \n", + " 2. Compare ranking of all final layouts based on interkey speed\n", + " 3. Compare ranking of all final layouts after removing each scoring parameter\n", + "\n", + "The first test is to see if allowing random sets of eight letters to rearrange in every possible combination improves the score of the winning layout. In the second test, we rescore all of the final layouts, replacing the flow matrix with the inter-key speed matrix to see if this affects their ranking. In the third test we remove each Engram scoring parameter one at a time and rescore all of the final layouts to see if this affects their ranking.\n", + "\n", + "### Stability Test 1. Compare score of the winning layout after rearranging random letters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Topmost of 3628800 permutations: 0.04451764837996277\n", + "['Y' 'P' 'O' 'X' 'H' 'I' 'E' 'A' 'G' 'K' 'J' 'U' 'F' 'C' 'M' 'W' 'T' 'S'\n", + " 'N' 'R' 'D' 'V' 'B' 'L']\n" + ] + } + ], + "source": [ + "data_matrix = Factors24x24\n", + "keys24 = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16, 17,18,19,20, 21,22,23,24]\n", + "letters24 = ['E','T','A','O','I','N','S','R','H','L','D','C','U','M','F','P','G','W','Y','B','V','K','X','J']\n", + "verbose = False\n", + "ntop = 0\n", + "\n", + "letters = ['Y','P','O','X','H','I','E','A','G','K','J','U','F','C','M','W','T','S','N','R','D','V','B','L']\n", + "\n", + "nunber_of_tests = 1000\n", + "size_random_set = 8\n", + "indices = [0,1,2,3, 8,9,10,11, 12,13,14,15, 20,21,22,23]\n", + "#indices = [0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15, 16,17,18,19, 20,21,22,23]\n", + "\n", + "for i in range(nunber_of_tests):\n", + "\n", + " letters_copy = letters.copy()\n", + "\n", + " random_indices = []\n", + " while np.size(random_indices) < size_random_set:\n", + " random_index = indices[np.int( np.round( (np.size(indices) - 1) * np.random.random(1) )[0])]\n", + " if random_index not in random_indices:\n", + " random_indices.append(random_index)\n", + " \n", + " for irand in random_indices:\n", + " letters_copy[np.int(irand)] = ''\n", + "\n", + " #print('')\n", + " #print('Random indices: {0}'.format(random_indices))\n", + " #print('Letters: {0}'.format(letters_copy))\n", + "\n", + " top_permutation_test1, letter_permutations_test1, scores_test1 = permute_optimize(letters_copy, letters24, keys24, data_matrix, bigrams, bigram_frequencies, verbose, ntop)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Stability Test 1 results: \n", + "\n", + "After randomly selecting eight letters from the top-scoring layout, creating layouts from every permutation of these letters, and computing their scores, we get identical results as the original layout. We repeated this test 100 times.\n", + "\n", + "### Stability Test 2: Compare ranking of all final layouts based on interkey speed\n", + "\n", + "The Speed matrix contains left-right averaged versions of the normalized interkey stroke times derived from the study (averaged to compensate for right-handedness of participants in the study):\n", + "\n", + "\"Estimation of digraph costs for keyboard layout optimization\", \n", + "A Iseri, Ma Eksioglu, International Journal of Industrial Ergonomics, 48, 127-138, 2015. " + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Letters: ['Y', 'P', 'O', 'X', 'H', 'I', 'E', 'A', 'G', 'K', 'J', 'U', 'F', 'C', 'M', 'W', 'T', 'S', 'N', 'R', 'D', 'V', 'B', 'L']\n", + "0.047893492070816585\n", + "Letters: ['Y', 'P', 'O', 'X', 'H', 'I', 'E', 'A', 'G', 'K', 'J', 'U', 'F', 'C', 'L', 'B', 'T', 'S', 'N', 'R', 'D', 'V', 'W', 'M']\n", + "0.04790271201179625\n", + "Letters: ['Y', 'G', 'U', 'X', 'I', 'O', 'E', 'A', 'P', 'K', 'J', 'D', 'V', 'M', 'C', 'W', 'H', 'T', 'S', 'N', 'L', 'B', 'F', 'R']\n", + "0.04785581394047941\n", + "Letters: ['X', 'P', 'U', 'Y', 'O', 'I', 'E', 'A', 'H', 'K', 'J', 'F', 'G', 'C', 'L', 'B', 'T', 'S', 'R', 'N', 'D', 'V', 'W', 'M']\n", + "0.04788460534737956\n", + "Letters: ['J', 'P', 'U', 'X', 'O', 'I', 'E', 'A', 'H', 'K', 'Y', 'F', 'G', 'C', 'L', 'B', 'T', 'S', 'R', 'N', 'D', 'V', 'W', 'M']\n", + "0.047884338371716156\n", + "Letters: ['Y', 'P', 'O', 'X', 'H', 'I', 'E', 'A', 'G', 'K', 'J', 'U', 'V', 'L', 'D', 'W', 'T', 'S', 'C', 'N', 'M', 'F', 'B', 'R']\n", + "0.0478256565979786\n", + "Letters: ['Y', 'P', 'O', 'X', 'H', 'I', 'E', 'A', 'G', 'K', 'J', 'U', 'W', 'D', 'L', 'B', 'T', 'C', 'S', 'N', 'M', 'F', 'V', 'R']\n", + "0.04782531823052567\n", + "Letters: ['Y', 'P', 'O', 'X', 'H', 'I', 'E', 'A', 'G', 'K', 'J', 'U', 'V', 'L', 'D', 'F', 'R', 'T', 'C', 'N', 'S', 'W', 'B', 'M']\n", + "0.047871391338431164\n", + "Letters: ['Y', 'P', 'O', 'X', 'H', 'I', 'E', 'A', 'G', 'K', 'J', 'U', 'V', 'D', 'M', 'W', 'C', 'T', 'N', 'R', 'S', 'B', 'F', 'L']\n", + "0.04786003123779349\n", + "Letters: ['X', 'P', 'U', 'Y', 'O', 'I', 'E', 'A', 'H', 'K', 'J', 'F', 'G', 'D', 'L', 'B', 'C', 'T', 'R', 'N', 'S', 'V', 'W', 'M']\n", + "0.0478599075622853\n", + "Letters: ['Y', 'G', 'U', 'X', 'I', 'O', 'E', 'A', 'P', 'K', 'J', 'D', 'B', 'L', 'M', 'W', 'H', 'T', 'C', 'N', 'S', 'V', 'F', 'R']\n", + "0.04786657411732643\n" + ] + } + ], + "source": [ + "#Factors24x24_new = Flow24x24 * Strength24x24\n", + "#Factors24x24_new = Flow24x24\n", + "#Factors24x24_new = Strength24x24\n", + "Factors24x24_new = Speed24x24\n", + "data_matrix = Factors24x24_new\n", + "verbose = False\n", + "\n", + "list_of_letters = [['Y','P','O','X','H','I','E','A','G','K','J','U','F','C','M','W','T','S','N','R','D','V','B','L'],\n", + " ['Y','G','U','X','I','O','E','A','P','K','J','D','V','M','C','W','H','T','S','N','L','B','F','R'],\n", + " ['X','P','U','Y','O','I','E','A','H','K','J','F','G','C','L','B','T','S','R','N','D','V','W','M'],\n", + " ['Y','P','O','X','H','I','E','A','G','K','J','U','V','L','D','W','T','S','C','N','M','F','B','R'],\n", + " ['Y','P','O','X','H','I','E','A','G','K','J','U','W','D','L','B','T','C','S','N','M','F','V','R'],\n", + " ['Y','P','O','X','H','I','E','A','G','K','J','U','V','L','D','F','R','T','C','N','S','W','B','M'],\n", + " ['Y','P','O','X','H','I','E','A','G','K','J','U','V','D','M','W','C','T','N','R','S','B','F','L'],\n", + " ['X','P','U','Y','O','I','E','A','H','K','J','F','G','D','L','B','C','T','R','N','S','V','W','M'],\n", + " ['Y','G','U','X','I','O','E','A','P','K','J','D','B','L','M','W','H','T','C','N','S','V','F','R']]\n", + "\n", + "for letters in list_of_letters:\n", + " \n", + " #print('Letters: {0}'.format(letters))\n", + "\n", + " s = score_layout(data_matrix, letters, bigrams, bigram_frequencies, verbose); print(\"{0}\".format(s))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Stability Test 2 results: \n", + "\n", + "Replacing Factors24x24 with the Speed matrix when scoring changes the ranking of the layouts, but the top-scored layout stays in top place:\n", + "\n", + " 1 0.047893492070816585\n", + " 7 0.04785581394047941\n", + " 2 0.04788460534737956\n", + " 8 0.0478256565979786\n", + " 9 0.04782531823052567\n", + " 3 0.047871391338431164\n", + " 5 0.04786003123779349\n", + " 6 0.0478599075622853\n", + " 4 0.04786657411732643\n", + " \n", + "Multiplying the Factors24x24 matrix by the Strength matrix when scoring changes the position of only one layout in the ranking of the layouts, and the top-scored layout remains in first place:\n", + " \n", + " 1 0.04451764837996277\n", + " 5 0.044338195884679035\n", + " 2 0.04439261339939324\n", + " 3 0.044344387643041445\n", + " 4 0.04434220552303007\n", + " 6 0.04430774236516413\n", + " 7 0.04430674825218268\n", + " 8 0.0441930152502403\n", + " 9 0.044162132214259915\n", + "\n", + "Replacing Factors24x24 with the Strength matrix by itself when scoring changes the ranking of the layouts, and the top-scored layout drops to third place:\n", + " \n", + " 3 0.046632538212919336\n", + " 9 0.04636923172195741\n", + " 8 0.046392192845358435\n", + " 4 0.046598847890122634\n", + " 5 0.046489851584343427\n", + " 1 0.046766576874421234\n", + " 2 0.04664212648625751\n", + " 7 0.046414937888770304\n", + " 6 0.04645855904778065\n", + "\n", + "\n", + "### Stability Test 3: Compare ranking of all final layouts after removing each scoring parameter" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Parameters: [1. 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9]\n", + "0.044659138950058686\n", + "0.04467037767638857\n", + "0.04450890793122707\n", + "0.0445683851252781\n", + "0.044566551284900564\n", + "0.04449376066881008\n", + "0.0444914039306669\n", + "0.04447954347990379\n", + "0.044441862917255305\n", + "0.04437013000051153\n", + "0.04435612293400218\n", + "Parameters: [0.9 1. 0.9 0.9 0.9 0.9 0.9 0.9 0.9]\n", + "0.04483519479356587\n", + "0.04482277611186561\n", + "0.04472127592896476\n", + "0.04479065660243393\n", + "0.04478801918323951\n", + "0.04465720848509772\n", + "0.04464911167651796\n", + "0.04466883911287722\n", + "0.04466734512738753\n", + "0.04463621966273051\n", + "0.044591579675131304\n", + "Parameters: [0.9 0.9 1. 0.9 0.9 0.9 0.9 0.9 0.9]\n", + "0.04729921052794759\n", + "0.04729847609310892\n", + "0.04722720082551514\n", + "0.04725197573192884\n", + "0.04725099188161449\n", + "0.04729535766901103\n", + "0.047292125570735574\n", + "0.047251308133121984\n", + "0.04723293359172548\n", + "0.04720212951585155\n", + "0.04719010136988248\n", + "Parameters: [0.9 0.9 0.9 1. 0.9 0.9 0.9 0.9 0.9]\n", + "0.04466735706537571\n", + "0.04466898806942351\n", + "0.0444864378123248\n", + "0.044514432098149086\n", + "0.044510393793933546\n", + "0.04451631900362364\n", + "0.0445115996206484\n", + "0.04448214150101738\n", + "0.04447007964981333\n", + "0.04432119448960584\n", + "0.04432760497785567\n", + "Parameters: [0.9 0.9 0.9 0.9 1. 0.9 0.9 0.9 0.9]\n", + "0.044981543210976235\n", + "0.04498019873495773\n", + "0.04475811091441146\n", + "0.04485929761973561\n", + "0.044767136036484495\n", + "0.04475610003925365\n", + "0.04475701194631845\n", + "0.044782404384206526\n", + "0.04471125672280924\n", + "0.04466046901764468\n", + "0.0445961897708845\n", + "Parameters: [0.9 0.9 0.9 0.9 0.9 1. 0.9 0.9 0.9]\n", + "0.04460613017522399\n", + "0.04459894672140189\n", + "0.04444765035750149\n", + "0.04450181848310145\n", + "0.0445059965409135\n", + "0.0444310998554193\n", + "0.044432807729179305\n", + "0.04440331274753842\n", + "0.04439541087201848\n", + "0.04430152956699746\n", + "0.04428087750913276\n", + "Parameters: [0.9 0.9 0.9 0.9 0.9 0.9 1. 0.9 0.9]\n", + "0.04460857795019283\n", + "0.0446103796875984\n", + "0.04443684987479579\n", + "0.04451061768101435\n", + "0.04450908336229595\n", + "0.04443646663675468\n", + "0.0444333499251023\n", + "0.0444166109389095\n", + "0.0443966066745228\n", + "0.044307169853576626\n", + "0.04427362063755531\n", + "Parameters: [0.9 0.9 0.9 0.9 0.9 0.9 0.9 1. 0.9]\n", + "0.044852285439829435\n", + "0.04485415461424774\n", + "0.044744247076570064\n", + "0.044745611920697925\n", + "0.04483516661573515\n", + "0.04473955031686124\n", + "0.044734061652889956\n", + "0.04466273681788413\n", + "0.044694373777388496\n", + "0.04454688680759243\n", + "0.04457563780046704\n", + "Parameters: [0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 1. ]\n", + "0.044621342155926974\n", + "0.04462369311596567\n", + "0.044466217786071176\n", + "0.04451626645765981\n", + "0.04451747933728863\n", + "0.04444902869900452\n", + "0.04445208622567924\n", + "0.04441767257371178\n", + "0.0444033543809191\n", + "0.04431820234822011\n", + "0.044279003951750516\n" + ] + } + ], + "source": [ + "# Unchanged parameter settings:\n", + "#same_finger = 0.9\n", + "#roll_out = 0.9\n", + "#not_home_row = 0.9\n", + "#skip_home_row = 0.9\n", + "#side_top = 0.9\n", + "#side_up_1away_down = 0.9 # index above middle, or little above ring \n", + "#side_up_2away_down = 0.9 # index above ring, or little above middle\n", + "#center_bottom = 0.9 # either middle or ring finger on bottom row\n", + "#ring_up_middle_down = 0.9 # ring above middle\n", + "\n", + "# Create new data_matrices:\n", + "params_lists = []\n", + "params0 = 0.9 * np.ones(9)\n", + "for i in range(9):\n", + " params_list = params0.copy()\n", + " params_list[i] = '1'\n", + " params_lists.append(params_list)\n", + " #print(params_lists)\n", + "\n", + "for P in params_lists:\n", + "\n", + " print('Parameters: {0}'.format(P))\n", + "\n", + " #Flow24x24 = create_24x24_flow_matrix(same_hand, same_finger, roll_out, not_home_row, skip_home_row, side_top, side_up_1away_down, side_up_2away_down, side_up_3away_down, center_bottom, ring_up_middle_down)\n", + " Factors24x24_new = create_24x24_flow_matrix(same_hand, P[0],P[1],P[2],P[3],P[4],P[5],P[6],1.0,P[7],P[8])\n", + "\n", + " if apply_strength:\n", + " Factors24x24_new = Strength24x24 * Factors24x24_new\n", + " if apply_speed:\n", + " Factors24x24_new = Speed24x24 * Factors24x24_new\n", + "\n", + " data_matrix = Factors24x24_new\n", + "\n", + " verbose = False\n", + "\n", + " list_of_letters = [['Y','P','O','X','H','I','E','A','G','K','J','U','F','C','M','W','T','S','N','R','D','V','B','L'],\n", + " ['Y','G','U','X','I','O','E','A','P','K','J','D','V','M','C','W','H','T','S','N','L','B','F','R'],\n", + " ['X','P','U','Y','O','I','E','A','H','K','J','F','G','C','L','B','T','S','R','N','D','V','W','M'],\n", + " ['Y','P','O','X','H','I','E','A','G','K','J','U','V','L','D','W','T','S','C','N','M','F','B','R'],\n", + " ['Y','P','O','X','H','I','E','A','G','K','J','U','W','D','L','B','T','C','S','N','M','F','V','R'],\n", + " ['Y','P','O','X','H','I','E','A','G','K','J','U','V','L','D','F','R','T','C','N','S','W','B','M'],\n", + " ['Y','P','O','X','H','I','E','A','G','K','J','U','V','D','M','W','C','T','N','R','S','B','F','L'],\n", + " ['X','P','U','Y','O','I','E','A','H','K','J','F','G','D','L','B','C','T','R','N','S','V','W','M'],\n", + " ['Y','G','U','X','I','O','E','A','P','K','J','D','B','L','M','W','H','T','C','N','S','V','F','R']]\n", + "\n", + " for letters in list_of_letters:\n", + "\n", + " #print('Letters: {0}'.format(letters))\n", + " \n", + " s = score_layout(data_matrix, letters, bigrams, bigram_frequencies, verbose); print(\"{0}\".format(s))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Stability Test 3 reults:\n", + "\n", + "Removing each scoring parameter results in the top-scoring layout staying in first place:\n", + "\n", + " same_finger\n", + " Parameters: [1. 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9]\n", + " 0.044659138950058686\n", + " 0.04450890793122707\n", + " 0.0445683851252781\n", + " 0.04449376066881008\n", + " 0.0444914039306669\n", + " 0.04447954347990379\n", + " 0.044441862917255305\n", + " 0.04437013000051153\n", + " 0.04435612293400218\n", + " \n", + " roll_out\n", + " Parameters: [0.9 1. 0.9 0.9 0.9 0.9 0.9 0.9 0.9]\n", + " 0.04483519479356587\n", + " 0.04472127592896476\n", + " 0.04479065660243393\n", + " 0.04465720848509772\n", + " 0.04464911167651796\n", + " 0.04466883911287722\n", + " 0.04466734512738753\n", + " 0.04463621966273051\n", + " 0.044591579675131304\n", + "\n", + " not_home_row\n", + " Parameters: [0.9 0.9 1. 0.9 0.9 0.9 0.9 0.9 0.9]\n", + " 0.04729921052794759\n", + " 0.04722720082551514\n", + " 0.04725197573192884\n", + " 0.04729535766901103\n", + " 0.047292125570735574\n", + " 0.047251308133121984\n", + " 0.04723293359172548\n", + " 0.04720212951585155\n", + " 0.04719010136988248\n", + " \n", + " skip_home_row \n", + " Parameters: [0.9 0.9 0.9 1. 0.9 0.9 0.9 0.9 0.9]\n", + " 0.04466735706537571\n", + " 0.0444864378123248\n", + " 0.044514432098149086\n", + " 0.04451631900362364\n", + " 0.0445115996206484\n", + " 0.04448214150101738\n", + " 0.04447007964981333\n", + " 0.04432119448960584\n", + " 0.04432760497785567\n", + " \n", + " side_top\n", + " Parameters: [0.9 0.9 0.9 0.9 1. 0.9 0.9 0.9 0.9]\n", + " 0.044981543210976235\n", + " 0.04475811091441146\n", + " 0.04485929761973561\n", + " 0.04475610003925365\n", + " 0.04475701194631845\n", + " 0.044782404384206526\n", + " 0.04471125672280924\n", + " 0.04466046901764468\n", + " 0.0445961897708845\n", + " \n", + " side_up_1away_down\n", + " Parameters: [0.9 0.9 0.9 0.9 0.9 1. 0.9 0.9 0.9]\n", + " 0.04460613017522399\n", + " 0.04444765035750149\n", + " 0.04450181848310145\n", + " 0.0444310998554193\n", + " 0.044432807729179305\n", + " 0.04440331274753842\n", + " 0.04439541087201848\n", + " 0.04430152956699746\n", + " 0.04428087750913276\n", + " \n", + " side_up_2away_down\n", + " Parameters: [0.9 0.9 0.9 0.9 0.9 0.9 1. 0.9 0.9]\n", + " 0.04460857795019283\n", + " 0.04443684987479579\n", + " 0.04451061768101435\n", + " 0.04443646663675468\n", + " 0.0444333499251023\n", + " 0.0444166109389095\n", + " 0.0443966066745228\n", + " 0.044307169853576626\n", + " 0.04427362063755531\n", + " \n", + " center_bottom\n", + " Parameters: [0.9 0.9 0.9 0.9 0.9 0.9 0.9 1. 0.9]\n", + " 0.044852285439829435\n", + " 0.044744247076570064\n", + " 0.044745611920697925\n", + " 0.04473955031686124\n", + " 0.044734061652889956\n", + " 0.04466273681788413\n", + " 0.044694373777388496\n", + " 0.04454688680759243\n", + " 0.04457563780046704\n", + " \n", + " ring_up_middle_down\n", + " Parameters: [0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 1. ]\n", + " 0.044621342155926974\n", + " 0.044466217786071176\n", + " 0.04451626645765981\n", + " 0.04444902869900452\n", + " 0.04445208622567924\n", + " 0.04441767257371178\n", + " 0.0444033543809191\n", + " 0.04431820234822011\n", + " 0.044279003951750516\n", + " \n", + "\n", + "### Stability Test results\n", + " \n", + "Test 1: The top-scored layout remains at the top, attesting to its stability.\n", + "\n", + "Test 2: The top-scored layout remains at the top, attesting to its efficiency with respect to speed.\n", + "\n", + "Test 3: The top-scored layout remains at the top, attesting to its robustness to parameter perturbations.\n", + "\n", + "We will therefore choose the top-scoring layout as our Engram layout:\n", + "\n", + " Y P O X F C M W Q\n", + " H I E A T S N R Z\n", + " G K J U D V B L\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "TPW3wZw2DzT7" + }, + "source": [ + "## Step 5: Arrange non-letter characters in easy-to-remember places \n", + " \n", + "Now that we have all 26 letters accounted for, we turn our attention to non-letter characters, taking into account frequency of punctuation and ease of recall." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "raw", + "id": "ul_j8VsZDzT7" + }, + "source": [ + "### Frequency of punctuation marks\n", + "\n", + " - Statistical values of punctuation frequency in 20 English-speaking countries (Table 1):
\n", + "Sun, Kun & Wang, Rong. (2018). Frequency Distributions of Punctuation Marks in English: Evidence from Large-scale Corpora. English Today. 10.1017/S0266078418000512.
\n", + "https://www.researchgate.net/publication/328512136_Frequency_Distributions_of_Punctuation_Marks_in_English_Evidence_from_Large-scale_Corpora\n", + "
\"frequency of punctuation marks attested for twenty English-speaking countries and regions... The data were acquired through GloWbE.\"\n", + " \"The corpus of GloWbE (2013) is a large English corpus collecting international English from the internet, containing about 1.9 billion words of text from twenty different countries. For further information on the corpora used, see https://corpus.byu.edu/.\"\n", + " \n", + " - Google N-grams and Twitter analysis:
\n", + "\"Punctuation Input on Touchscreen Keyboards: Analyzing Frequency of Use and Costs\"
\n", + "S Malik, L Findlater - College Park: The Human-Computer Interaction Lab. 2013
\n", + "https://www.cs.umd.edu/sites/default/files/scholarly_papers/Malik.pdf
\n", + " \"the Twitter corpora included substantially higher punctuation use than the Google corpus,
\n", + " comprising 7.5% of characters in the mobile tweets and 7.6% in desktop versus only 4.4%...
\n", + "With the Google corpus,only 6 punctuation symbols (. -’ ( ) “) appeared more frequently than [q]\"\n", + "\n", + " - \"Frequencies for English Punctuation Marks\" by Vivian Cook
\n", + "http://www.viviancook.uk/Punctuation/PunctFigs.htm
\n", + " \"Based on a writing system corpus some 459 thousand words long.
\n", + " This includes three novels of different types (276 thousand words),
\n", + " selections of articles from two newspapers (55 thousand),
\n", + "one bureaucratic report (94 thousand), and assorted academic papers
\n", + "on language topics (34 thousand). More information is in
\n", + "Cook, V.J. (2013) ‘Standard punctuation and the punctuation of the street’
\n", + "in M. Pawlak and L. Aronin (eds.), Essential Topics in Applied Linguistics and Multilingualism,
\n", + " Springer International Publishing Switzerland (2013), 267-290\"\n", + "\n", + " - \"A Statistical Study of Current Usage in Punctuation\":
\n", + "Ruhlen, H., & Pressey, S. (1924). A Statistical Study of Current Usage in Punctuation. The English Journal, 13(5), 325-331. doi:10.2307/802253\n", + "\n", + " - \"Computer Languages Character Frequency\"\n", + "by Xah Lee.
\n", + "Date: 2013-05-23. Last updated: 2020-06-29.
\n", + "http://xahlee.info/comp/computer_language_char_distribution.html
\n", + "NOTE: biased toward C (19.8%) and Py (18.5%), which have high use of \"_\".\n", + "\n", + "Frequency: \n", + "\n", + " Sun: Malik: Ruhlen: Cook: Xah:\n", + " /1M N-gram % /10,000 /1,000 All% JS% Py%\n", + "\n", + " . 42840.02 1.151 535 65.3 6.6 9.4 10.3\n", + " , 44189.96 556 61.6 5.8 8.9 7.5\n", + " \" 2.284 44 26.7 3.9 1.6 6.2\n", + " ' 2980.35 0.200 40 24.3 4.4 4.0 8.6\n", + " - 9529.78 0.217 21 15.3 4.1 1.9 3.0\n", + " () 4500.81 0.140 7 7.4 9.8 8.1\n", + " ; 1355.22 0.096 22 3.2 3.8 8.6\n", + " z 0.09 - -\n", + " : 3221.82 0.087 11 3.4 3.5 2.8 4.7\n", + " ? 4154.78 0.032 14 5.6 0.3\n", + " / 0.019 4.0 4.9 1.1\n", + " ! 2057.22 0.013 3 3.3 0.4\n", + " _ 0.001 11.0 2.9 10.5\n", + " = 4.4 10.7 5.4\n", + " * 3.6 2.1\n", + " > 3.0 1.4\n", + " $ 2.7 1.6\n", + " # 2.2 3.2\n", + " {} 1.9 4.2\n", + " < 1.3\n", + " & 1.3\n", + " \\ 1.2 1.1\n", + " [] 0.9 1.9 1.2\n", + " @ 0.8\n", + " | 0.6\n", + " + 0.6 1.9\n", + " % 0.4" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "sdl3lLOfDzT8" + }, + "source": [ + "### Add punctuation keys and number keys\n", + "\n", + "We will assign the most frequent punctuation according to Sun, et al (2018) to the six keys in the middle two columns: . , \" ' - ? ; : () ! _\n", + "\n", + " Y P O X ' \" F C M W Q\n", + " H I E A , . T S N R Z\n", + " G K J U - ? D V B L\n", + "\n", + "We will use the Shift key to group similar punctuation marks (separating and joining marks in the left middle column and closing marks in the right middle column):\n", + "\n", + " Y P O X '( \") F C M W Q\n", + " H I E A ,; .: T S N R Z\n", + " G K J U -_ ?! D V B L\n", + " \n", + "**Separating marks (left)**: The comma separates text in lists; the semicolon can be used in place of the comma to separate items in a list (especially if these items contain commas); open parenthesis sets off an explanatory word, phrase, or sentence. \n", + "\n", + "**Joining marks (left)**: The apostrophe joins words as contractions; the hyphen joins words as compounds; the underscore joins words in cases where whitespace characters are not permitted (such as in variables or file names). \n", + "\n", + "**Closing marks (right)**: A sentence usually ends with a period, question mark, or exclamation mark. The colon ends one statement but precedes the following: an explanation, quotation, list, etc. Double quotes and close parenthesis closes a word, clause, or sentence separated by an open parenthesis.\n", + "\n", + "**Number keys**: \n", + "The numbers are flanked to the left and right by [square brackets], and {curly brackets} accessed by the Shift key. Each of the numbers is paired with a mathematical or logic symbol accessed by the Shift key:\n", + " \n", + " { | = ~ + < > ^ & % * } \\\n", + " [ 1 2 3 4 5 6 7 8 9 0 ] /\n", + "\n", + " 1: | (vertical bar or \"pipe\" represents the logical OR operator: 1 stroke, looks like the number one)\n", + " 2: = (equal: 2 strokes, like the Chinese character for \"2\")\n", + " 3: ~ (tilde: \"almost equal\", often written with 3 strokes, like the Chinese character for \"3\")\n", + " 4: + (plus: has four quadrants; resembles \"4\")\n", + " 5 & 6: < > (\"less/greater than\"; these angle brackets are directly above the other bracket keys)\n", + " 7: ^ (caret for logical XOR operator as well as exponentiation; resembles \"7\")\n", + " 8: & (ampersand: logical AND operator; resembles \"8\")\n", + " 9: % (percent: related to division; resembles \"9\")\n", + " 0: * (asterisk: for multiplication; resembles \"0\") \n", + "\n", + "The three remaining keys in many common keyboards (flanking the upper right hand corner Backspace key) are displaced in special keyboards, such as the Kinesis Advantage and Ergodox. For the top right key, we will assign the forward slash and backslash: / \\\\. For the remaining two keys, we will assign two symbols that in modern usage have significance in social media: the hash/pound sign and the \"at sign\". The hash or hashtag identifies digital content on a specific topic (the Shift key accesses the dollar sign). The \"at sign\" identifies a location or affiliation (such as in email addresses) and acts as a \"handle\" to identify users in popular social media platforms and online forums.\n", + "\n", + "The resulting Engram layout:\n", + "\n", + " { | = ~ + < > ^ & % * } \\\n", + " [ 1 2 3 4 5 6 7 8 9 0 ] /\n", + "\n", + " Y P O X '( \") F C M W Q #$ @\n", + " H I E A ,; .: T S N R Z\n", + " G K J U -_ ?! D V B L\n", + " " + ] + } + ], + "metadata": { + "colab": { + "name": "engram-layout.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}