Various changes
[cipher-tools.git] / find_best_caesar_break_parameters.py
1 import random
2 import collections
3 from cipher import *
4 from cipherbreak import *
5 import itertools
6
7 corpus = sanitise(''.join([open('shakespeare.txt', 'r').read(),
8 open('sherlock-holmes.txt', 'r').read(),
9 open('war-and-peace.txt', 'r').read()]))
10 corpus_length = len(corpus)
11
12 euclidean_scaled_english_counts = norms.euclidean_scale(english_counts)
13
14 metrics = [{'func': norms.l1, 'name': 'l1'},
15 {'func': norms.l2, 'name': 'l2'},
16 {'func': norms.l3, 'name': 'l3'},
17 {'func': norms.cosine_distance, 'name': 'cosine_distance'},
18 {'func': norms.harmonic_mean, 'name': 'harmonic_mean'},
19 {'func': norms.geometric_mean, 'name': 'geometric_mean'},
20 {'func': norms.inverse_log_pl, 'name': 'inverse_log_pl'}]
21 scalings = [{'corpus_frequency': normalised_english_counts,
22 'scaling': norms.normalise,
23 'name': 'normalised'},
24 {'corpus_frequency': euclidean_scaled_english_counts,
25 'scaling': norms.euclidean_scale,
26 'name': 'euclidean_scaled'},
27 {'corpus_frequency': normalised_english_counts,
28 'scaling': norms.identity_scale,
29 'name': 'normalised_with_identity'}]
30 message_lengths = [300, 100, 50, 30, 20, 10, 5]
31
32 trials = 5000
33
34 scores = collections.defaultdict(int)
35
36 def eval_all():
37 list(itertools.starmap(eval_one_parameter_set,
38 itertools.product(metrics, scalings, message_lengths)))
39
40 def eval_one_parameter_set(metric, scaling, message_length):
41 for _ in range(trials):
42 sample_start = random.randint(0, corpus_length - message_length)
43 sample = corpus[sample_start:(sample_start + message_length)]
44 key = random.randint(1, 25)
45 sample_ciphertext = caesar_encipher(sample, key)
46 found_key, _ = caesar_break(sample_ciphertext,
47 metric=metric['func'],
48 target_counts=scaling['corpus_frequency'],
49 message_frequency_scaling=scaling['scaling'])
50 if found_key == key:
51 scores[(metric['name'], scaling['name'], message_length)] += 1
52 return scores[(metric['name'], scaling['name'], message_length)]
53
54 def show_results():
55 with open('caesar_break_parameter_trials.csv', 'w') as f:
56 print(',message_length', file = f)
57 print('metric+scaling,', ','.join([str(l) for l in message_lengths]), file = f)
58 for (metric, scaling) in itertools.product(metrics, scalings):
59 print('{}:{}'.format(metric['name'], scaling['name']), end='', file=f)
60 for l in message_lengths:
61 print(',', scores[(metric['name'], scaling['name'], l)] / trials, end='', file=f)
62 print('', file = f)
63
64 eval_all()
65 show_results()