initial commit

This commit is contained in:
2022-09-22 13:13:15 +02:00
commit ea1fbe4e94
93 changed files with 9161 additions and 0 deletions

View File

@ -0,0 +1,95 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generates latex table for alignment pattern locations
(C) 2022 Louis Heredero louis.heredero@edu.vs.ch
"""
LOCATIONS = [
[],
[6, 18],
[6, 22],
[6, 26],
[6, 30],
[6, 34],
[6, 22, 38],
[6, 24, 42],
[6, 26, 46],
[6, 28, 50],
[6, 30, 54],
[6, 32, 58],
[6, 34, 62],
[6, 26, 46, 66],
[6, 26, 48, 70],
[6, 26, 50, 74],
[6, 30, 54, 78],
[6, 30, 56, 82],
[6, 30, 58, 86],
[6, 34, 62, 90],
[6, 28, 50, 72, 94],
[6, 26, 50, 74, 98],
[6, 30, 54, 78, 102],
[6, 28, 54, 80, 106],
[6, 32, 58, 84, 110],
[6, 30, 58, 86, 114],
[6, 34, 62, 90, 118],
[6, 26, 50, 74, 98, 122],
[6, 30, 54, 78, 102, 126],
[6, 26, 52, 78, 104, 130],
[6, 30, 56, 82, 108, 134],
[6, 34, 60, 86, 112, 138],
[6, 30, 58, 86, 114, 142],
[6, 34, 62, 90, 118, 146],
[6, 30, 54, 78, 102, 126, 150],
[6, 24, 50, 76, 102, 128, 154],
[6, 28, 54, 80, 106, 132, 158],
[6, 32, 58, 84, 110, 136, 162],
[6, 26, 54, 82, 110, 138, 166],
[6, 30, 58, 86, 114, 142, 170]
]
start = r"""\def\arraystretch{1.2}
\begin{center}
\begin{longtabu}{|[2pt]c|c|c|c|c|c|c|c|[2pt]}
\caption{Alignment pattern locations}
\label{tab:qr_alignment}\\
\tabucline[2pt]{-}
Version & \multicolumn{7}{c|[2pt]}{Central x and y coordinates} \\
\tabucline[2pt]{-}
\endfirsthead
\multicolumn{8}{r}{\emph{Continued from last page}}\\
\hline
Version & \multicolumn{7}{c|[2pt]}{Central x and y coordinates} \\
\endhead
Version & \multicolumn{7}{c|[2pt]}{Central x and y coordinates} \\
\hline
\multicolumn{8}{r}{\emph{Continued on next page}}\\
\endfoot
\tabucline[2pt]{-}
\endlastfoot
"""
end = r""" \hline
\end{longtabu}
\end{center}
\def\arraystretch{1}
"""
if __name__ == "__main__":
with open("alignment.tex", "w") as f_tex:
f_tex.write(start)
for i, row in enumerate(LOCATIONS):
if i > 0:
f_tex.write(" \\hline\n")
f_tex.write(f" {i+1:2}")
for j in range(7):
val = row[j] if j < len(row) else ""
f_tex.write(f" & {val:3}")
f_tex.write(" \\\\\n")
f_tex.write(end)

View File

@ -0,0 +1,104 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generates latex table for error correction information
(C) 2022 Louis Heredero louis.heredero@edu.vs.ch
"""
levels = "LMQH"
start = r"""\def\arraystretch{1.5}
\begin{table}[H]
\centering
\begin{longtabu}{|[2pt]c|c|c|c|c|c|c|c|[2pt]}
\tabucline[2pt]{-}
Version & Correction level & Data codewords & Error correction codewords per block & Blocks in group 1 & Data codewords per group 1 blocks & Blocks in group 2 & Data codewords per group 2 blocks \\
\tabucline[2pt]{-}
"""
end = r""" \tabucline[2pt]{-}
\end{longtabu}
\caption{Error correction characteristics}
\label{tab:qr_error_correction}
\end{table}
\def\arraystretch{1}
"""
start = r"""\def\arraystretch{1.2}
\begin{center}
\begin{longtabu}{|[2pt]c|c|c|c|c|c|c|c|[2pt]}
\caption{Error correction characteristics}
\label{tab:qr_error_correction}\\
\tabucline[2pt]{-}
\rot{Version} & \rot{Correction level} & \rot{Data codewords} & \rot{\shortstack[l]{Error correction \\ codewords per block}} & \rot{Blocks in group 1} & \rot{\shortstack[l]{Data codewords per \\ group 1 blocks}} & \rot{Blocks in group 2} & \rot{\shortstack[l]{Data codewords per \\ group 2 blocks}} \\
\tabucline[2pt]{-}
\endfirsthead
\multicolumn{8}{r}{\emph{Continued from last page}}\\
\hline
Ver & Level & Data CW & EC CW /B & Blocks G1 & CW G1 & Blocks G2 & CW G2 \\
\endhead
Ver & Level & Data CW & EC CW /B & Blocks G1 & CW G1 & Blocks G2 & CW G2 \\
\hline
\multicolumn{8}{r}{\emph{Continued on next page}}\\
\endfoot
\tabucline[2pt]{-}
\endlastfoot
"""
end = r""" \hline
\end{longtabu}
\end{center}
\def\arraystretch{1}
"""
if __name__ == "__main__":
with open("error_correction.txt", "r") as f_txt, open("error_correction.tex", "w") as f_tex:
ecs = f_txt.read().split("\n\n")
f_tex.write(start)
"""for i, version in enumerate(versions):
lvls = version.split("\n")
if i > 0:
f_tex.write(" \\hline\n")
f_tex.write(f" \\multirow{{4}}{{*}}{{{i+1:2}}}")
# f_tex.write(f" {i+1:2}")
for j, lvl in enumerate(lvls):
values = " & ".join(
map(lambda s: f"{s:>4}", lvl.split("\t"))
)
if j > 0:
f_tex.write(" ")
# f_tex.write(" ")
f_tex.write(
f" & {levels[j]} & {values} \\\\{'*' if j < 3 else ''}\n")"""
for i, ec in enumerate(ecs):
lvls = [list(map(int, lvl.split("\t"))) for lvl in ec.split("\n")]
lvls = [lvl + [0]*(6-len(lvl)) for lvl in lvls]
if i > 0:
f_tex.write(" \\hline\n")
f_tex.write(f" \\multirow{{4}}{{*}}{{{i+1:2}}}")
for j, lvl in enumerate(lvls):
values = " & ".join(
map(lambda s: f"{s:>4}", lvl)
)
if j > 0:
f_tex.write(" ")
# f_tex.write(" ")
f_tex.write(
f" & {levels[j]} & {values} \\\\{'*' if j < 3 else ''}\n")
f_tex.write(end)

