new struct `finger_cost`
[evolve-layout.git] / evolution.py
blobf0194a7bce7931857374876042b2fbd864846563
1 #!/usr/bin/env python3
2 # encoding: utf-8
4 """Run a full evolution of keyboard layouts."""
6 from optparse import OptionParser
8 ### config
10 #: The number of new layouts to create. Can be overwritten with the -n parameter.
11 num_layouts = 50
13 #: The output filename. Can be overwritten with the -o parameter.
14 filename = "output.txt" # None for shell output
16 #: The number of random evolution steps to take.
17 steps = 4000
19 #: The number of random mutations to do before the evolution to get a random layout
20 prerandomize = 3000
22 #: Should we always do the locally best step (very slow and *not* optimal)
23 controlled = False
25 #: Should we spout out information on the shell? (Windows users disable this. Your shell can’t take Unicode)
26 quiet = True
28 #: Should we give additional statistics for the final layout?
29 verbose = True
31 #: Should we finalize the layout with as many controlled steps as needed, so a single keyswitch can’t improve it further?
32 controlled_tail = True
34 #: Should we use annealing? How many steps? Per step it adds one switch, so anneal 5 starts with 6 switches aka changing half the layout (12 keys).
35 anneal = 5
36 #: The number of iterations to spend in one anneal level. The first anneal * anneal_step iterations are spent in simulated annealing.
37 anneal_step = 100
39 #: The layout to use as base for mutations. If you want a given starting layout, also set prerandomize = 0.
40 STARTING_LAYOUT = """xvlcw khgfqß´
41 uiaeo snrtdy
42 üöäpz bm,.j"""
45 ### Parse console arguments
47 parser = OptionParser(usage = "evolutionary running script", version = "0.1")
48 parser.add_option("-o", "--output", type="string", dest="filename", default=filename, help="set outputfile")
49 parser.add_option("-n", "--number", type="int", dest="evolution_steps", default=num_layouts, help="number of steps")
50 parser.add_option("-f", "--file", type="string", dest="data",
51 default=None, help="use the given textfile as korpus instead of the ngram files.", metavar="filepath")
53 (options, args) = parser.parse_args()
55 if options.data:
56 with open(options.data) as f:
57 options.data = f.read()
59 ### run
61 # Hack to make the script output to a file instead of the shell (necessary for windows users).
62 # MUST come before the imports from check_neo.
63 if filename is not None:
64 import sys
65 sys.argv.append("-o")
66 sys.argv.append(options.filename)
68 from check_neo import evolve_a_layout, string_to_layout
69 from time import time
70 from datetime import timedelta
71 STARTING_LAYOUT = string_to_layout(STARTING_LAYOUT)
73 print("# Starting the evolution.")
75 t = time()
76 for step in range(options.evolution_steps):
77 evolve_a_layout(steps,
78 prerandomize,
79 controlled,
80 quiet,
81 verbose,
82 controlled_tail,
83 starting_layout=STARTING_LAYOUT,
84 data=options.data,
85 anneal=anneal,
86 anneal_step = anneal_step)
87 print(step+1, "/", options.evolution_steps,
88 timedelta(seconds=time()-t))
89 t = time()