novy slovnik substantiv
[krypto.git] / jakobsen.py
1 """Modul pro praci s Jakobsenovym algoritmem."""
2
3 from itertools import combinations
4 import pickle
5 from ocesavac import ocesat
6 from spolecne import MABECEDA
7
8 def nova_tabulka(zprava, abc=MABECEDA):
9     """Vraci tabulku cetnosti bigramu ve zprave nad danou abecedou."""
10     tabulka = dict()
11     for i in abc:
12         tabulka[i] = dict()
13         for j in abc:
14             tabulka[i][j] = 0
15     for i in range(len(zprava) - 1):
16         tabulka[zprava[i]][zprava[i+1]] += 1
17     celkem = sum(sum(tab2.values()) for tab2 in tabulka.values())
18     for i in abc:
19         for j in abc:
20             tabulka[i][j] /= float(celkem)
21     return tabulka
22
23 def vzdalenost(tab1, tab2, abc=MABECEDA):
24     """Vraci soucet strednich kvadratickych odchylek pro dve tabulky cetnosti
25     bigramu nad danou abecedou."""
26     rozdil = 0
27     for i in abc:
28         for j in abc:
29             rozdil += abs(tab1[i][j] - tab2[i][j])
30     return rozdil
31
32 def substituce(zprava, slovnik):
33     """Vrati zpravu, ve ktere jsou znaky dane abecedy nahrazenypodle daneho
34     slovniku."""
35     pole = []
36     for char in zprava:
37         if char in slovnik:
38             pole.append(slovnik[char])
39         else:
40             pole.append(char)
41     return pole
42
43 def poradi_dle_frekvence(zprava, abc=MABECEDA):
44     """Vrati znaky dane abecedy v poradi podle frekvence v dane zprave."""
45     freq = dict()
46     for char in abc:
47         freq[char] = 0
48     for char in zprava:
49         if char in abc:
50             freq[char] += 1
51     return sorted(freq.keys(), key=freq.get, reverse=True)
52
53 class reference:
54     pass
55
56 def kombinace(abeceda):
57     a = 0
58     b = 1
59     while b < len(abeceda):
60         yield (abeceda[a], abeceda[a + b])
61         a += 1
62         if a + b == len(abeceda):
63             a = 0
64             b += 1
65
66 def jakobsen(zprava, ref):
67     """Pro danou sifrovanou zpravu vrati substitucni slovnik odvozeny s pomoci
68     Jakobsenova algoritmu s danou referencni tabulkou."""
69     slovnik = dict(zip(poradi_dle_frekvence(zprava, ref.abeceda), ref.poradi))
70     tabulka = nova_tabulka(
71                   substituce(zprava, slovnik),
72                   ref.abeceda
73                   )
74     vzdal = vzdalenost(tabulka, ref.tabulka, ref.abeceda)
75
76     vzdal_old = vzdal + 1
77     while vzdal_old > vzdal:
78         vzdal_old = vzdal
79         for (x, y) in kombinace(ref.poradi):
80             slovnik[x], slovnik[y] = slovnik[y], slovnik[x]
81             nova_vzdalenost = vzdalenost(
82                      nova_tabulka(
83                          substituce(zprava, slovnik),
84                          ref.abeceda),
85                      ref.tabulka,
86                      ref.abeceda)
87             if  nova_vzdalenost < vzdal:
88                 vzdal = nova_vzdalenost
89                 break
90             else:
91                 slovnik[x], slovnik[y] = slovnik[y], slovnik[x]
92     return slovnik, vzdal
93     
94
95 def desifruj(zprava, mezery=True):
96     """Vrati vysledek pokusu dekodovat zpravu Jakobsenovym algoritmem."""
97     if mezery:
98         soubor = open('ref')
99     else:
100         soubor = open('bref')
101     ref = pickle.load(soubor)
102     soubor.close()
103     slovnik, _ = jakobsen(ocesat(zprava, mezery), ref)
104     return '\n'.join([''.join(substituce(zprava, slovnik)),
105                       ' '.join(ref.abeceda),
106                       ' '.join([slovnik[c] for c in ref.abeceda])])