View File

@ -0,0 +1,199 @@
19 7 1 19
16 10 1 16
13 13 1 13
9 17 1 9
34 10 1 34
28 16 1 28
22 22 1 22
16 28 1 16
55 15 1 55
44 26 1 44
34 18 2 17
26 22 2 13
80 20 1 80
64 18 2 32
48 26 2 24
36 16 4 9
108 26 1 108
86 24 2 43
62 18 2 15 2 16
46 22 2 11 2 12
136 18 2 68
108 16 4 27
76 24 4 19
60 28 4 15
156 20 2 78
124 18 4 31
88 18 2 14 4 15
66 26 4 13 1 14
194 24 2 97
154 22 2 38 2 39
110 22 4 18 2 19
86 26 4 14 2 15
232 30 2 116
182 22 3 36 2 37
132 20 4 16 4 17
100 24 4 12 4 13
274 18 2 68 2 69
216 26 4 43 1 44
154 24 6 19 2 20
122 28 6 15 2 16
324 20 4 81
254 30 1 50 4 51
180 28 4 22 4 23
140 24 3 12 8 13
370 24 2 92 2 93
290 22 6 36 2 37
206 26 4 20 6 21
158 28 7 14 4 15
428 26 4 107
334 22 8 37 1 38
244 24 8 20 4 21
180 22 12 11 4 12
461 30 3 115 1 116
365 24 4 40 5 41
261 20 11 16 5 17
197 24 11 12 5 13
523 22 5 87 1 88
415 24 5 41 5 42
295 30 5 24 7 25
223 24 11 12 7 13
589 24 5 98 1 99
453 28 7 45 3 46
325 24 15 19 2 20
253 30 3 15 13 16
647 28 1 107 5 108
507 28 10 46 1 47
367 28 1 22 15 23
283 28 2 14 17 15
721 30 5 120 1 121
563 26 9 43 4 44
397 28 17 22 1 23
313 28 2 14 19 15
795 28 3 113 4 114
627 26 3 44 11 45
445 26 17 21 4 22
341 26 9 13 16 14
861 28 3 107 5 108
669 26 3 41 13 42
485 30 15 24 5 25
385 28 15 15 10 16
932 28 4 116 4 117
714 26 17 42
512 28 17 22 6 23
406 30 19 16 6 17
1006 28 2 111 7 112
782 28 17 46
568 30 7 24 16 25
442 24 34 13
1094 30 4 121 5 122
860 28 4 47 14 48
614 30 11 24 14 25
464 30 16 15 14 16
1174 30 6 117 4 118
914 28 6 45 14 46
664 30 11 24 16 25
514 30 30 16 2 17
1276 26 8 106 4 107
1000 28 8 47 13 48
718 30 7 24 22 25
538 30 22 15 13 16
1370 28 10 114 2 115
1062 28 19 46 4 47
754 28 28 22 6 23
596 30 33 16 4 17
1468 30 8 122 4 123
1128 28 22 45 3 46
808 30 8 23 26 24
628 30 12 15 28 16
1531 30 3 117 10 118
1193 28 3 45 23 46
871 30 4 24 31 25
661 30 11 15 31 16
1631 30 7 116 7 117
1267 28 21 45 7 46
911 30 1 23 37 24
701 30 19 15 26 16
1735 30 5 115 10 116
1373 28 19 47 10 48
985 30 15 24 25 25
745 30 23 15 25 16
1843 30 13 115 3 116
1455 28 2 46 29 47
1033 30 42 24 1 25
793 30 23 15 28 16
1955 30 17 115
1541 28 10 46 23 47
1115 30 10 24 35 25
845 30 19 15 35 16
2071 30 17 115 1 116
1631 28 14 46 21 47
1171 30 29 24 19 25
901 30 11 15 46 16
2191 30 13 115 6 116
1725 28 14 46 23 47
1231 30 44 24 7 25
961 30 59 16 1 17
2306 30 12 121 7 122
1812 28 12 47 26 48
1286 30 39 24 14 25
986 30 22 15 41 16
2434 30 6 121 14 122
1914 28 6 47 34 48
1354 30 46 24 10 25
1054 30 2 15 64 16
2566 30 17 122 4 123
1992 28 29 46 14 47
1426 30 49 24 10 25
1096 30 24 15 46 16
2702 30 4 122 18 123
2102 28 13 46 32 47
1502 30 48 24 14 25
1142 30 42 15 32 16
2812 30 20 117 4 118
2216 28 40 47 7 48
1582 30 43 24 22 25
1222 30 10 15 67 16
2956 30 19 118 6 119
2334 28 18 47 31 48
1666 30 34 24 34 25
1276 30 20 15 61 16

