X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=find_best_caesar_break_parameters.py;h=7a8ddc9dc0a4dd3340a84c3fb021d44131d1ab87;hb=f420062910c850658815504763c8ca77067bac82;hp=a07f30f096684ac3f282be95fb3ecfe1f7eba45a;hpb=1c65dba2a525fd559fc326cbd9fc2cde4441c9d5;p=cipher-tools.git diff --git a/find_best_caesar_break_parameters.py b/find_best_caesar_break_parameters.py index a07f30f..7a8ddc9 100644 --- a/find_best_caesar_break_parameters.py +++ b/find_best_caesar_break_parameters.py @@ -2,6 +2,8 @@ import random import collections from cipher import * from cipherbreak import * +import itertools +import csv corpus = sanitise(''.join([open('shakespeare.txt', 'r').read(), open('sherlock-holmes.txt', 'r').read(), @@ -10,47 +12,69 @@ corpus_length = len(corpus) euclidean_scaled_english_counts = norms.euclidean_scale(english_counts) -metrics = [{'func': norms.l1, 'name': 'l1'}, - {'func': norms.l2, 'name': 'l2'}, - {'func': norms.l3, 'name': 'l2'}, - {'func': norms.cosine_distance, 'name': 'cosine_distance'}, - {'func': norms.harmonic_mean, 'name': 'harmonic_mean'}, - {'func': norms.geometric_mean, 'name': 'geometric_mean'}, - {'func': norms.inverse_log_pl, 'name': 'inverse_log_pl'}] +metrics = [{'func': norms.l1, 'invert': True, 'name': 'l1'}, + {'func': norms.l2, 'invert': True, 'name': 'l2'}, + {'func': norms.l3, 'invert': True, 'name': 'l3'}, + {'func': norms.cosine_similarity, 'invert': False, 'name': 'cosine_similarity'}] + # {'func': norms.harmonic_mean, 'invert': True, 'name': 'harmonic_mean'}, + # {'func': norms.geometric_mean, 'invert': True, 'name': 'geometric_mean'}] scalings = [{'corpus_frequency': normalised_english_counts, 'scaling': norms.normalise, 'name': 'normalised'}, {'corpus_frequency': euclidean_scaled_english_counts, 'scaling': norms.euclidean_scale, - 'name': 'euclidean_scaled'}, - {'corpus_frequency': normalised_english_counts, - 'scaling': norms.identity_scale, - 'name': 'normalised_with_identity'}] -message_lengths = [300, 100, 50, 30, 20, 10, 5] + 'name': 'euclidean_scaled'}] +message_lengths = [100, 50, 30, 20, 10, 5] trials = 5000 -scores = collections.defaultdict(int) - -with open('caesar_break_parameter_trials.csv', 'w') as f: - print('metric,scaling,message_length,score', file = f) - for metric in metrics: - for scaling in scalings: - for message_length in message_lengths: - for i in range(trials): - sample_start = random.randint(0, corpus_length - message_length) - sample = corpus[sample_start:(sample_start + message_length)] - key = random.randint(1, 25) - sample_ciphertext = caesar_encipher(sample, key) - (found_key, score) = caesar_break(sample_ciphertext, - metric=metric['func'], - target_counts=scaling['corpus_frequency'], - message_frequency_scaling=scaling['scaling']) - if found_key == key: - scores[(metric['name'], scaling['name'], message_length)] += 1 - print(', '.join([metric['name'], - scaling['name'], - str(message_length), - str(scores[(metric['name'], scaling['name'], message_length)] / trials) ]), - file = f) -print() +scores = {} + + +def make_frequency_compare_function(target_frequency, frequency_scaling, metric, invert): + def frequency_compare(text): + counts = frequency_scaling(frequencies(text)) + if invert: + score = -1 * metric(target_frequency, counts) + else: + score = metric(target_frequency, counts) + return score + return frequency_compare + +def scoring_functions(): + return [{'func': make_frequency_compare_function(s['corpus_frequency'], + s['scaling'], m['func'], m['invert']), + 'name': '{} + {}'.format(m['name'], s['name'])} + for m in metrics + for s in scalings] + [{'func': Pletters, 'name': 'Pletters'}] + +def eval_scores(): + [eval_one_score(f, l) + for f in scoring_functions() + for l in message_lengths] + +def eval_one_score(scoring_function, message_length): + print(scoring_function['name'], message_length) + if scoring_function['name'] not in scores: + scores[scoring_function['name']] = collections.defaultdict(int) + for _ in range(trials): + sample_start = random.randint(0, corpus_length - message_length) + sample = corpus[sample_start:(sample_start + message_length)] + key = random.randint(1, 25) + ciphertext = caesar_encipher(sample, key) + found_key, _ = caesar_break(ciphertext, scoring_function['func']) + if found_key == key: + scores[scoring_function['name']][message_length] += 1 + return scores[scoring_function['name']][message_length] + +def show_results(): + with open('caesar_break_parameter_trials.csv', 'w') as f: + writer = csv.DictWriter(f, ['name'] + message_lengths, + quoting=csv.QUOTE_NONNUMERIC) + writer.writeheader() + for scoring in sorted(scores): + scores[scoring]['name'] = scoring + writer.writerow(scores[scoring]) + +eval_scores() +show_results()