From 455b15416e3f98128f68e56cae2f4347a29b01b7 Mon Sep 17 00:00:00 2001 From: Bjoern Ludwig <bjoern.ludwig@ptb.de> Date: Mon, 14 Feb 2022 15:09:28 +0100 Subject: [PATCH 01/10] refactor(ilp): finalize key to position rename --- src/ilp_keyboard_layout_optimization/ilp.py | 108 +++++++++--------- .../optimize.py | 4 +- test/test_initialization.py | 6 +- 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/ilp_keyboard_layout_optimization/ilp.py b/src/ilp_keyboard_layout_optimization/ilp.py index 0c03cca..53f0301 100644 --- a/src/ilp_keyboard_layout_optimization/ilp.py +++ b/src/ilp_keyboard_layout_optimization/ilp.py @@ -19,10 +19,10 @@ from .type_aliases import ( class KeyboardOptimization: """Instances of this class represent instances of the keyboard layout QAP - The IP variant of an optimization of character to key assignments can be modeled - as a so-called quadratic assignment problem (QAP). The task is to assign a set of - characters to a set of keys on a keyboard. The way in which they should be - arranged has to meet certain criteria such as for instance: characters that are + The IP variant of an optimization of character to position assignments can be + modeled as a so-called quadratic assignment problem (QAP). The task is to assign a + set of characters to a set of positions on a keyboard. The way in which they should + be arranged has to meet certain criteria such as for instance: characters that are often typed after one another should not be assigned to positions, that are supposed to be pressed by the same finger. @@ -47,82 +47,82 @@ class KeyboardOptimization: self.quad_char_pos_costs: QuadCosts = {} self.model: Model = Model("Keyboard Layout Optimization") - def set_up_model(self, char_key_costs: LinCosts, quad_char_key_costs: QuadCosts): + def set_up_model(self, char_pos_costs: LinCosts, quad_char_pos_costs: QuadCosts): """Set up all the variables and initialize the costs for the SCIP model""" - for (char, key) in self.char_key_assigns_keys: - self.char_pos_assigns[char, key] = self.model.addVar( - name=f"{key}={char}", vtype="B" + for (char, pos) in self.char_pos_assigns_keys: + self.char_pos_assigns[char, pos] = self.model.addVar( + name=f"{pos}={char}", vtype="B" ) - for (char, char_2, key, key_2) in self.quad_char_key_assigns_keys: - self.quad_char_pos_assigns[char, char_2, key, key_2] = self.model.addVar( - name=f"{key}={char}_and_{key_2}={char_2}", vtype="C", lb=0, ub=1 + for (char, char_2, pos, pos_2) in self.quad_char_pos_assigns_keys: + self.quad_char_pos_assigns[char, char_2, pos, pos_2] = self.model.addVar( + name=f"{pos}={char}_and_{pos_2}={char_2}", vtype="C", lb=0, ub=1 ) - assert len(quad_char_key_costs) == len(self.quad_char_pos_assigns) - assert len(char_key_costs) == len(self.char_pos_assigns) - self.char_pos_costs = char_key_costs - self.quad_char_pos_costs = quad_char_key_costs + assert len(quad_char_pos_costs) == len(self.quad_char_pos_assigns) + assert len(char_pos_costs) == len(self.char_pos_assigns) + self.char_pos_costs = char_pos_costs + self.quad_char_pos_costs = quad_char_pos_costs constr = {} for char in self.chars.monos: self.model.addCons( - quicksum(self.char_pos_assigns[char, key] for key in self.poss) == 1, + quicksum(self.char_pos_assigns[char, pos] for pos in self.poss) == 1, f"AllCharacterAssignedOnce({char})", ) - for (key, key_2) in self.key_pairs: + for (pos, pos_2) in self.pos_pairs: self.model.addCons( quicksum( - self.quad_char_pos_assigns[char, char_2, key, key_2] + self.quad_char_pos_assigns[char, char_2, pos, pos_2] for char_2 in self.chars.monos if char_2 != char ) - <= self.char_pos_assigns[char, key], - f"QuadCharacterAssignedLEQThanPosition({char},{key},{key_2})", + <= self.char_pos_assigns[char, pos], + f"QuadCharacterAssignedLEQThanPosition({char},{pos},{pos_2})", ) self.model.addCons( quicksum( - self.quad_char_pos_assigns[char_2, char, key_2, key] + self.quad_char_pos_assigns[char_2, char, pos_2, pos] for char_2 in self.chars.monos if char_2 != char ) - <= self.char_pos_assigns[char, key], - f"QuadCharacterAssignedLEQThanSecondPosition({char},{key_2},{key})", + <= self.char_pos_assigns[char, pos], + f"QuadCharacterAssignedLEQThanSecondPosition({char},{pos_2},{pos})", ) for char_2 in self.chars.monos: - for key in self.poss: + for pos in self.poss: if char_2 != char: self.model.addCons( quicksum( - self.quad_char_pos_assigns[char, char_2, key, key_2] - for key_2 in self.poss - if key_2 != key + self.quad_char_pos_assigns[char, char_2, pos, pos_2] + for pos_2 in self.poss + if pos_2 != pos ) - <= self.char_pos_assigns[char, key], + <= self.char_pos_assigns[char, pos], f"QuadCharacterAssignedLEQThanCharacter({char},{char_2}," - f"{key})", + f"{pos})", ) self.model.addCons( quicksum( - self.quad_char_pos_assigns[char_2, char, key_2, key] - for key_2 in self.poss - if key_2 != key + self.quad_char_pos_assigns[char_2, char, pos_2, pos] + for pos_2 in self.poss + if pos_2 != pos ) - <= self.char_pos_assigns[char, key], + <= self.char_pos_assigns[char, pos], f"QuadCharacterAssignedLEQThanSecondCharacter({char_2}," - f"{char},{key})", + f"{char},{pos})", ) - for (char, char_2, key, key_2) in self.quad_char_key_assigns_keys: + for (char, char_2, pos, pos_2) in self.quad_char_pos_assigns_keys: self.model.addCons( - self.char_pos_assigns[char, key] + self.char_pos_assigns[char_2, key_2] - <= 1 + self.quad_char_pos_assigns[char, char_2, key, key_2], - f"IntegrableQuadAssign({char},{key_2},{key})", + self.char_pos_assigns[char, pos] + self.char_pos_assigns[char_2, pos_2] + <= 1 + self.quad_char_pos_assigns[char, char_2, pos, pos_2], + f"IntegrableQuadAssign({char},{pos_2},{pos})", ) - for key in self.poss: - constr[key] = self.model.addCons( - quicksum(self.char_pos_assigns[char, key] for char in self.chars.monos) + for pos in self.poss: + constr[pos] = self.model.addCons( + quicksum(self.char_pos_assigns[char, pos] for char in self.chars.monos) == 1, - f"AllPositionsAssignedOnce({key})", + f"AllPositionsAssignedOnce({pos})", ) self.model.setObjective( @@ -157,14 +157,14 @@ class KeyboardOptimization: def visualize_solution(self): """Rudimentary visualize the optimization result on the console""" solution_assignments = [] - for (char, key) in self.char_key_assigns_keys: + for (char, pos) in self.char_pos_assigns_keys: print( - f"({char}, {key}): " - f"{self.model.getVal(self.char_pos_assigns[char, key])}, " - f"cost: {self.char_pos_costs[char, key]}" + f"({char}, {pos}): " + f"{self.model.getVal(self.char_pos_assigns[char, pos])}, " + f"cost: {self.char_pos_costs[char, pos]}" ) - if self.model.getVal(self.char_pos_assigns[char, key]) == 1: - solution_assignments.append((char, key)) + if self.model.getVal(self.char_pos_assigns[char, pos]) == 1: + solution_assignments.append((char, pos)) assert "('u', 'left_pinky_home')" in str(solution_assignments) # assert "('a', 'left_middle_home')" in str(solution_assignments) @@ -181,13 +181,13 @@ class KeyboardOptimization: print(f"{str(solution_assignments)}") @property - def char_key_assigns_keys(self) -> Iterable[CharPosPair]: - """An iterator for the pairs of (special) characters and corresponding keys""" + def char_pos_assigns_keys(self) -> Iterable[CharPosPair]: + """An iterator for the pairs of characters and corresponding positions""" return product(self.chars.monos, self.poss) @property - def quad_char_key_assigns_keys(self) -> Iterable[CharPosQuadruple]: - """An iterator for quadruples of character pairs and corresponding key pairs""" + def quad_char_pos_assigns_keys(self) -> Iterable[CharPosQuadruple]: + """An iterator for quadruples of char. pairs and corresponding position pairs""" flattened_tuple_of_quads = chain.from_iterable( chain.from_iterable( product(permutations(self.chars.monos, 2), permutations(self.poss, 2)) @@ -197,6 +197,6 @@ class KeyboardOptimization: return zip(*iter_of_quads) @property - def key_pairs(self) -> Iterable: - """An iterator for all pairs of keys that are possible""" + def pos_pairs(self) -> Iterable: + """An iterator for all pairs of positions that are possible""" return permutations(self.poss, 2) diff --git a/src/ilp_keyboard_layout_optimization/optimize.py b/src/ilp_keyboard_layout_optimization/optimize.py index 714ef97..99b88c6 100644 --- a/src/ilp_keyboard_layout_optimization/optimize.py +++ b/src/ilp_keyboard_layout_optimization/optimize.py @@ -34,7 +34,7 @@ def prepare_costs( """ _linear_costs = {} _quad_costs = {} - for (char, pos) in optimization_problem.char_key_assigns_keys: + for (char, pos) in optimization_problem.char_pos_assigns_keys: if ( (char == "u" and pos == "left_pinky_home") or (char == "n" and pos == "right_index_home") @@ -46,7 +46,7 @@ def prepare_costs( continue _linear_costs[char, pos] = 1.0 - for (char, char_2, pos, pos_2) in optimization_problem.quad_char_key_assigns_keys: + for (char, char_2, pos, pos_2) in optimization_problem.quad_char_pos_assigns_keys: if ( ( char == "u" diff --git a/test/test_initialization.py b/test/test_initialization.py index 3e502a2..b56ddc1 100644 --- a/test/test_initialization.py +++ b/test/test_initialization.py @@ -29,7 +29,7 @@ def test_keyboard_optimization_init(three_chars, three_poss): def test_keyboard_optimization_char_pos_assigns_keys(three_chars, three_poss): linear_keys = tuple( - KeyboardOptimization(three_chars, three_poss).char_key_assigns_keys + KeyboardOptimization(three_chars, three_poss).char_pos_assigns_keys ) assert len(linear_keys) == len(three_chars) * len(three_poss) for char in three_chars: @@ -39,7 +39,7 @@ def test_keyboard_optimization_char_pos_assigns_keys(three_chars, three_poss): def test_keyboard_optimization_quad_char_pos_assigns_keys(three_chars, three_poss): quadratic_keys = tuple( - KeyboardOptimization(three_chars, three_poss).quad_char_key_assigns_keys + KeyboardOptimization(three_chars, three_poss).quad_char_pos_assigns_keys ) assert len(quadratic_keys) == len(three_chars) * (len(three_chars) - 1) * len( three_poss @@ -50,7 +50,7 @@ def test_keyboard_optimization_quad_char_pos_assigns_keys(three_chars, three_pos def test_keyboard_optimization_quad_poss(three_chars, three_poss): - quad_poss = tuple(KeyboardOptimization(three_chars, three_poss).key_pairs) + quad_poss = tuple(KeyboardOptimization(three_chars, three_poss).pos_pairs) assert len(quad_poss) == len(three_poss) * (len(three_poss) - 1) for pos in three_poss: for pos_2 in three_poss: -- GitLab From f4c274d7100f2d8d4b3b372220db2ce10ac4bc43 Mon Sep 17 00:00:00 2001 From: Bjoern Ludwig <bjoern.ludwig@ptb.de> Date: Mon, 14 Feb 2022 15:15:30 +0100 Subject: [PATCH 02/10] refactor(optimize): simplify Char initialization --- src/ilp_keyboard_layout_optimization/optimize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ilp_keyboard_layout_optimization/optimize.py b/src/ilp_keyboard_layout_optimization/optimize.py index 99b88c6..10f89d0 100644 --- a/src/ilp_keyboard_layout_optimization/optimize.py +++ b/src/ilp_keyboard_layout_optimization/optimize.py @@ -74,7 +74,7 @@ def prepare_costs( if __name__ == "__main__": - test_chars = Chars(("a", "e", "i", "u", "n", "r", "t", "d")) + test_chars = Chars(("aeiunrtd")) test_poss = ( "left_pinky_home", "left_ring_home", -- GitLab From 4a2ba5e61e7fdeaad86a55a486e89a4f498a3a83 Mon Sep 17 00:00:00 2001 From: Bjoern Ludwig <bjoern.ludwig@ptb.de> Date: Mon, 14 Feb 2022 17:48:00 +0100 Subject: [PATCH 03/10] feat(types): introduce types for more sophisticated positions --- .../type_aliases.py | 55 ++++++- test/test_types.py | 145 +++++++++++++++++- 2 files changed, 194 insertions(+), 6 deletions(-) diff --git a/src/ilp_keyboard_layout_optimization/type_aliases.py b/src/ilp_keyboard_layout_optimization/type_aliases.py index 6160ee2..68b854a 100644 --- a/src/ilp_keyboard_layout_optimization/type_aliases.py +++ b/src/ilp_keyboard_layout_optimization/type_aliases.py @@ -6,22 +6,73 @@ __all__ = [ "CharPosPair", "CharPosQuadruple", "CharTuple", + "Col", "LinCosts", "LinVars", + "Mod", "Pos", "PosPair", "PosTuple", "ProbDict", "QuadCosts", "QuadVars", + "Row", + "Side", ] from collections import defaultdict +from enum import auto, Enum +from typing import NamedTuple Char = str """A (special) character""" -Pos = str -"""A position""" + + +class Side(Enum): + """Side of a position, i.e. if usually reached with the left or the right hand""" + + LEFT = auto() + RIGHT = auto() + + +class Mod(Enum): + """Modifier keys needed to reach a position""" + + NONE = 0 + SHIFT = auto() + UPPER = auto() + LOWER = auto() + NAV = 2 + + +class Col(Enum): + """Column of a position""" + + OUTERMOST = 0 + PINKY = 1 + RING = 2 + MIDDLE = 3 + INDEX = 4 + INNERMOST = 5 + + +class Row(Enum): + """Column of a position""" + + UPPER = 0 + HOME = 1 + LOWER = 2 + + +class Pos(NamedTuple): + """A position including side, modifiers, column and row""" + + side: Side + mod: Mod + col: Col + row: Row + + CharPosPair = tuple[Char, Pos] """A pair of a (special) character and a position""" Bigram = str diff --git a/test/test_types.py b/test/test_types.py index a3e2385..97c1a6a 100644 --- a/test/test_types.py +++ b/test/test_types.py @@ -1,4 +1,5 @@ from collections import defaultdict +from enum import EnumMeta from ilp_keyboard_layout_optimization.costs import FreqTuple from ilp_keyboard_layout_optimization.type_aliases import ( @@ -7,14 +8,18 @@ from ilp_keyboard_layout_optimization.type_aliases import ( CharPosPair, CharPosQuadruple, CharTuple, + Col, LinCosts, LinVars, + Mod, Pos, PosPair, PosTuple, ProbDict, QuadCosts, QuadVars, + Row, + Side, ) @@ -27,11 +32,27 @@ def test_char(): assert Char == str -def test_key(): - assert Pos == str +def test_pos(): + assert issubclass(Pos, tuple) -def test_char_key_pair(): +def test_pos_row(): + assert "row" in Pos._fields + + +def test_pos_mod(): + assert "mod" in Pos._fields + + +def test_pos_side(): + assert "side" in Pos._fields + + +def test_pos_col(): + assert "col" in Pos._fields + + +def test_char_pos_pair(): assert CharPosPair == tuple[Char, Pos] @@ -39,6 +60,122 @@ def test_bigram(): assert Bigram == str +def test_col(): + assert isinstance(Col, EnumMeta) + + +def test_col_outermost(): + assert Col.OUTERMOST + + +def test_col_pinky(): + assert Col.PINKY + + +def test_col_ring(): + assert Col.RING + + +def test_col_middle(): + assert Col.MIDDLE + + +def test_col_index(): + assert Col.INDEX + + +def test_col_innermost(): + assert Col.INNERMOST + + +def test_col_innermost_minus_index(): + assert Col.INNERMOST.value - Col.INDEX.value == 1 + + +def test_col_innermost_minus_middle(): + assert Col.INNERMOST.value - Col.MIDDLE.value == 2 + + +def test_col_innermost_minus_ring(): + assert Col.INNERMOST.value - Col.RING.value == 3 + + +def test_col_innermost_minus_pinky(): + assert Col.INNERMOST.value - Col.PINKY.value == 4 + + +def test_col_innermost_minus_outermost(): + assert Col.INNERMOST.value - Col.OUTERMOST.value == 5 + + +def test_mod(): + assert isinstance(Mod, EnumMeta) + + +def test_mod_none(): + assert Mod.NONE + + +def test_mod_shift(): + assert Mod.SHIFT + + +def test_mod_upper(): + assert Mod.UPPER + + +def test_mod_lower(): + assert Mod.LOWER + + +def test_mod_nav(): + assert Mod.NAV + + +def test_mod_none_equals_zero(): + assert Mod.NONE.value == 0 + + +def test_mod_nav_equals_two(): + assert Mod.NAV.value == 2 + + +def test_row(): + assert isinstance(Row, EnumMeta) + + +def test_row_upper(): + assert Row.UPPER + + +def test_row_lower(): + assert Row.LOWER + + +def test_row_home(): + assert Row.HOME + + +def test_row_lower_minus_home(): + assert Row.LOWER.value - Row.HOME.value == 1 + + +def test_row_lower_minus_home(): + assert Row.LOWER.value - Row.UPPER.value == 2 + + +def test_side(): + assert isinstance(Side, EnumMeta) + + +def test_side_left(): + assert Side.LEFT + + +def test_side_right(): + assert Side.RIGHT + + def test_pos_pair(): assert PosPair == tuple[Pos, Pos] @@ -60,7 +197,7 @@ def test_lin_vars(): def test_quad_pos_quadruple(): - assert CharPosQuadruple == tuple[Char, Pos, Char, Pos] + assert CharPosQuadruple == tuple[Char, Char, Pos, Pos] def test_quad_costs(): -- GitLab From ed7f7dc5cd36cb1ff8173eeb8bcc6294725281f9 Mon Sep 17 00:00:00 2001 From: Bjoern Ludwig <bjoern.ludwig@ptb.de> Date: Mon, 14 Feb 2022 17:58:20 +0100 Subject: [PATCH 04/10] feat(positions): introduce sophisticated positions --- .../data_aquisition/positions.py | 33 ++ test/test_positions.py | 348 ++++++++++++++++++ 2 files changed, 381 insertions(+) create mode 100644 src/ilp_keyboard_layout_optimization/data_aquisition/positions.py create mode 100644 test/test_positions.py diff --git a/src/ilp_keyboard_layout_optimization/data_aquisition/positions.py b/src/ilp_keyboard_layout_optimization/data_aquisition/positions.py new file mode 100644 index 0000000..06d5fac --- /dev/null +++ b/src/ilp_keyboard_layout_optimization/data_aquisition/positions.py @@ -0,0 +1,33 @@ +from dataclasses import dataclass +from itertools import product + +from ..type_aliases import Col, Mod, Pos, PosTuple, Row, Side + + +@dataclass +class Positions: + """An instance provides a tuple of relevant positions on our Corne keyboard + + Attributes + ---------- + poss : PosTuple + the relevant positions to assign chars to on our Corne keyboard + """ + + poss: PosTuple + + def __init__(self): + poss = set( + product( + Side, + Mod, + (Col.PINKY, Col.RING, Col.MIDDLE, Col.INDEX, Col.INNERMOST), + Row, + ) + ) + for mod in (Mod.SHIFT, Mod.NONE, Mod.LOWER): + poss.add(Pos(Side.RIGHT, mod, Col.OUTERMOST, Row.HOME)) + for col in (Col.PINKY, Col.RING, Col.MIDDLE, Col.INDEX, Col.INNERMOST): + for side in Side: + poss.remove(Pos(side, Mod.LOWER, col, Row.UPPER)) + self.poss = tuple(poss) diff --git a/test/test_positions.py b/test/test_positions.py new file mode 100644 index 0000000..5075c09 --- /dev/null +++ b/test/test_positions.py @@ -0,0 +1,348 @@ +from typing import Callable, Dict + +import pytest +from hypothesis import given, strategies as hst +from hypothesis.strategies import composite + +from ilp_keyboard_layout_optimization.data_aquisition.positions import Positions +from ilp_keyboard_layout_optimization.type_aliases import Char, Col, Mod, Pos, Row, Side +from ilp_keyboard_layout_optimization.visualize import make_layer_strs + + +@pytest.fixture(scope="session") +def positions(): + return Positions() + + +@composite +def assigns(draw: Callable): + assignments: Dict[Pos, Char] = {} + default_positions: Positions = Positions() + for pos in default_positions.poss: + assignments[pos] = draw(hst.characters()) + return assignments + + +def test_class_positions_available(): + assert Positions + + +def test_init_positions(positions): + assert positions + + +def test_positions_content(positions): + test_poss = positions.poss + assert test_poss + + +def test_positions_missing_left_outermost_column(positions): + missing_poss = ( + Pos(Side.LEFT, mod, Col.OUTERMOST, row) for mod in Mod for row in Row + ) + for pos in missing_poss: + assert pos not in positions.poss + + +def test_positions_missing_lower_upper_row(positions): + missing_poss = ( + Pos(side, Mod.LOWER, col, Row.UPPER) for side in Side for col in Col + ) + for pos in missing_poss: + assert pos not in positions.poss + + +def test_positions_missing_right_outermost_lower_key(positions): + missing_poss = (Pos(Side.RIGHT, mod, Col.OUTERMOST, Row.LOWER) for mod in Mod) + for pos in missing_poss: + assert pos not in positions.poss + + +def test_positions_missing_right_outermost_upper_key(positions): + missing_poss = ( + Pos(Side.RIGHT, mod, Col.OUTERMOST, Row.UPPER) + for mod in (Mod.SHIFT, Mod.UPPER, Mod.NONE) + ) + for pos in missing_poss: + assert pos not in positions.poss + + +def test_positions_missing_right_outermost_home_key(positions): + missing_poss = ( + Pos(Side.RIGHT, mod, Col.OUTERMOST, Row.HOME) for mod in (Mod.NAV, Mod.UPPER) + ) + for pos in missing_poss: + assert pos not in positions.poss + + +def test_positions_inners(positions): + poss = ( + Pos(side, mod, col, row) + for side in Side + for mod in Mod + for col in (Col.PINKY, Col.RING, Col.MIDDLE, Col.INDEX, Col.INNERMOST) + for row in (Row.HOME, Row.LOWER) + ) + for pos in poss: + assert pos in positions.poss + + +def test_positions_uppers(positions): + poss = ( + Pos(side, mod, col, Row.UPPER) + for side in Side + for mod in (Mod.NONE, Mod.SHIFT, Mod.UPPER, Mod.NAV) + for col in (Col.PINKY, Col.RING, Col.MIDDLE, Col.INDEX, Col.INNERMOST) + ) + for pos in poss: + assert pos in positions.poss + + +def test_positions_right_outermost_home_key(positions): + poss = ( + Pos(Side.RIGHT, mod, Col.OUTERMOST, Row.HOME) + for mod in (Mod.NONE, Mod.SHIFT, Mod.LOWER) + ) + for pos in poss: + assert pos in positions.poss + + +@given(assigns()) +def test_positions_with_visualization(assignments): + layout = make_layer_strs(assignments) + assert layout + assert ( + "UNMODIFIED:\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇥ " + f"| {assignments[Side.LEFT, Mod.NONE, Col.PINKY, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.NONE, Col.RING, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.NONE, Col.MIDDLE, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.NONE, Col.INDEX, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.NONE, Col.INNERMOST, Row.UPPER]} " + f"| " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.INNERMOST, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.INDEX, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.MIDDLE, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.RING, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.PINKY, Row.UPPER]} " + f"| ↠|\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⎈ " + f"" + f"| {assignments[Side.LEFT, Mod.NONE, Col.PINKY, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.NONE, Col.RING, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.NONE, Col.MIDDLE, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.NONE, Col.INDEX, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.NONE, Col.INNERMOST, Row.HOME]} " + f"| " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.INNERMOST, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.INDEX, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.MIDDLE, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.RING, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.PINKY, Row.HOME]} " + f"" + f"| {assignments[Side.RIGHT, Mod.NONE, Col.OUTERMOST, Row.HOME]} |\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇧ " + f"| {assignments[Side.LEFT, Mod.NONE, Col.PINKY, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.NONE, Col.RING, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.NONE, Col.MIDDLE, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.NONE, Col.INDEX, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.NONE, Col.INNERMOST, Row.LOWER]} " + f"| " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.INNERMOST, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.INDEX, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.MIDDLE, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.RING, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.NONE, Col.PINKY, Row.LOWER]} " + "| ⇧ |\n " + f"------------------------------------- " + f"-------------------------------------\n \n " + "SHIFT:\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇥ " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.PINKY, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.RING, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.MIDDLE, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.INDEX, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.INNERMOST, Row.UPPER]} " + f"| " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.INNERMOST, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.INDEX, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.MIDDLE, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.RING, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.PINKY, Row.UPPER]} " + f"| ↠|\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⎈ " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.PINKY, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.RING, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.MIDDLE, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.INDEX, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.INNERMOST, Row.HOME]} " + f"| " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.INNERMOST, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.INDEX, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.MIDDLE, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.RING, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.PINKY, Row.HOME]} " + f"" + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.OUTERMOST, Row.HOME]} |\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇧ " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.PINKY, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.RING, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.MIDDLE, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.INDEX, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.SHIFT, Col.INNERMOST, Row.LOWER]} " + f"| " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.INNERMOST, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.INDEX, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.MIDDLE, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.RING, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.SHIFT, Col.PINKY, Row.LOWER]} " + "| ⇧ |\n " + f"------------------------------------- " + f"-------------------------------------\n \n " + "LOWER:\n " + f"------------------------------------- " + f"-------------------------------------\n " + "| F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F10 | F11 " + "| F12 |\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇕ " + f"| {assignments[Side.LEFT, Mod.LOWER, Col.PINKY, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.LOWER, Col.RING, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.LOWER, Col.MIDDLE, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.LOWER, Col.INDEX, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.LOWER, Col.INNERMOST, Row.HOME]} " + f"| " + f"| {assignments[Side.RIGHT, Mod.LOWER, Col.INNERMOST, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.LOWER, Col.INDEX, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.LOWER, Col.MIDDLE, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.LOWER, Col.RING, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.LOWER, Col.PINKY, Row.HOME]} " + f"" + f"| {assignments[Side.RIGHT, Mod.LOWER, Col.OUTERMOST, Row.HOME]} |\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⎇ " + f"| {assignments[Side.LEFT, Mod.LOWER, Col.PINKY, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.LOWER, Col.RING, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.LOWER, Col.MIDDLE, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.LOWER, Col.INDEX, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.LOWER, Col.INNERMOST, Row.LOWER]} " + f"| " + f"| {assignments[Side.RIGHT, Mod.LOWER, Col.INNERMOST, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.LOWER, Col.INDEX, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.LOWER, Col.MIDDLE, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.LOWER, Col.RING, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.LOWER, Col.PINKY, Row.LOWER]} " + "|AltGr|\n " + f"------------------------------------- " + f"-------------------------------------\n \n " + "UPPER:\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇥ " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.PINKY, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.RING, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.MIDDLE, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.INDEX, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.INNERMOST, Row.UPPER]} " + f"| " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.INNERMOST, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.INDEX, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.MIDDLE, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.RING, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.PINKY, Row.UPPER]} " + f"| ⌦ |\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⎈ " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.PINKY, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.RING, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.MIDDLE, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.INDEX, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.INNERMOST, Row.HOME]} " + f"| " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.INNERMOST, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.INDEX, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.MIDDLE, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.RING, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.PINKY, Row.HOME]} " + f"| ⇕ |\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇧ " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.PINKY, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.RING, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.MIDDLE, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.INDEX, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.UPPER, Col.INNERMOST, Row.LOWER]} " + f"| " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.INNERMOST, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.INDEX, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.MIDDLE, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.RING, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.UPPER, Col.PINKY, Row.LOWER]} " + "|AltGr|\n " + f"------------------------------------- " + f"-------------------------------------\n \n " + "NAV:\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇥ " + f"| {assignments[Side.LEFT, Mod.NAV, Col.PINKY, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.NAV, Col.RING, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.NAV, Col.MIDDLE, Row.UPPER]} " + f"| {assignments[Side.LEFT, Mod.NAV, Col.INDEX, Row.UPPER]} " + f"" + f"| {assignments[Side.LEFT, Mod.NAV, Col.INNERMOST, Row.UPPER]} | " + f"| {assignments[Side.RIGHT, Mod.NAV, Col.INNERMOST, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.NAV, Col.INDEX, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.NAV, Col.MIDDLE, Row.UPPER]} " + f"" + f"| {assignments[Side.RIGHT, Mod.NAV, Col.RING, Row.UPPER]} " + f"| {assignments[Side.RIGHT, Mod.NAV, Col.PINKY, Row.UPPER]} | ↠|\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| " + f"| {assignments[Side.LEFT, Mod.NAV, Col.PINKY, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.NAV, Col.RING, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.NAV, Col.MIDDLE, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.NAV, Col.INDEX, Row.HOME]} " + f"| {assignments[Side.LEFT, Mod.NAV, Col.INNERMOST, Row.HOME]} " + f"| " + f"| {assignments[Side.RIGHT, Mod.NAV, Col.INNERMOST, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.NAV, Col.INDEX, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.NAV, Col.MIDDLE, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.NAV, Col.RING, Row.HOME]} " + f"| {assignments[Side.RIGHT, Mod.NAV, Col.PINKY, Row.HOME]} " + f"| |\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇧ " + f"| {assignments[Side.LEFT, Mod.NAV, Col.PINKY, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.NAV, Col.RING, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.NAV, Col.MIDDLE, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.NAV, Col.INDEX, Row.LOWER]} " + f"| {assignments[Side.LEFT, Mod.NAV, Col.INNERMOST, Row.LOWER]} " + f"| " + f"| {assignments[Side.RIGHT, Mod.NAV, Col.INNERMOST, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.NAV, Col.INDEX, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.NAV, Col.MIDDLE, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.NAV, Col.RING, Row.LOWER]} " + f"| {assignments[Side.RIGHT, Mod.NAV, Col.PINKY, Row.LOWER]} " + "| ⇧ |\n " + f"------------------------------------- " + f"-------------------------------------" + ) in layout -- GitLab From c21808274cacbc8236d907457e65f2649f82227b Mon Sep 17 00:00:00 2001 From: Bjoern Ludwig <bjoern.ludwig@ptb.de> Date: Mon, 14 Feb 2022 17:59:12 +0100 Subject: [PATCH 05/10] refactor(test_initialization): adapt tests to new Chars type --- test/test_initialization.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/test/test_initialization.py b/test/test_initialization.py index b56ddc1..ed759fd 100644 --- a/test/test_initialization.py +++ b/test/test_initialization.py @@ -2,13 +2,14 @@ from itertools import permutations import pytest +from ilp_keyboard_layout_optimization.data_aquisition.chars import Chars from ilp_keyboard_layout_optimization.ilp import KeyboardOptimization -from ilp_keyboard_layout_optimization.types import CharTuple +from ilp_keyboard_layout_optimization.type_aliases import CharTuple @pytest.fixture(scope="session") -def three_chars() -> CharTuple: - return "a", "b", "c" +def three_chars() -> Chars: + return Chars(("a", "b", "c")) @pytest.fixture(scope="session") @@ -31,8 +32,8 @@ def test_keyboard_optimization_char_pos_assigns_keys(three_chars, three_poss): linear_keys = tuple( KeyboardOptimization(three_chars, three_poss).char_pos_assigns_keys ) - assert len(linear_keys) == len(three_chars) * len(three_poss) - for char in three_chars: + assert len(linear_keys) == len(three_chars.chars) * len(three_poss) + for char in three_chars.chars: for pos in three_poss: assert (char, pos) in linear_keys @@ -41,10 +42,10 @@ def test_keyboard_optimization_quad_char_pos_assigns_keys(three_chars, three_pos quadratic_keys = tuple( KeyboardOptimization(three_chars, three_poss).quad_char_pos_assigns_keys ) - assert len(quadratic_keys) == len(three_chars) * (len(three_chars) - 1) * len( - three_poss - ) * (len(three_poss) - 1) - for (char, char_2) in permutations(three_chars, 2): + assert len(quadratic_keys) == len(three_chars.chars) * ( + len(three_chars.chars) - 1 + ) * len(three_poss) * (len(three_poss) - 1) + for (char, char_2) in permutations(three_chars.monos, 2): for (pos, pos_2) in permutations(three_poss, 2): assert (char, char_2, pos, pos_2) in quadratic_keys -- GitLab From ef9fd80b6510d90ae3012507209c95f56f23df26 Mon Sep 17 00:00:00 2001 From: Bjoern Ludwig <bjoern.ludwig@ptb.de> Date: Mon, 14 Feb 2022 17:59:41 +0100 Subject: [PATCH 06/10] feat(visualize): introduce sophisticated visualization module --- .../visualize.py | 220 ++++ test/test_visualize.py | 942 ++++++++++++++++++ 2 files changed, 1162 insertions(+) create mode 100644 src/ilp_keyboard_layout_optimization/visualize.py create mode 100644 test/test_visualize.py diff --git a/src/ilp_keyboard_layout_optimization/visualize.py b/src/ilp_keyboard_layout_optimization/visualize.py new file mode 100644 index 0000000..d6f90c5 --- /dev/null +++ b/src/ilp_keyboard_layout_optimization/visualize.py @@ -0,0 +1,220 @@ +from typing import Dict + +from ilp_keyboard_layout_optimization.type_aliases import ( + Char, + Col, + Mod, + Pos, + PosTuple, + Row, + Side, +) + + +def make_layer_strs(poss: Dict[PosTuple, Char]): + """Create UNICODE string of the different layers""" + home_str = """ + UNMODIFIED: + ------------------------------------- ------------------------------------- + | ⇥ | {} | {} | {} | {} | {} | | {} | {} | {} | {} | {} | ↠| + ------------------------------------- ------------------------------------- + | ⎈ | {} | {} | {} | {} | {} | | {} | {} | {} | {} | {} | {} | + ------------------------------------- ------------------------------------- + | ⇧ | {} | {} | {} | {} | {} | | {} | {} | {} | {} | {} | ⇧ | + ------------------------------------- ------------------------------------- + """ + shifted_str = """ + SHIFT: + ------------------------------------- ------------------------------------- + | ⇥ | {} | {} | {} | {} | {} | | {} | {} | {} | {} | {} | ↠| + ------------------------------------- ------------------------------------- + | ⎈ | {} | {} | {} | {} | {} | | {} | {} | {} | {} | {} | {} | + ------------------------------------- ------------------------------------- + | ⇧ | {} | {} | {} | {} | {} | | {} | {} | {} | {} | {} | ⇧ | + ------------------------------------- ------------------------------------- + """ + lowered_str = """ + LOWER: + ------------------------------------- ------------------------------------- + | F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F10 | F11 | F12 | + ------------------------------------- ------------------------------------- + | ⇕ | {} | {} | {} | {} | {} | | {} | {} | {} | {} | {} | {} | + ------------------------------------- ------------------------------------- + | ⎇ | {} | {} | {} | {} | {} | | {} | {} | {} | {} | {} |AltGr| + ------------------------------------- ------------------------------------- + """ + raised_str = """ + UPPER: + ------------------------------------- ------------------------------------- + | ⇥ | {} | {} | {} | {} | {} | | {} | {} | {} | {} | {} | ⌦ | + ------------------------------------- ------------------------------------- + | ⎈ | {} | {} | {} | {} | {} | | {} | {} | {} | {} | {} | ⇕ | + ------------------------------------- ------------------------------------- + | ⇧ | {} | {} | {} | {} | {} | | {} | {} | {} | {} | {} |AltGr| + ------------------------------------- ------------------------------------- + """ + nav_str = """ + NAV: + ------------------------------------- ------------------------------------- + | ⇥ | {} | {} | {} | {} | {} | | {} | {} | {} | {} | {} | ↠| + ------------------------------------- ------------------------------------- + | | {} | {} | {} | {} | {} | | {} | {} | {} | {} | {} | | + ------------------------------------- ------------------------------------- + | ⇧ | {} | {} | {} | {} | {} | | {} | {} | {} | {} | {} | ⇧ | + ------------------------------------- ------------------------------------- + """ + return ( + home_str.format( + poss.get((Side.LEFT, Mod.NONE, Col.PINKY, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.NONE, Col.RING, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.NONE, Col.MIDDLE, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.NONE, Col.INDEX, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.NONE, Col.INNERMOST, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.INNERMOST, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.INDEX, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.MIDDLE, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.RING, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.PINKY, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.NONE, Col.PINKY, Row.HOME), " "), + poss.get((Side.LEFT, Mod.NONE, Col.RING, Row.HOME), " "), + poss.get((Side.LEFT, Mod.NONE, Col.MIDDLE, Row.HOME), " "), + poss.get((Side.LEFT, Mod.NONE, Col.INDEX, Row.HOME), " "), + poss.get((Side.LEFT, Mod.NONE, Col.INNERMOST, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.INNERMOST, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.INDEX, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.MIDDLE, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.RING, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.PINKY, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.OUTERMOST, Row.HOME), " "), + poss.get((Side.LEFT, Mod.NONE, Col.PINKY, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.NONE, Col.RING, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.NONE, Col.MIDDLE, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.NONE, Col.INDEX, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.NONE, Col.INNERMOST, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.INNERMOST, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.INDEX, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.MIDDLE, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.RING, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.NONE, Col.PINKY, Row.LOWER), " "), + ) + + shifted_str.format( + poss.get((Side.LEFT, Mod.SHIFT, Col.PINKY, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.SHIFT, Col.RING, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.SHIFT, Col.MIDDLE, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.SHIFT, Col.INDEX, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.SHIFT, Col.INNERMOST, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.INNERMOST, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.INDEX, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.MIDDLE, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.RING, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.PINKY, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.SHIFT, Col.PINKY, Row.HOME), " "), + poss.get((Side.LEFT, Mod.SHIFT, Col.RING, Row.HOME), " "), + poss.get((Side.LEFT, Mod.SHIFT, Col.MIDDLE, Row.HOME), " "), + poss.get((Side.LEFT, Mod.SHIFT, Col.INDEX, Row.HOME), " "), + poss.get((Side.LEFT, Mod.SHIFT, Col.INNERMOST, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.INNERMOST, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.INDEX, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.MIDDLE, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.RING, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.PINKY, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.OUTERMOST, Row.HOME), " "), + poss.get((Side.LEFT, Mod.SHIFT, Col.PINKY, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.SHIFT, Col.RING, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.SHIFT, Col.MIDDLE, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.SHIFT, Col.INDEX, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.SHIFT, Col.INNERMOST, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.INNERMOST, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.INDEX, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.MIDDLE, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.RING, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.SHIFT, Col.PINKY, Row.LOWER), " "), + ) + + lowered_str.format( + poss.get((Side.LEFT, Mod.LOWER, Col.PINKY, Row.HOME), " "), + poss.get((Side.LEFT, Mod.LOWER, Col.RING, Row.HOME), " "), + poss.get((Side.LEFT, Mod.LOWER, Col.MIDDLE, Row.HOME), " "), + poss.get((Side.LEFT, Mod.LOWER, Col.INDEX, Row.HOME), " "), + poss.get((Side.LEFT, Mod.LOWER, Col.INNERMOST, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.LOWER, Col.INNERMOST, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.LOWER, Col.INDEX, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.LOWER, Col.MIDDLE, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.LOWER, Col.RING, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.LOWER, Col.PINKY, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.LOWER, Col.OUTERMOST, Row.HOME), " "), + poss.get((Side.LEFT, Mod.LOWER, Col.PINKY, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.LOWER, Col.RING, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.LOWER, Col.MIDDLE, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.LOWER, Col.INDEX, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.LOWER, Col.INNERMOST, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.LOWER, Col.INNERMOST, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.LOWER, Col.INDEX, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.LOWER, Col.MIDDLE, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.LOWER, Col.RING, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.LOWER, Col.PINKY, Row.LOWER), " "), + ) + + raised_str.format( + poss.get((Side.LEFT, Mod.UPPER, Col.PINKY, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.UPPER, Col.RING, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.UPPER, Col.MIDDLE, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.UPPER, Col.INDEX, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.UPPER, Col.INNERMOST, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.INNERMOST, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.INDEX, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.MIDDLE, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.RING, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.PINKY, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.UPPER, Col.PINKY, Row.HOME), " "), + poss.get((Side.LEFT, Mod.UPPER, Col.RING, Row.HOME), " "), + poss.get((Side.LEFT, Mod.UPPER, Col.MIDDLE, Row.HOME), " "), + poss.get((Side.LEFT, Mod.UPPER, Col.INDEX, Row.HOME), " "), + poss.get((Side.LEFT, Mod.UPPER, Col.INNERMOST, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.INNERMOST, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.INDEX, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.MIDDLE, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.RING, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.PINKY, Row.HOME), " "), + poss.get((Side.LEFT, Mod.UPPER, Col.PINKY, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.UPPER, Col.RING, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.UPPER, Col.MIDDLE, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.UPPER, Col.INDEX, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.UPPER, Col.INNERMOST, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.INNERMOST, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.INDEX, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.MIDDLE, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.RING, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.UPPER, Col.PINKY, Row.LOWER), " "), + ) + + nav_str.format( + poss.get((Side.LEFT, Mod.NAV, Col.PINKY, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.NAV, Col.RING, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.NAV, Col.MIDDLE, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.NAV, Col.INDEX, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.NAV, Col.INNERMOST, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.INNERMOST, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.INDEX, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.MIDDLE, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.RING, Row.UPPER), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.PINKY, Row.UPPER), " "), + poss.get((Side.LEFT, Mod.NAV, Col.PINKY, Row.HOME), " "), + poss.get((Side.LEFT, Mod.NAV, Col.RING, Row.HOME), " "), + poss.get((Side.LEFT, Mod.NAV, Col.MIDDLE, Row.HOME), " "), + poss.get((Side.LEFT, Mod.NAV, Col.INDEX, Row.HOME), " "), + poss.get((Side.LEFT, Mod.NAV, Col.INNERMOST, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.INNERMOST, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.INDEX, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.MIDDLE, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.RING, Row.HOME), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.PINKY, Row.HOME), " "), + poss.get((Side.LEFT, Mod.NAV, Col.PINKY, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.NAV, Col.RING, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.NAV, Col.MIDDLE, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.NAV, Col.INDEX, Row.LOWER), " "), + poss.get((Side.LEFT, Mod.NAV, Col.INNERMOST, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.INNERMOST, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.INDEX, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.MIDDLE, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.RING, Row.LOWER), " "), + poss.get((Side.RIGHT, Mod.NAV, Col.PINKY, Row.LOWER), " "), + ) + ) diff --git a/test/test_visualize.py b/test/test_visualize.py new file mode 100644 index 0000000..800662a --- /dev/null +++ b/test/test_visualize.py @@ -0,0 +1,942 @@ +from hypothesis import given +from hypothesis.strategies import characters as chrs + +from ilp_keyboard_layout_optimization.type_aliases import Col, Mod, Pos, Row, Side +from ilp_keyboard_layout_optimization.visualize import make_layer_strs + + +def test_make_layer_strs_function(): + assert make_layer_strs + + +def test_make_layer_strs_len(): + assert len(make_layer_strs({})) == 3023 + + +def test_make_layer_strs_all_modifiers_there(): + layout_string = make_layer_strs({}) + for mod in Mod: + if mod.name == "NONE": + assert "UNMODIFIED" in layout_string + else: + assert mod.name in layout_string + print(layout_string) + + +@given(chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs()) +def test_make_layer_strs_with_unmodified_upper( + char0, char1, char2, char3, char4, char5, char6, char7, char8, char9 +): + layout_string = make_layer_strs( + { + Pos(Side.LEFT, Mod.NONE, Col.PINKY, Row.UPPER): char0, + Pos(Side.LEFT, Mod.NONE, Col.RING, Row.UPPER): char1, + Pos(Side.LEFT, Mod.NONE, Col.MIDDLE, Row.UPPER): char2, + Pos(Side.LEFT, Mod.NONE, Col.INDEX, Row.UPPER): char3, + Pos(Side.LEFT, Mod.NONE, Col.INNERMOST, Row.UPPER): char4, + Pos(Side.RIGHT, Mod.NONE, Col.INNERMOST, Row.UPPER): char5, + Pos(Side.RIGHT, Mod.NONE, Col.INDEX, Row.UPPER): char6, + Pos(Side.RIGHT, Mod.NONE, Col.MIDDLE, Row.UPPER): char7, + Pos(Side.RIGHT, Mod.NONE, Col.RING, Row.UPPER): char8, + Pos(Side.RIGHT, Mod.NONE, Col.PINKY, Row.UPPER): char9, + }, + ) + assert ( + f"| ⇥ | {char0} | {char1} | {char2} | {char3} | {char4} " + f"| | {char5} | {char6} | {char7} | {char8} | {char9} " + f"| ↠|" in layout_string + ) + + +@given( + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), +) +def test_make_layer_strs_with_unmodified_home( + char0, char1, char2, char3, char4, char5, char6, char7, char8, char9, char10 +): + layout_string = make_layer_strs( + { + Pos(Side.LEFT, Mod.NONE, Col.PINKY, Row.HOME): char0, + Pos(Side.LEFT, Mod.NONE, Col.RING, Row.HOME): char1, + Pos(Side.LEFT, Mod.NONE, Col.MIDDLE, Row.HOME): char2, + Pos(Side.LEFT, Mod.NONE, Col.INDEX, Row.HOME): char3, + Pos(Side.LEFT, Mod.NONE, Col.INNERMOST, Row.HOME): char4, + Pos(Side.RIGHT, Mod.NONE, Col.INNERMOST, Row.HOME): char5, + Pos(Side.RIGHT, Mod.NONE, Col.INDEX, Row.HOME): char6, + Pos(Side.RIGHT, Mod.NONE, Col.MIDDLE, Row.HOME): char7, + Pos(Side.RIGHT, Mod.NONE, Col.RING, Row.HOME): char8, + Pos(Side.RIGHT, Mod.NONE, Col.PINKY, Row.HOME): char9, + Pos(Side.RIGHT, Mod.NONE, Col.OUTERMOST, Row.HOME): char10, + }, + ) + assert ( + f"| ⎈ | {char0} | {char1} | {char2} | {char3} | {char4} " + f"| | {char5} | {char6} | {char7} | {char8} | {char9} " + f"| {char10} |" in layout_string + ) + + +@given(chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs()) +def test_make_layer_strs_with_unmodified_lower( + char0, char1, char2, char3, char4, char5, char6, char7, char8, char9 +): + layout_string = make_layer_strs( + { + Pos(Side.LEFT, Mod.NONE, Col.PINKY, Row.LOWER): char0, + Pos(Side.LEFT, Mod.NONE, Col.RING, Row.LOWER): char1, + Pos(Side.LEFT, Mod.NONE, Col.MIDDLE, Row.LOWER): char2, + Pos(Side.LEFT, Mod.NONE, Col.INDEX, Row.LOWER): char3, + Pos(Side.LEFT, Mod.NONE, Col.INNERMOST, Row.LOWER): char4, + Pos(Side.RIGHT, Mod.NONE, Col.INNERMOST, Row.LOWER): char5, + Pos(Side.RIGHT, Mod.NONE, Col.INDEX, Row.LOWER): char6, + Pos(Side.RIGHT, Mod.NONE, Col.MIDDLE, Row.LOWER): char7, + Pos(Side.RIGHT, Mod.NONE, Col.RING, Row.LOWER): char8, + Pos(Side.RIGHT, Mod.NONE, Col.PINKY, Row.LOWER): char9, + }, + ) + assert ( + f"| ⇧ | {char0} | {char1} | {char2} | {char3} | {char4} " + f"| | {char5} | {char6} | {char7} | {char8} | {char9} " + "| ⇧ |" in layout_string + ) + + +@given(chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs()) +def test_make_layer_strs_with_shifted_upper( + char_1, char_2, char_3, char_4, char_5, char_6, char_7, char_8, char_9, char_0 +): + layout_string = make_layer_strs( + { + Pos(Side.LEFT, Mod.SHIFT, Col.PINKY, Row.UPPER): char_1, + Pos(Side.LEFT, Mod.SHIFT, Col.RING, Row.UPPER): char_2, + Pos(Side.LEFT, Mod.SHIFT, Col.MIDDLE, Row.UPPER): char_3, + Pos(Side.LEFT, Mod.SHIFT, Col.INDEX, Row.UPPER): char_4, + Pos(Side.LEFT, Mod.SHIFT, Col.INNERMOST, Row.UPPER): char_5, + Pos(Side.RIGHT, Mod.SHIFT, Col.INNERMOST, Row.UPPER): char_6, + Pos(Side.RIGHT, Mod.SHIFT, Col.INDEX, Row.UPPER): char_7, + Pos(Side.RIGHT, Mod.SHIFT, Col.MIDDLE, Row.UPPER): char_8, + Pos(Side.RIGHT, Mod.SHIFT, Col.RING, Row.UPPER): char_9, + Pos(Side.RIGHT, Mod.SHIFT, Col.PINKY, Row.UPPER): char_0, + }, + ) + assert ( + f"| ⇥ | {char_1} | {char_2} | {char_3} | {char_4} | {char_5} " + f"| | {char_6} | {char_7} | {char_8} | {char_9} | {char_0} " + f"| ↠|" in layout_string + ) + + +@given( + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), +) +def test_make_layer_strs_with_shifted_home( + char0, char1, char2, char3, char4, char5, char6, char7, char8, char9, char10 +): + layout_string = make_layer_strs( + { + Pos(Side.LEFT, Mod.SHIFT, Col.PINKY, Row.HOME): char0, + Pos(Side.LEFT, Mod.SHIFT, Col.RING, Row.HOME): char1, + Pos(Side.LEFT, Mod.SHIFT, Col.MIDDLE, Row.HOME): char2, + Pos(Side.LEFT, Mod.SHIFT, Col.INDEX, Row.HOME): char3, + Pos(Side.LEFT, Mod.SHIFT, Col.INNERMOST, Row.HOME): char4, + Pos(Side.RIGHT, Mod.SHIFT, Col.INNERMOST, Row.HOME): char5, + Pos(Side.RIGHT, Mod.SHIFT, Col.INDEX, Row.HOME): char6, + Pos(Side.RIGHT, Mod.SHIFT, Col.MIDDLE, Row.HOME): char7, + Pos(Side.RIGHT, Mod.SHIFT, Col.RING, Row.HOME): char8, + Pos(Side.RIGHT, Mod.SHIFT, Col.PINKY, Row.HOME): char9, + Pos(Side.RIGHT, Mod.SHIFT, Col.OUTERMOST, Row.HOME): char10, + }, + ) + assert ( + f"| ⎈ | {char0} | {char1} | {char2} | {char3} | {char4} " + f"| | {char5} | {char6} | {char7} | {char8} | {char9} " + f"| {char10} |" in layout_string + ) + + +@given(chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs()) +def test_make_layer_strs_with_shifted_lower( + char0, char1, char2, char3, char4, char5, char6, char7, char8, char9 +): + layout_string = make_layer_strs( + { + Pos(Side.LEFT, Mod.SHIFT, Col.PINKY, Row.LOWER): char0, + Pos(Side.LEFT, Mod.SHIFT, Col.RING, Row.LOWER): char1, + Pos(Side.LEFT, Mod.SHIFT, Col.MIDDLE, Row.LOWER): char2, + Pos(Side.LEFT, Mod.SHIFT, Col.INDEX, Row.LOWER): char3, + Pos(Side.LEFT, Mod.SHIFT, Col.INNERMOST, Row.LOWER): char4, + Pos(Side.RIGHT, Mod.SHIFT, Col.INNERMOST, Row.LOWER): char5, + Pos(Side.RIGHT, Mod.SHIFT, Col.INDEX, Row.LOWER): char6, + Pos(Side.RIGHT, Mod.SHIFT, Col.MIDDLE, Row.LOWER): char7, + Pos(Side.RIGHT, Mod.SHIFT, Col.RING, Row.LOWER): char8, + Pos(Side.RIGHT, Mod.SHIFT, Col.PINKY, Row.LOWER): char9, + }, + ) + assert ( + f"| ⇧ | {char0} | {char1} | {char2} | {char3} | {char4} " + f"| | {char5} | {char6} | {char7} | {char8} | {char9} " + "| ⇧ |" in layout_string + ) + + +@given( + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), +) +def test_make_layer_strs_with_lower_home( + char0, char1, char2, char3, char4, char5, char6, char7, char8, char9, char10 +): + layout_string = make_layer_strs( + { + Pos(Side.LEFT, Mod.LOWER, Col.PINKY, Row.HOME): char0, + Pos(Side.LEFT, Mod.LOWER, Col.RING, Row.HOME): char1, + Pos(Side.LEFT, Mod.LOWER, Col.MIDDLE, Row.HOME): char2, + Pos(Side.LEFT, Mod.LOWER, Col.INDEX, Row.HOME): char3, + Pos(Side.LEFT, Mod.LOWER, Col.INNERMOST, Row.HOME): char4, + Pos(Side.RIGHT, Mod.LOWER, Col.INNERMOST, Row.HOME): char5, + Pos(Side.RIGHT, Mod.LOWER, Col.INDEX, Row.HOME): char6, + Pos(Side.RIGHT, Mod.LOWER, Col.MIDDLE, Row.HOME): char7, + Pos(Side.RIGHT, Mod.LOWER, Col.RING, Row.HOME): char8, + Pos(Side.RIGHT, Mod.LOWER, Col.PINKY, Row.HOME): char9, + Pos(Side.RIGHT, Mod.LOWER, Col.OUTERMOST, Row.HOME): char10, + }, + ) + assert ( + f"| ⇕ | {char0} | {char1} | {char2} | {char3} | {char4} " + f"| | {char5} | {char6} | {char7} | {char8} | {char9} " + f"| {char10} |" in layout_string + ) + + +@given(chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs()) +def test_make_layer_strs_with_lower_lower( + char0, char1, char2, char3, char4, char5, char6, char7, char8, char9 +): + layout_string = make_layer_strs( + { + Pos(Side.LEFT, Mod.LOWER, Col.PINKY, Row.LOWER): char0, + Pos(Side.LEFT, Mod.LOWER, Col.RING, Row.LOWER): char1, + Pos(Side.LEFT, Mod.LOWER, Col.MIDDLE, Row.LOWER): char2, + Pos(Side.LEFT, Mod.LOWER, Col.INDEX, Row.LOWER): char3, + Pos(Side.LEFT, Mod.LOWER, Col.INNERMOST, Row.LOWER): char4, + Pos(Side.RIGHT, Mod.LOWER, Col.INNERMOST, Row.LOWER): char5, + Pos(Side.RIGHT, Mod.LOWER, Col.INDEX, Row.LOWER): char6, + Pos(Side.RIGHT, Mod.LOWER, Col.MIDDLE, Row.LOWER): char7, + Pos(Side.RIGHT, Mod.LOWER, Col.RING, Row.LOWER): char8, + Pos(Side.RIGHT, Mod.LOWER, Col.PINKY, Row.LOWER): char9, + }, + ) + assert ( + f"| ⎇ | {char0} | {char1} | {char2} | {char3} | {char4} " + f"| | {char5} | {char6} | {char7} | {char8} | {char9} " + "|AltGr|" in layout_string + ) + + +@given(chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs()) +def test_make_layer_strs_with_upper_upper( + char_1, char_2, char_3, char_4, char_5, char_6, char_7, char_8, char_9, char_0 +): + layout_string = make_layer_strs( + { + Pos(Side.LEFT, Mod.UPPER, Col.PINKY, Row.UPPER): char_1, + Pos(Side.LEFT, Mod.UPPER, Col.RING, Row.UPPER): char_2, + Pos(Side.LEFT, Mod.UPPER, Col.MIDDLE, Row.UPPER): char_3, + Pos(Side.LEFT, Mod.UPPER, Col.INDEX, Row.UPPER): char_4, + Pos(Side.LEFT, Mod.UPPER, Col.INNERMOST, Row.UPPER): char_5, + Pos(Side.RIGHT, Mod.UPPER, Col.INNERMOST, Row.UPPER): char_6, + Pos(Side.RIGHT, Mod.UPPER, Col.INDEX, Row.UPPER): char_7, + Pos(Side.RIGHT, Mod.UPPER, Col.MIDDLE, Row.UPPER): char_8, + Pos(Side.RIGHT, Mod.UPPER, Col.RING, Row.UPPER): char_9, + Pos(Side.RIGHT, Mod.UPPER, Col.PINKY, Row.UPPER): char_0, + }, + ) + assert ( + f"| ⇥ | {char_1} | {char_2} | {char_3} | {char_4} | {char_5} " + f"| | {char_6} | {char_7} | {char_8} | {char_9} | {char_0} " + f"| ⌦ |" in layout_string + ) + + +@given(chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs()) +def test_make_layer_strs_with_upper_home( + char0, char1, char2, char3, char4, char5, char6, char7, char8, char9 +): + assert ( + f"| ⎈ | {char0} | {char1} | {char2} | {char3} | {char4} " + f"| | {char5} | {char6} | {char7} | {char8} | {char9} " + f"| ⇕ |" + in make_layer_strs( + { + Pos(Side.LEFT, Mod.UPPER, Col.PINKY, Row.HOME): char0, + Pos(Side.LEFT, Mod.UPPER, Col.RING, Row.HOME): char1, + Pos(Side.LEFT, Mod.UPPER, Col.MIDDLE, Row.HOME): char2, + Pos(Side.LEFT, Mod.UPPER, Col.INDEX, Row.HOME): char3, + Pos(Side.LEFT, Mod.UPPER, Col.INNERMOST, Row.HOME): char4, + Pos(Side.RIGHT, Mod.UPPER, Col.INNERMOST, Row.HOME): char5, + Pos(Side.RIGHT, Mod.UPPER, Col.INDEX, Row.HOME): char6, + Pos(Side.RIGHT, Mod.UPPER, Col.MIDDLE, Row.HOME): char7, + Pos(Side.RIGHT, Mod.UPPER, Col.RING, Row.HOME): char8, + Pos(Side.RIGHT, Mod.UPPER, Col.PINKY, Row.HOME): char9, + }, + ) + ) + + +@given(chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs()) +def test_make_layer_strs_with_upper_lower( + char0, char1, char2, char3, char4, char5, char6, char7, char8, char9 +): + assert ( + f"| ⇧ | {char0} | {char1} | {char2} | {char3} | {char4} " + f"| | {char5} | {char6} | {char7} | {char8} | {char9} " + "|AltGr|" + in make_layer_strs( + { + Pos(Side.LEFT, Mod.UPPER, Col.PINKY, Row.LOWER): char0, + Pos(Side.LEFT, Mod.UPPER, Col.RING, Row.LOWER): char1, + Pos(Side.LEFT, Mod.UPPER, Col.MIDDLE, Row.LOWER): char2, + Pos(Side.LEFT, Mod.UPPER, Col.INDEX, Row.LOWER): char3, + Pos(Side.LEFT, Mod.UPPER, Col.INNERMOST, Row.LOWER): char4, + Pos(Side.RIGHT, Mod.UPPER, Col.INNERMOST, Row.LOWER): char5, + Pos(Side.RIGHT, Mod.UPPER, Col.INDEX, Row.LOWER): char6, + Pos(Side.RIGHT, Mod.UPPER, Col.MIDDLE, Row.LOWER): char7, + Pos(Side.RIGHT, Mod.UPPER, Col.RING, Row.LOWER): char8, + Pos(Side.RIGHT, Mod.UPPER, Col.PINKY, Row.LOWER): char9, + }, + ) + ) + + +@given(chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs()) +def test_make_layer_strs_with_nav_upper( + char_1, char_2, char_3, char_4, char_5, char_6, char_7, char_8, char_9, char_0 +): + layout_string = make_layer_strs( + { + Pos(Side.LEFT, Mod.NAV, Col.PINKY, Row.UPPER): char_1, + Pos(Side.LEFT, Mod.NAV, Col.RING, Row.UPPER): char_2, + Pos(Side.LEFT, Mod.NAV, Col.MIDDLE, Row.UPPER): char_3, + Pos(Side.LEFT, Mod.NAV, Col.INDEX, Row.UPPER): char_4, + Pos(Side.LEFT, Mod.NAV, Col.INNERMOST, Row.UPPER): char_5, + Pos(Side.RIGHT, Mod.NAV, Col.INNERMOST, Row.UPPER): char_6, + Pos(Side.RIGHT, Mod.NAV, Col.INDEX, Row.UPPER): char_7, + Pos(Side.RIGHT, Mod.NAV, Col.MIDDLE, Row.UPPER): char_8, + Pos(Side.RIGHT, Mod.NAV, Col.RING, Row.UPPER): char_9, + Pos(Side.RIGHT, Mod.NAV, Col.PINKY, Row.UPPER): char_0, + }, + ) + assert ( + f"| ⇥ | {char_1} | {char_2} | {char_3} | {char_4} | {char_5} " + f"| | {char_6} | {char_7} | {char_8} | {char_9} | {char_0} " + f"| ↠|" in layout_string + ) + + +@given(chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs()) +def test_make_layer_strs_with_nav_home( + char0, char1, char2, char3, char4, char5, char6, char7, char8, char9 +): + assert ( + f"| | {char0} | {char1} | {char2} | {char3} | {char4} " + f"| | {char5} | {char6} | {char7} | {char8} | {char9} " + f"| |" + in make_layer_strs( + { + Pos(Side.LEFT, Mod.NAV, Col.PINKY, Row.HOME): char0, + Pos(Side.LEFT, Mod.NAV, Col.RING, Row.HOME): char1, + Pos(Side.LEFT, Mod.NAV, Col.MIDDLE, Row.HOME): char2, + Pos(Side.LEFT, Mod.NAV, Col.INDEX, Row.HOME): char3, + Pos(Side.LEFT, Mod.NAV, Col.INNERMOST, Row.HOME): char4, + Pos(Side.RIGHT, Mod.NAV, Col.INNERMOST, Row.HOME): char5, + Pos(Side.RIGHT, Mod.NAV, Col.INDEX, Row.HOME): char6, + Pos(Side.RIGHT, Mod.NAV, Col.MIDDLE, Row.HOME): char7, + Pos(Side.RIGHT, Mod.NAV, Col.RING, Row.HOME): char8, + Pos(Side.RIGHT, Mod.NAV, Col.PINKY, Row.HOME): char9, + }, + ) + ) + + +@given(chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs(), chrs()) +def test_make_layer_strs_with_nav_lower( + char0, char1, char2, char3, char4, char5, char6, char7, char8, char9 +): + assert ( + f"| ⇧ | {char0} | {char1} | {char2} | {char3} | {char4} " + f"| | {char5} | {char6} | {char7} | {char8} | {char9} " + "| ⇧ |" + in make_layer_strs( + { + Pos(Side.LEFT, Mod.NAV, Col.PINKY, Row.LOWER): char0, + Pos(Side.LEFT, Mod.NAV, Col.RING, Row.LOWER): char1, + Pos(Side.LEFT, Mod.NAV, Col.MIDDLE, Row.LOWER): char2, + Pos(Side.LEFT, Mod.NAV, Col.INDEX, Row.LOWER): char3, + Pos(Side.LEFT, Mod.NAV, Col.INNERMOST, Row.LOWER): char4, + Pos(Side.RIGHT, Mod.NAV, Col.INNERMOST, Row.LOWER): char5, + Pos(Side.RIGHT, Mod.NAV, Col.INDEX, Row.LOWER): char6, + Pos(Side.RIGHT, Mod.NAV, Col.MIDDLE, Row.LOWER): char7, + Pos(Side.RIGHT, Mod.NAV, Col.RING, Row.LOWER): char8, + Pos(Side.RIGHT, Mod.NAV, Col.PINKY, Row.LOWER): char9, + }, + ) + ) + + +@given( + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), + chrs(), +) +def test_make_layer_strs_with_all_positions_set_manually_randomly( + char0, + char1, + char2, + char3, + char4, + char5, + char6, + char7, + char8, + char9, + char10, + char11, + char12, + char13, + char14, + char15, + char16, + char17, + char18, + char19, + char110, + char20, + char21, + char22, + char23, + char24, + char25, + char26, + char27, + char28, + char29, + char_31, + char_32, + char_33, + char_34, + char_35, + char_36, + char_37, + char_38, + char_39, + char_30, + char40, + char41, + char42, + char43, + char44, + char45, + char46, + char47, + char48, + char49, + char410, + char50, + char51, + char52, + char53, + char54, + char55, + char56, + char57, + char58, + char59, + char60, + char61, + char62, + char63, + char64, + char65, + char66, + char67, + char68, + char69, + char610, + char70, + char71, + char72, + char73, + char74, + char75, + char76, + char77, + char78, + char79, + char8_1, + char8_2, + char8_3, + char8_4, + char8_5, + char8_6, + char8_7, + char8_8, + char8_9, + char8_0, + char90, + char91, + char92, + char93, + char94, + char95, + char96, + char97, + char98, + char99, + char100, + char101, + char102, + char103, + char104, + char105, + char106, + char107, + char108, + char109, + char11_1, + char11_2, + char11_3, + char11_4, + char11_5, + char11_6, + char11_7, + char11_8, + char11_9, + char11_0, + char120, + char121, + char122, + char123, + char124, + char125, + char126, + char127, + char128, + char129, + char130, + char131, + char132, + char133, + char134, + char135, + char136, + char137, + char138, + char139, +): + layout = make_layer_strs( + { + Pos(Side.LEFT, Mod.NAV, Col.PINKY, Row.LOWER): char130, + Pos(Side.LEFT, Mod.NAV, Col.RING, Row.LOWER): char131, + Pos(Side.LEFT, Mod.NAV, Col.MIDDLE, Row.LOWER): char132, + Pos(Side.LEFT, Mod.NAV, Col.INDEX, Row.LOWER): char133, + Pos(Side.LEFT, Mod.NAV, Col.INNERMOST, Row.LOWER): char134, + Pos(Side.RIGHT, Mod.NAV, Col.INNERMOST, Row.LOWER): char135, + Pos(Side.RIGHT, Mod.NAV, Col.INDEX, Row.LOWER): char136, + Pos(Side.RIGHT, Mod.NAV, Col.MIDDLE, Row.LOWER): char137, + Pos(Side.RIGHT, Mod.NAV, Col.RING, Row.LOWER): char138, + Pos(Side.RIGHT, Mod.NAV, Col.PINKY, Row.LOWER): char139, + Pos(Side.LEFT, Mod.LOWER, Col.PINKY, Row.HOME): char60, + Pos(Side.LEFT, Mod.LOWER, Col.RING, Row.HOME): char61, + Pos(Side.LEFT, Mod.LOWER, Col.MIDDLE, Row.HOME): char62, + Pos(Side.LEFT, Mod.LOWER, Col.INDEX, Row.HOME): char63, + Pos(Side.LEFT, Mod.LOWER, Col.INNERMOST, Row.HOME): char64, + Pos(Side.RIGHT, Mod.LOWER, Col.INNERMOST, Row.HOME): char65, + Pos(Side.RIGHT, Mod.LOWER, Col.INDEX, Row.HOME): char66, + Pos(Side.RIGHT, Mod.LOWER, Col.MIDDLE, Row.HOME): char67, + Pos(Side.RIGHT, Mod.LOWER, Col.RING, Row.HOME): char68, + Pos(Side.RIGHT, Mod.LOWER, Col.PINKY, Row.HOME): char69, + Pos(Side.RIGHT, Mod.LOWER, Col.OUTERMOST, Row.HOME): char610, + Pos(Side.LEFT, Mod.NONE, Col.PINKY, Row.UPPER): char0, + Pos(Side.LEFT, Mod.NONE, Col.RING, Row.UPPER): char1, + Pos(Side.LEFT, Mod.NONE, Col.MIDDLE, Row.UPPER): char2, + Pos(Side.LEFT, Mod.NONE, Col.INDEX, Row.UPPER): char3, + Pos(Side.LEFT, Mod.NONE, Col.INNERMOST, Row.UPPER): char4, + Pos(Side.RIGHT, Mod.NONE, Col.INNERMOST, Row.UPPER): char5, + Pos(Side.RIGHT, Mod.NONE, Col.INDEX, Row.UPPER): char6, + Pos(Side.RIGHT, Mod.NONE, Col.MIDDLE, Row.UPPER): char7, + Pos(Side.RIGHT, Mod.NONE, Col.RING, Row.UPPER): char8, + Pos(Side.RIGHT, Mod.NONE, Col.PINKY, Row.UPPER): char9, + Pos(Side.LEFT, Mod.NONE, Col.PINKY, Row.HOME): char10, + Pos(Side.LEFT, Mod.NONE, Col.RING, Row.HOME): char11, + Pos(Side.LEFT, Mod.NONE, Col.MIDDLE, Row.HOME): char12, + Pos(Side.LEFT, Mod.NONE, Col.INDEX, Row.HOME): char13, + Pos(Side.LEFT, Mod.NONE, Col.INNERMOST, Row.HOME): char14, + Pos(Side.RIGHT, Mod.NONE, Col.INNERMOST, Row.HOME): char15, + Pos(Side.RIGHT, Mod.NONE, Col.INDEX, Row.HOME): char16, + Pos(Side.RIGHT, Mod.NONE, Col.MIDDLE, Row.HOME): char17, + Pos(Side.RIGHT, Mod.NONE, Col.RING, Row.HOME): char18, + Pos(Side.RIGHT, Mod.NONE, Col.PINKY, Row.HOME): char19, + Pos(Side.LEFT, Mod.NAV, Col.PINKY, Row.HOME): char120, + Pos(Side.LEFT, Mod.NAV, Col.RING, Row.HOME): char121, + Pos(Side.LEFT, Mod.NAV, Col.MIDDLE, Row.HOME): char122, + Pos(Side.LEFT, Mod.NAV, Col.INDEX, Row.HOME): char123, + Pos(Side.LEFT, Mod.NAV, Col.INNERMOST, Row.HOME): char124, + Pos(Side.RIGHT, Mod.NAV, Col.INNERMOST, Row.HOME): char125, + Pos(Side.RIGHT, Mod.NAV, Col.INDEX, Row.HOME): char126, + Pos(Side.RIGHT, Mod.NAV, Col.MIDDLE, Row.HOME): char127, + Pos(Side.RIGHT, Mod.NAV, Col.RING, Row.HOME): char128, + Pos(Side.RIGHT, Mod.NAV, Col.PINKY, Row.HOME): char129, + Pos(Side.LEFT, Mod.NAV, Col.PINKY, Row.UPPER): char11_1, + Pos(Side.LEFT, Mod.NAV, Col.RING, Row.UPPER): char11_2, + Pos(Side.LEFT, Mod.NAV, Col.MIDDLE, Row.UPPER): char11_3, + Pos(Side.LEFT, Mod.NAV, Col.INDEX, Row.UPPER): char11_4, + Pos(Side.LEFT, Mod.NAV, Col.INNERMOST, Row.UPPER): char11_5, + Pos(Side.RIGHT, Mod.NAV, Col.INNERMOST, Row.UPPER): char11_6, + Pos(Side.RIGHT, Mod.NAV, Col.INDEX, Row.UPPER): char11_7, + Pos(Side.RIGHT, Mod.NAV, Col.MIDDLE, Row.UPPER): char11_8, + Pos(Side.RIGHT, Mod.NAV, Col.RING, Row.UPPER): char11_9, + Pos(Side.RIGHT, Mod.NAV, Col.PINKY, Row.UPPER): char11_0, + Pos(Side.RIGHT, Mod.NONE, Col.OUTERMOST, Row.HOME): char110, + Pos(Side.LEFT, Mod.NONE, Col.PINKY, Row.LOWER): char20, + Pos(Side.LEFT, Mod.NONE, Col.RING, Row.LOWER): char21, + Pos(Side.LEFT, Mod.NONE, Col.MIDDLE, Row.LOWER): char22, + Pos(Side.LEFT, Mod.NONE, Col.INDEX, Row.LOWER): char23, + Pos(Side.LEFT, Mod.NONE, Col.INNERMOST, Row.LOWER): char24, + Pos(Side.RIGHT, Mod.NONE, Col.INNERMOST, Row.LOWER): char25, + Pos(Side.RIGHT, Mod.NONE, Col.INDEX, Row.LOWER): char26, + Pos(Side.RIGHT, Mod.NONE, Col.MIDDLE, Row.LOWER): char27, + Pos(Side.RIGHT, Mod.NONE, Col.RING, Row.LOWER): char28, + Pos(Side.RIGHT, Mod.NONE, Col.PINKY, Row.LOWER): char29, + Pos(Side.LEFT, Mod.UPPER, Col.PINKY, Row.LOWER): char100, + Pos(Side.LEFT, Mod.UPPER, Col.RING, Row.LOWER): char101, + Pos(Side.LEFT, Mod.UPPER, Col.MIDDLE, Row.LOWER): char102, + Pos(Side.LEFT, Mod.UPPER, Col.INDEX, Row.LOWER): char103, + Pos(Side.LEFT, Mod.UPPER, Col.INNERMOST, Row.LOWER): char104, + Pos(Side.RIGHT, Mod.UPPER, Col.INNERMOST, Row.LOWER): char105, + Pos(Side.RIGHT, Mod.UPPER, Col.INDEX, Row.LOWER): char106, + Pos(Side.RIGHT, Mod.UPPER, Col.MIDDLE, Row.LOWER): char107, + Pos(Side.RIGHT, Mod.UPPER, Col.RING, Row.LOWER): char108, + Pos(Side.RIGHT, Mod.UPPER, Col.PINKY, Row.LOWER): char109, + Pos(Side.LEFT, Mod.UPPER, Col.PINKY, Row.HOME): char90, + Pos(Side.LEFT, Mod.UPPER, Col.RING, Row.HOME): char91, + Pos(Side.LEFT, Mod.UPPER, Col.MIDDLE, Row.HOME): char92, + Pos(Side.LEFT, Mod.UPPER, Col.INDEX, Row.HOME): char93, + Pos(Side.LEFT, Mod.UPPER, Col.INNERMOST, Row.HOME): char94, + Pos(Side.RIGHT, Mod.UPPER, Col.INNERMOST, Row.HOME): char95, + Pos(Side.RIGHT, Mod.UPPER, Col.INDEX, Row.HOME): char96, + Pos(Side.RIGHT, Mod.UPPER, Col.MIDDLE, Row.HOME): char97, + Pos(Side.RIGHT, Mod.UPPER, Col.RING, Row.HOME): char98, + Pos(Side.RIGHT, Mod.UPPER, Col.PINKY, Row.HOME): char99, + Pos(Side.LEFT, Mod.UPPER, Col.PINKY, Row.UPPER): char8_1, + Pos(Side.LEFT, Mod.UPPER, Col.RING, Row.UPPER): char8_2, + Pos(Side.LEFT, Mod.UPPER, Col.MIDDLE, Row.UPPER): char8_3, + Pos(Side.LEFT, Mod.UPPER, Col.INDEX, Row.UPPER): char8_4, + Pos(Side.LEFT, Mod.UPPER, Col.INNERMOST, Row.UPPER): char8_5, + Pos(Side.RIGHT, Mod.UPPER, Col.INNERMOST, Row.UPPER): char8_6, + Pos(Side.RIGHT, Mod.UPPER, Col.INDEX, Row.UPPER): char8_7, + Pos(Side.RIGHT, Mod.UPPER, Col.MIDDLE, Row.UPPER): char8_8, + Pos(Side.RIGHT, Mod.UPPER, Col.RING, Row.UPPER): char8_9, + Pos(Side.RIGHT, Mod.UPPER, Col.PINKY, Row.UPPER): char8_0, + Pos(Side.LEFT, Mod.LOWER, Col.PINKY, Row.LOWER): char70, + Pos(Side.LEFT, Mod.LOWER, Col.RING, Row.LOWER): char71, + Pos(Side.LEFT, Mod.LOWER, Col.MIDDLE, Row.LOWER): char72, + Pos(Side.LEFT, Mod.LOWER, Col.INDEX, Row.LOWER): char73, + Pos(Side.LEFT, Mod.LOWER, Col.INNERMOST, Row.LOWER): char74, + Pos(Side.RIGHT, Mod.LOWER, Col.INNERMOST, Row.LOWER): char75, + Pos(Side.RIGHT, Mod.LOWER, Col.INDEX, Row.LOWER): char76, + Pos(Side.RIGHT, Mod.LOWER, Col.MIDDLE, Row.LOWER): char77, + Pos(Side.RIGHT, Mod.LOWER, Col.RING, Row.LOWER): char78, + Pos(Side.RIGHT, Mod.LOWER, Col.PINKY, Row.LOWER): char79, + Pos(Side.LEFT, Mod.SHIFT, Col.PINKY, Row.UPPER): char_31, + Pos(Side.LEFT, Mod.SHIFT, Col.RING, Row.UPPER): char_32, + Pos(Side.LEFT, Mod.SHIFT, Col.MIDDLE, Row.UPPER): char_33, + Pos(Side.LEFT, Mod.SHIFT, Col.INDEX, Row.UPPER): char_34, + Pos(Side.LEFT, Mod.SHIFT, Col.INNERMOST, Row.UPPER): char_35, + Pos(Side.RIGHT, Mod.SHIFT, Col.INNERMOST, Row.UPPER): char_36, + Pos(Side.RIGHT, Mod.SHIFT, Col.INDEX, Row.UPPER): char_37, + Pos(Side.RIGHT, Mod.SHIFT, Col.MIDDLE, Row.UPPER): char_38, + Pos(Side.RIGHT, Mod.SHIFT, Col.RING, Row.UPPER): char_39, + Pos(Side.RIGHT, Mod.SHIFT, Col.PINKY, Row.UPPER): char_30, + Pos(Side.LEFT, Mod.SHIFT, Col.PINKY, Row.HOME): char40, + Pos(Side.LEFT, Mod.SHIFT, Col.RING, Row.HOME): char41, + Pos(Side.LEFT, Mod.SHIFT, Col.MIDDLE, Row.HOME): char42, + Pos(Side.LEFT, Mod.SHIFT, Col.INDEX, Row.HOME): char43, + Pos(Side.LEFT, Mod.SHIFT, Col.INNERMOST, Row.HOME): char44, + Pos(Side.RIGHT, Mod.SHIFT, Col.INNERMOST, Row.HOME): char45, + Pos(Side.RIGHT, Mod.SHIFT, Col.INDEX, Row.HOME): char46, + Pos(Side.RIGHT, Mod.SHIFT, Col.MIDDLE, Row.HOME): char47, + Pos(Side.RIGHT, Mod.SHIFT, Col.RING, Row.HOME): char48, + Pos(Side.RIGHT, Mod.SHIFT, Col.PINKY, Row.HOME): char49, + Pos(Side.RIGHT, Mod.SHIFT, Col.OUTERMOST, Row.HOME): char410, + Pos(Side.LEFT, Mod.SHIFT, Col.PINKY, Row.LOWER): char50, + Pos(Side.LEFT, Mod.SHIFT, Col.RING, Row.LOWER): char51, + Pos(Side.LEFT, Mod.SHIFT, Col.MIDDLE, Row.LOWER): char52, + Pos(Side.LEFT, Mod.SHIFT, Col.INDEX, Row.LOWER): char53, + Pos(Side.LEFT, Mod.SHIFT, Col.INNERMOST, Row.LOWER): char54, + Pos(Side.RIGHT, Mod.SHIFT, Col.INNERMOST, Row.LOWER): char55, + Pos(Side.RIGHT, Mod.SHIFT, Col.INDEX, Row.LOWER): char56, + Pos(Side.RIGHT, Mod.SHIFT, Col.MIDDLE, Row.LOWER): char57, + Pos(Side.RIGHT, Mod.SHIFT, Col.RING, Row.LOWER): char58, + Pos(Side.RIGHT, Mod.SHIFT, Col.PINKY, Row.LOWER): char59, + }, + ) + assert ( + "UNMODIFIED:\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇥ | {char0} | {char1} | {char2} | {char3} | {char4} " + f"| | {char5} | {char6} | {char7} | {char8} | {char9} " + f"| ↠|\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⎈ | {char10} | {char11} | {char12} | {char13} | {char14} " + f"| | {char15} | {char16} | {char17} | {char18} | {char19} " + f"| {char110} |\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇧ | {char20} | {char21} | {char22} | {char23} | {char24} " + f"| | {char25} | {char26} | {char27} | {char28} | {char29} " + "| ⇧ |\n " + f"------------------------------------- " + f"-------------------------------------\n \n " + "SHIFT:\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇥ | {char_31} | {char_32} | {char_33} | {char_34} | {char_35} " + f"| | {char_36} | {char_37} | {char_38} | {char_39} | {char_30} " + f"| ↠|\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⎈ | {char40} | {char41} | {char42} | {char43} | {char44} " + f"| | {char45} | {char46} | {char47} | {char48} | {char49} " + f"| {char410} |\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇧ | {char50} | {char51} | {char52} | {char53} | {char54} " + f"| | {char55} | {char56} | {char57} | {char58} | {char59} " + "| ⇧ |\n " + f"------------------------------------- " + f"-------------------------------------\n \n " + "LOWER:\n " + f"------------------------------------- " + f"-------------------------------------\n " + "| F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F10 | F11 " + "| F12 |\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇕ | {char60} | {char61} | {char62} | {char63} | {char64} " + f"| | {char65} | {char66} | {char67} | {char68} | {char69} " + f"| {char610} |\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⎇ | {char70} | {char71} | {char72} | {char73} | {char74} " + f"| | {char75} | {char76} | {char77} | {char78} | {char79} " + "|AltGr|\n " + f"------------------------------------- " + f"-------------------------------------\n \n " + "UPPER:\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇥ | {char8_1} | {char8_2} | {char8_3} | {char8_4} | {char8_5} " + f"| | {char8_6} | {char8_7} | {char8_8} | {char8_9} | {char8_0} " + f"| ⌦ |\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⎈ | {char90} | {char91} | {char92} | {char93} | {char94} " + f"| | {char95} | {char96} | {char97} | {char98} | {char99} " + f"| ⇕ |\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇧ | {char100} | {char101} | {char102} | {char103} | {char104} " + f"| | {char105} | {char106} | {char107} | {char108} | {char109} " + "|AltGr|\n " + f"------------------------------------- " + f"-------------------------------------\n \n " + "NAV:\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇥ | {char11_1} | {char11_2} | {char11_3} | {char11_4} " + f"| {char11_5} | | {char11_6} | {char11_7} | {char11_8} " + f"| {char11_9} | {char11_0} | ↠|\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| | {char120} | {char121} | {char122} | {char123} | {char124} " + f"| | {char125} | {char126} | {char127} | {char128} | {char129} " + f"| |\n " + f"------------------------------------- " + f"-------------------------------------\n " + f"| ⇧ | {char130} | {char131} | {char132} | {char133} | {char134} " + f"| | {char135} | {char136} | {char137} | {char138} | {char139} " + "| ⇧ |\n " + f"------------------------------------- " + f"-------------------------------------" in layout + ) -- GitLab From f6f7ed783999d56696b8c118fa7936cb9763b0b1 Mon Sep 17 00:00:00 2001 From: Bjoern Ludwig <bjoern.ludwig@ptb.de> Date: Mon, 14 Feb 2022 18:52:06 +0100 Subject: [PATCH 07/10] fix(type_aliases): fix numbering for Mod class --- src/ilp_keyboard_layout_optimization/type_aliases.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ilp_keyboard_layout_optimization/type_aliases.py b/src/ilp_keyboard_layout_optimization/type_aliases.py index 68b854a..4634a16 100644 --- a/src/ilp_keyboard_layout_optimization/type_aliases.py +++ b/src/ilp_keyboard_layout_optimization/type_aliases.py @@ -39,9 +39,9 @@ class Mod(Enum): """Modifier keys needed to reach a position""" NONE = 0 - SHIFT = auto() - UPPER = auto() - LOWER = auto() + SHIFT = 1 + UPPER = 3 + LOWER = 4 NAV = 2 -- GitLab From 3e3b01d4b57fd1bac985e0123cac8d25490dedd5 Mon Sep 17 00:00:00 2001 From: Bjoern Ludwig <bjoern.ludwig@ptb.de> Date: Mon, 14 Feb 2022 18:53:00 +0100 Subject: [PATCH 08/10] fix(test_visualize): fix comparison string for overall visualization --- test/test_visualize.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test_visualize.py b/test/test_visualize.py index 800662a..84d1965 100644 --- a/test/test_visualize.py +++ b/test/test_visualize.py @@ -850,6 +850,7 @@ def test_make_layer_strs_with_all_positions_set_manually_randomly( }, ) assert ( + "\n " "UNMODIFIED:\n " f"------------------------------------- " f"-------------------------------------\n " @@ -938,5 +939,6 @@ def test_make_layer_strs_with_all_positions_set_manually_randomly( f"| | {char135} | {char136} | {char137} | {char138} | {char139} " "| ⇧ |\n " f"------------------------------------- " - f"-------------------------------------" in layout + f"-------------------------------------\n " + in layout ) -- GitLab From 016a8e143d9b80246c0c5f5ffb35bebc8441b870 Mon Sep 17 00:00:00 2001 From: Bjoern Ludwig <bjoern.ludwig@ptb.de> Date: Mon, 14 Feb 2022 18:53:40 +0100 Subject: [PATCH 09/10] build(setup): increment version number to 0.0.3 --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 34bc04a..111254a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = ilp_keyboard_layout_optimization -version = 0.0.2a9 +version = 0.0.3 description = The QAP variant of keyboard layout optimization, i.e. character to key assignments long_description = file: README.md -- GitLab From 830b93ad07abbca10df4b0efb5fb80a243bab662 Mon Sep 17 00:00:00 2001 From: Bjoern Ludwig <bjoern.ludwig@ptb.de> Date: Mon, 14 Feb 2022 18:56:36 +0100 Subject: [PATCH 10/10] refactor(test_probabilities): reduce runtime of test suite by not executing default bigram extraction twice --- test/test_probabilities.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_probabilities.py b/test/test_probabilities.py index 314cf22..d4886db 100644 --- a/test/test_probabilities.py +++ b/test/test_probabilities.py @@ -285,8 +285,8 @@ def test_init_extract_monogram_data(chars_probs): assert chars_probs._extract_monogram_data() -def test_init_extract_bigram_data(chars_probs): - assert chars_probs._extract_bigram_data() +def test_init_extract_bigram_data(custom_chars_probs): + assert custom_chars_probs._extract_bigram_data() def test_init_custom_bigram_data(custom_chars_probs): -- GitLab