View File

@ -0,0 +1,99 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generates latex tables for hamming codes
(C) 2022 Louis Heredero louis.heredero@edu.vs.ch
"""
start = r""" \begin{tabu}{|[2pt]c|c|c|c|c|c|c|c|[2pt]}
\tabucline[2pt]{-}
& 1 & 2 & 3 & 4 & 5 & 6 & 7 \\
\tabucline[1pt]{-}
"""
end = r""" \tabucline[2pt]{-}
\end{tabu}
"""
class HammingError(Exception):
pass
def encode(data, blocksize=7):
A = start
B = start
result = []
datasize = blocksize-blocksize.bit_length()
data = list(map(int, data))
if len(data) % datasize:
raise HammingError(f"Length of data is not a multiple of {datasize}")
nblocks = int(len(data)/datasize)
last = 0
for b in range(nblocks):
if b > 0:
A += " \\hline\n"
B += " \\hline\n"
A += f" Group {b+1}"
B += f" Group {b+1}"
count = 0
for i in range(blocksize):
A += " & "
count += data[0]
# Power of 2
if (i+1)&i == 0 or i == 0:
A += "\_"
result.append(0)
else:
A += str(data[0])
result.append(data.pop(0))
A += " \\\\\n"
for i in range(blocksize.bit_length()):
p = 1 << i
c = sum([result[b*blocksize+j] for j in range(blocksize) if (j+1)&p])
if c%2:
result[b*blocksize+p-1] = 1
for i in range(blocksize):
B += " & "
B += str(result[b*blocksize+i])
B += " \\\\\n"
if count == 0:
if last >= 2:
A = A.rsplit("\n",2)[0]
A += "\n ... & ... & ... & ... & ... & ... & ... & ... \\\\\n"
B = B.rsplit("\n",2)[0]
B += "\n ... & ... & ... & ... & ... & ... & ... & ... \\\\\n"
break
last += 1
else:
last = 0
#return "".join(list(map(str, result)))
A += end
B += end
return A, B
if __name__ == "__main__":
data = "00000000001111101011000010100110101100111"
ds = 4
total_bits = (3**2 * 24 - 6)
data_bits = total_bits * ds // 7
data += "0"*(ds-len(data)%ds)
s = ""
i = 0
left = data_bits-len(data)
while len(s) < left:
s += f"{i:0b}"
i += 1
s = s[:left]
data += s
a, b = encode(data)
print(a)
print(b)

View File

@ -0,0 +1,199 @@
41 25 17 10
34 20 14 8
27 16 11 7
17 10 7 4
77 47 32 20
63 38 26 16
48 29 20 12
34 20 14 8
127 77 53 32
101 61 42 26
77 47 32 20
58 35 24 15
187 114 78 48
149 90 62 38
111 67 46 28
82 50 34 21
255 154 106 65
202 122 84 52
144 87 60 37
106 64 44 27
322 195 134 82
255 154 106 65
178 108 74 45
139 84 58 36
370 224 154 95
293 178 122 75
207 125 86 53
154 93 64 39
461 279 192 118
365 221 152 93
259 157 108 66
202 122 84 52
552 335 230 141
432 262 180 111
312 189 130 80
235 143 98 60
652 395 271 167
513 311 213 131
364 221 151 93
288 174 119 74
772 468 321 198
604 366 251 155
427 259 177 109
331 200 137 85
883 535 367 226
691 419 287 177
489 296 203 125
374 227 155 96
1022 619 425 262
796 483 331 204
580 352 241 149
427 259 177 109
1101 667 458 282
871 528 362 223
621 376 258 159
468 283 194 120
1250 758 520 320
991 600 412 254
703 426 292 180
530 321 220 136
1408 854 586 361
1082 656 450 277
775 470 322 198
602 365 250 154
1548 938 644 397
1212 734 504 310
876 531 364 224
674 408 280 173
1725 1046 718 442
1346 816 560 345
948 574 394 243
746 452 310 191
1903 1153 792 488
1500 909 624 384
1063 644 442 272
813 493 338 208
2061 1249 858 528
1600 970 666 410
1159 702 482 297
919 557 382 235
2232 1352 929 572
1708 1035 711 438
1224 742 509 314
969 587 403 248
2409 1460 1003 618
1872 1134 779 480
1358 823 565 348
1056 640 439 270
2620 1588 1091 672
2059 1248 857 528
1468 890 611 376
1108 672 461 284
2812 1704 1171 721
2188 1326 911 561
1588 963 661 407
1228 744 511 315
3057 1853 1273 784
2395 1451 997 614
1718 1041 715 440
1286 779 535 330
3283 1990 1367 842
2544 1542 1059 652
1804 1094 751 462
1425 864 593 365
3517 2132 1465 902
2701 1637 1125 692
1933 1172 805 496
1501 910 625 385
3669 2223 1528 940
2857 1732 1190 732
2085 1263 868 534
1581 958 658 405
3909 2369 1628 1002
3035 1839 1264 778
2181 1322 908 559
1677 1016 698 430
4158 2520 1732 1066
3289 1994 1370 843
2358 1429 982 604
1782 1080 742 457
4417 2677 1840 1132
3486 2113 1452 894
2473 1499 1030 634
1897 1150 790 486
4686 2840 1952 1201
3693 2238 1538 947
2670 1618 1112 684
2022 1226 842 518
4965 3009 2068 1273
3909 2369 1628 1002
2805 1700 1168 719
2157 1307 898 553
5253 3183 2188 1347
4134 2506 1722 1060
2949 1787 1228 756
2301 1394 958 590
5529 3351 2303 1417
4343 2632 1809 1113
3081 1867 1283 790
2361 1431 983 605
5836 3537 2431 1496
4588 2780 1911 1176
3244 1966 1351 832
2524 1530 1051 647
6153 3729 2563 1577
4775 2894 1989 1224
3417 2071 1423 876
2625 1591 1093 673
6479 3927 2699 1661
5039 3054 2099 1292
3599 2181 1499 923
2735 1658 1139 701
6743 4087 2809 1729
5313 3220 2213 1362
3791 2298 1579 972
2927 1774 1219 750
7089 4296 2953 1817
5596 3391 2331 1435
3993 2420 1663 1024
3057 1852 1273 784

View File

@ -0,0 +1,282 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Prints steps of Reed-Solomon decoding
(C) 2022 Louis Heredero louis.heredero@edu.vs.ch
"""
class GF:
def __init__(self, val):
self.val = val
def copy(self):
return GF(self.val)
def __add__(self, n):
return GF(self.val ^ n.val)
def __sub__(self, n):
return GF(self.val ^ n.val)
def __mul__(self, n):
if self.val == 0 or n.val == 0:
return GF(0)
return GF.EXP[GF.LOG[self.val].val + GF.LOG[n.val].val].copy()
def __truediv__(self, n):
if n.val == 0:
raise ZeroDivisionError
if self.val == 0:
return GF(0)
return GF.EXP[(GF.LOG[self.val].val + 255 - GF.LOG[n.val].val)%255].copy()
def __pow__(self, n):
return GF.EXP[(GF.LOG[self.val].val * n.val)%255].copy()
def __repr__(self):
return self.val.__repr__()
#return f"GF({self.val})"
def log(self):
return GF.LOG[self.val]
GF.EXP = [GF(0)]*512
GF.LOG = [GF(0)]*256
value = 1
for exponent in range(255):
GF.LOG[value] = GF(exponent)
GF.EXP[exponent] = GF(value)
value = ((value << 1) ^ 285) if value > 127 else value << 1
for i in range(255, 512):
GF.EXP[i] = GF.EXP[i-255].copy()
class Poly:
def __init__(self, coefs):
self.coefs = coefs.copy()
@property
def deg(self):
return len(self.coefs)
def copy(self):
return Poly(self.coefs)
def __add__(self, p):
d1, d2 = self.deg, p.deg
deg = max(d1,d2)
result = [GF(0) for i in range(deg)]
for i in range(d1):
result[i + deg - d1] = self.coefs[i]
for i in range(d2):
result[i + deg - d2] += p.coefs[i]
return Poly(result)
def __mul__(self, p):
result = [GF(0) for i in range(self.deg+p.deg-1)]
for i in range(p.deg):
for j in range(self.deg):
result[i+j] += self.coefs[j] * p.coefs[i]
return Poly(result)
def __truediv__(self, p):
dividend = self.coefs.copy()
dividend += [GF(0) for i in range(p.deg-1)]
quotient = []
for i in range(self.deg):
coef = dividend[i] / p.coefs[0]
quotient.append(coef)
print("sub:", p*Poly([coef]))
for j in range(p.deg):
dividend[i+j] -= p.coefs[j] * coef
print("rem:", dividend)
print()
while dividend[0].val == 0:
dividend.pop(0)
return [Poly(quotient), Poly(dividend)]
def __repr__(self):
return f"<Poly {self.coefs}>"
def eval(self, x):
y = GF(0)
for i in range(self.deg):
y += self.coefs[i] * x**GF(self.deg-i-1)
return y
def del_lead_zeros(self):
while len(self.coefs) > 1 and self.coefs[0].val == 0:
self.coefs.pop(0)
if len(self.coefs) == 0:
self.coefs = [GF(0)]
return self
def get_generator_poly(n):
poly = Poly([GF(1)])
for i in range(n):
poly *= Poly([GF(1), GF(2)**GF(i)])
return poly
class ReedSolomonException(Exception):
pass
def correct(data, ec):
n = len(ec)
data = Poly([GF(int(cw, 2)) for cw in data+ec])
##print("data", list(map(lambda c:c.val, data.coefs)))
print("r(x)", data)
syndrome = [0]*n
corrupted = False
for i in range(n):
syndrome[i] = data.eval(GF.EXP[i])
if syndrome[i].val != 0:
corrupted = True
if not corrupted:
print("No errors")
return data
syndrome = Poly(syndrome[::-1])
print("syndrome", syndrome)
#Find locator poly
sigma, omega = euclidean_algorithm(Poly([GF(1)]+[GF(0) for i in range(n)]), syndrome, n)
print("locator", sigma)
print("evaluator", omega)
error_loc = find_error_loc(sigma)
print("location", error_loc)
error_mag = find_error_mag(omega, error_loc)
print("mag", error_mag)
for i in range(len(error_loc)):
pos = GF(error_loc[i]).log()
pos = data.deg - pos.val - 1
if pos < 0:
raise ReedSolomonException("Bad error location")
data.coefs[pos] += GF(error_mag[i])
return data
def euclidean_algorithm(a, b, R):
if a.deg < b.deg:
a, b = b, a
r_last = a
r = b
t_last = Poly([GF(0)])
t = Poly([GF(1)])
while r.deg-1 >= int(R/2):
r_last_last = r_last
t_last_last = t_last
r_last = r
t_last = t
if r_last.coefs[0] == 0:
raise ReedSolomonException("r_{i-1} was zero")
r = r_last_last
q = Poly([GF(0)])
denom_lead_term = r_last.coefs[0]
dlt_inv = denom_lead_term ** GF(-1)
I = 0
while r.deg >= r_last.deg and r.coefs[0] != 0:
I += 1
deg_diff = r.deg - r_last.deg
scale = r.coefs[0] * dlt_inv
q += Poly([scale]+[GF(0) for i in range(deg_diff)])
r += r_last * Poly([scale]+[GF(0) for i in range(deg_diff)])
q.del_lead_zeros()
r.del_lead_zeros()
if I > 100:
raise ReedSolomonException("Too long")
t = (q * t_last).del_lead_zeros() + t_last_last
t.del_lead_zeros()
if r.deg >= r_last.deg:
raise ReedSolomonException("Division algorithm failed to reduce polynomial")
sigma_tilde_at_zero = t.coefs[-1]
if sigma_tilde_at_zero.val == 0:
raise ReedSolomonException("sigma_tilde(0) was zero")
inv = Poly([sigma_tilde_at_zero ** GF(-1)])
sigma = t * inv
omega = r * inv
return [sigma, omega]
def find_error_loc(error_loc):
num_errors = error_loc.deg-1
if num_errors == 1:
return [error_loc.coefs[-2].val]
result = [0]*num_errors
e = 0
i = 1
while i < 256 and e < num_errors:
if error_loc.eval(GF(i)).val == 0:
result[e] = (GF(i) ** GF(-1)).val
e += 1
i += 1
if e != num_errors:
raise ReedSolomonException("Error locator degree does not match number of roots")
return result
def find_error_mag(error_eval, error_loc):
s = len(error_loc)
result = [0]*s
for i in range(s):
xi_inv = GF(error_loc[i]) ** GF(-1)
denom = GF(1)
for j in range(s):
if i != j:
denom *= GF(1) + GF(error_loc[j]) * xi_inv
result[i] = ( error_eval.eval(xi_inv) * (denom ** GF(-1)) ).val
return result
if __name__ == "__main__":
m = Poly([GF(67),GF(111),GF(100),GF(101),GF(115)])
g = get_generator_poly(4)
print()
print(g)
print(m/g)
print()
data = [67,111,110,101,115]
#ec = [119,123,82]
ec = [50,166,245,58]
data = [f"{n:08b}" for n in data]
ec = [f"{n:08b}" for n in ec]
print(correct(data, ec))

View File

@ -0,0 +1,78 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generates latex table for version capacity information
(C) 2022 Louis Heredero louis.heredero@edu.vs.ch
"""
levels = "LMQH"
start = r"""\def\arraystretch{1.5}
\begin{table}[H]
\centering
\begin{longtabu}{|[2pt]c|c|c:c:c:c|[2pt]}
\tabucline[2pt]{-}
Version & Correction level & Numerical & Alphanumerical & Byte & Kanji \\
\tabucline[2pt]{-}
"""
end = r""" \tabucline[2pt]{-}
\end{longtabu}
\caption{Version capacities}
\label{tab:qr_versions}
\end{table}
\def\arraystretch{1}
"""
start = r"""\def\arraystretch{1.2}
\begin{center}
\begin{longtabu}{|[2pt]c|c|c:c:c:c|[2pt]}
\caption{Version capacities}
\label{tab:qr_versions}\\
\tabucline[2pt]{-}
Version & Correction level & Numerical & Alphanumerical & Byte & Kanji \\
\tabucline[2pt]{-}
\endfirsthead
\multicolumn{6}{r}{\emph{Continued from last page}}\\
\endhead
\multicolumn{6}{r}{\emph{Continued on next page}}\\
\endfoot
\tabucline[2pt]{-}
\endlastfoot
"""
end = r""" \hline
\end{longtabu}
\end{center}
\def\arraystretch{1}
"""
if __name__ == "__main__":
with open("qr_versions.txt", "r") as f_txt, open("qr_versions.tex", "w") as f_tex:
versions = f_txt.read().split("\n\n")
f_tex.write(start)
for i, version in enumerate(versions):
lvls = version.split("\n")
if i > 0:
f_tex.write(" \\hline\n")
f_tex.write(f" \\multirow{{4}}{{*}}{{{i+1:2}}}")
#f_tex.write(f" {i+1:2}")
for j, lvl in enumerate(lvls):
values = " & ".join(
map(lambda s: f"{s:>4}", lvl.split("\t"))
)
if j > 0:
f_tex.write(" ")
#f_tex.write(" ")
f_tex.write(f" & {levels[j]} & {values} \\\\{'*' if j < 3 else ''}\n")
f_tex.write(end)