Moved python files from sw to sw/python; Moved scritps into sw/python/scripts
This commit is contained in:
2
sw/python/utility/__init__.py
Normal file
2
sw/python/utility/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
"""This package contains various utilities that can be used in combination
|
||||
with the decoders."""
|
||||
249
sw/python/utility/codes.py
Normal file
249
sw/python/utility/codes.py
Normal file
@@ -0,0 +1,249 @@
|
||||
"""This file Helper functions for generating an H matrix from alist data.
|
||||
Code from https://github.com/gnuradio/gnuradio/blob/master/gr-fec/python/fec
|
||||
/LDPC/Generate_LDPC_matrix_functions.py
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
#
|
||||
# Related to alist files
|
||||
#
|
||||
|
||||
|
||||
def _parse_alist_header(header):
|
||||
size = header.split()
|
||||
return int(size[0]), int(size[1])
|
||||
|
||||
|
||||
def read_alist_file(filename):
|
||||
"""
|
||||
This function reads in an alist file and creates the
|
||||
corresponding parity check matrix H. The format of alist
|
||||
files is described at:
|
||||
http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html
|
||||
"""
|
||||
|
||||
with open(filename, 'r') as myfile:
|
||||
data = myfile.readlines()
|
||||
numCols, numRows = _parse_alist_header(data[0])
|
||||
|
||||
H = np.zeros((numRows, numCols))
|
||||
|
||||
# The locations of 1s starts in the 5th line of the file
|
||||
for lineNumber in np.arange(4, 4 + numCols):
|
||||
indices = data[lineNumber].split()
|
||||
for index in indices:
|
||||
H[int(index) - 1, lineNumber - 4] = 1
|
||||
|
||||
return H
|
||||
|
||||
|
||||
#
|
||||
# G matrices of specific codes
|
||||
#
|
||||
|
||||
|
||||
# @formatter:off
|
||||
|
||||
Gs = {'Hamming_7_4': np.array([[1, 0, 0, 0, 0, 1, 1],
|
||||
[0, 1, 0, 0, 1, 0, 1],
|
||||
[0, 0, 1, 0, 1, 1, 0],
|
||||
[0, 0, 0, 1, 1, 1, 1]]),
|
||||
|
||||
'Golay_24_12': np.array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1]]),
|
||||
|
||||
'BCH_15_7': np.array([[1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1],
|
||||
[0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1]]),
|
||||
|
||||
'BCH_31_6': np.array([[1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1],
|
||||
[0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1],
|
||||
[0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1],
|
||||
[0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1]]),
|
||||
|
||||
'BCH_31_11': np.array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1]]),
|
||||
|
||||
'BCH_31_16': np.array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1]]),
|
||||
|
||||
'BCH_31_21': np.array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1]]),
|
||||
|
||||
'BCH_63_16': np.array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1],
|
||||
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1]]),
|
||||
|
||||
'BCH_63_30': np.array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1]]),
|
||||
|
||||
# TODO: Fix this. This code should be systematic
|
||||
'BCH_63_45': np.array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1],
|
||||
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1]])
|
||||
}
|
||||
|
||||
# @formatter:on
|
||||
|
||||
|
||||
#
|
||||
# Utilities for systematic codes
|
||||
#
|
||||
|
||||
|
||||
def get_systematic_H(G: np.array) -> np.array:
|
||||
"""Compute the H matrix for a systematic code.
|
||||
|
||||
:param G: Generator matrix of the systematic code
|
||||
:return: Parity check matrix H
|
||||
"""
|
||||
k, n = G.shape
|
||||
|
||||
I = G[:, :k]
|
||||
assert np.array_equal(I, np.identity(k))
|
||||
|
||||
P = G[:, k:]
|
||||
|
||||
H = np.zeros(shape=(n - k, n))
|
||||
H[:, :k] = P.T
|
||||
H[:, k:] = np.identity(n - k)
|
||||
|
||||
return H
|
||||
72
sw/python/utility/misc.py
Normal file
72
sw/python/utility/misc.py
Normal file
@@ -0,0 +1,72 @@
|
||||
import unicodedata
|
||||
import re
|
||||
import typing
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
|
||||
def slugify(value, allow_unicode=False):
|
||||
"""
|
||||
Taken from https://github.com/django/django/blob/master/django/utils
|
||||
/text.py
|
||||
Convert to ASCII if 'allow_unicode' is False. Convert spaces or repeated
|
||||
dashes to single dashes. Remove characters that aren't alphanumerics,
|
||||
underscores, or hyphens. Convert to lowercase. Also strip leading and
|
||||
trailing whitespace, dashes, and underscores.
|
||||
"""
|
||||
value = str(value)
|
||||
if allow_unicode:
|
||||
value = unicodedata.normalize('NFKC', value)
|
||||
else:
|
||||
value = unicodedata.normalize('NFKD', value).encode('ascii',
|
||||
'ignore').decode(
|
||||
'ascii')
|
||||
value = re.sub(r'[^\w\s-]', '', value.lower())
|
||||
return re.sub(r'[-\s]+', '-', value).strip('-_')
|
||||
|
||||
|
||||
def pgf_reformat_data_3d(results: typing.Sequence, x_param_name: str,
|
||||
y_param_name: str,
|
||||
z_param_names: typing.Sequence[str]):
|
||||
"""Reformat the results obtained from the GenericMultithreadedSimulator
|
||||
into a form usable by pgfplots.
|
||||
|
||||
:param results: Results from GenericMultiThreadedSimulator
|
||||
(dict of the form {params1: results1, params2: results2, ...}),
|
||||
where resultsN and paramsN are themselves dicts:
|
||||
paramsN = {param_name_1: val, param_name_2: val, ...}
|
||||
resultsN = {result_name_1: val, result_name_2: val, ...}
|
||||
:param x_param_name:
|
||||
:param y_param_name:
|
||||
:param z_param_names:
|
||||
:return: pandas DataFrame of the following form:
|
||||
{x_param_name: [x1, x1, x1, ..., x2, x2, x2, ...],
|
||||
y_param_name: [y1, y2, y3, ..., y1, y2, y3, ...],
|
||||
z_param_name: [z11, z21, z31, ..., z12, z22, z32, ...]}
|
||||
"""
|
||||
# Create result variables
|
||||
x = np.zeros(len(results))
|
||||
y = np.zeros(len(results))
|
||||
zs = {name: np.zeros(len(results)) for name in z_param_names}
|
||||
|
||||
# Populate result variables
|
||||
for i, (params, result) in enumerate(results.items()):
|
||||
x_val = params[x_param_name]
|
||||
y_val = params[y_param_name]
|
||||
for z_param_name in z_param_names:
|
||||
zs[z_param_name][i] = result[z_param_name]
|
||||
|
||||
x[i] = x_val
|
||||
y[i] = y_val
|
||||
|
||||
# Create and return pandas DataFrame
|
||||
df = pd.DataFrame({x_param_name: x, y_param_name: y})
|
||||
for z_param_name in z_param_names:
|
||||
df[z_param_name] = zs[z_param_name]
|
||||
|
||||
return df.sort_values(by=[x_param_name, y_param_name])
|
||||
|
||||
|
||||
def count_bit_errors(x: np.array, x_hat: np.array) -> int:
|
||||
"""Count the number of different bits between two words."""
|
||||
return np.sum(x != x_hat)
|
||||
34
sw/python/utility/noise.py
Normal file
34
sw/python/utility/noise.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""Utility functions relating to noise and SNR calculations."""
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def get_noise_variance_from_SNR(SNR: float, n: int, k: int) -> float:
|
||||
"""Calculate the variance of the noise from an SNR and the signal
|
||||
amplitude.
|
||||
|
||||
:param SNR: Signal-to-Noise-Ratio in dB (E_b/N_0)
|
||||
:param n: Length of a codeword of the used code
|
||||
:param k: Length of a dataword of the used code
|
||||
:return: Variance of the noise
|
||||
"""
|
||||
SNR_linear = 10 ** (SNR / 10)
|
||||
variance = 1 / (2 * (k / n) * SNR_linear)
|
||||
|
||||
return variance
|
||||
|
||||
|
||||
def add_awgn(c: np.array, SNR: float, n: int, k: int) -> np.array:
|
||||
"""Add Additive White Gaussian Noise to a data vector. As this function
|
||||
adds random noise to the input, the output changes, even if it is called
|
||||
multiple times with the same input.
|
||||
|
||||
:param c: Binary vector representing the data to be transmitted
|
||||
:param SNR: Signal-to-Noise-Ratio in dB
|
||||
:param n: Length of a codeword of the used code
|
||||
:param k: Length of a dataword of the used code
|
||||
:return: Data vector with added noise
|
||||
"""
|
||||
noise_var = get_noise_variance_from_SNR(SNR, n, k)
|
||||
y = c + np.sqrt(noise_var) * np.random.normal(size=c.size)
|
||||
return y
|
||||
77
sw/python/utility/simulation/__init__.py
Normal file
77
sw/python/utility/simulation/__init__.py
Normal file
@@ -0,0 +1,77 @@
|
||||
"""Simulation package.
|
||||
|
||||
This package provides a way to easily define simulations in such a way that
|
||||
they can be paused and resumed.
|
||||
|
||||
General Structure
|
||||
=================
|
||||
The package consists of 3 main components:
|
||||
- The 'SimulationDeSerializer': Responsible for file IO
|
||||
- The 'Simulator': Responsible for the actual simulating
|
||||
- The 'SimulationManager': Delegates work to the DeSerializer and the
|
||||
Simulator
|
||||
|
||||
The Simulator Class
|
||||
===================
|
||||
For each new simulating task, a new 'Simulator' must be defined. The
|
||||
requirements for this class are the following:
|
||||
- Must define the 'start_or_continue()', 'stop()' and
|
||||
'get_current_results()' functions
|
||||
- Must be picklable in order to store the simulation state
|
||||
|
||||
An example simulator could look as follows:
|
||||
----------------------------------------------------------------
|
||||
class SomeSimulator:
|
||||
def __init__(self, num_iterations):
|
||||
self._num_iterations = num_iterations
|
||||
self._current_iter = 0
|
||||
|
||||
self._simulation_running = False
|
||||
|
||||
self._results = pd.DataFrame()
|
||||
|
||||
def _perform_iteration(self):
|
||||
# Perform iteration and append results
|
||||
...
|
||||
|
||||
def start_or_continue(self) -> None:
|
||||
self._simulation_running = True
|
||||
|
||||
while self._simulation_running and (
|
||||
self._current_iter < self._num_iterations):
|
||||
self._perform_iteration()
|
||||
|
||||
def stop(self) -> None:
|
||||
self._simulation_running = False
|
||||
|
||||
def get_current_results(self) -> pd.DataFrame:
|
||||
return self._results
|
||||
----------------------------------------------------------------
|
||||
|
||||
Usage
|
||||
=====
|
||||
To start a new simulation:
|
||||
----------------------------------------------------------------
|
||||
sim_mgr = SimulationManager(results_dir="results", saves_dir="saves")
|
||||
|
||||
sim = SomeSimulator(num_iterations=100)
|
||||
sim_mgr.configure_simulation(simulator=sim, name='Some Simulation', \
|
||||
column_labels=['label1', 'label2'])
|
||||
sim_mgr.start()
|
||||
----------------------------------------------------------------
|
||||
|
||||
To check for a previously interrupted simulation and continue:
|
||||
----------------------------------------------------------------
|
||||
sim_mgr = SimulationManager(results_dir="results", saves_dir="saves")
|
||||
|
||||
unfinished_sims = sim_mgr.get_unfinished()
|
||||
|
||||
if len(unfinished_sims) > 0:
|
||||
sim_mgr.load_unfinished(unfinished_sims[0])
|
||||
sim_mgr.simulate()
|
||||
----------------------------------------------------------------
|
||||
"""
|
||||
|
||||
|
||||
from utility.simulation.management import SimulationManager, \
|
||||
SimulationDeSerializer
|
||||
239
sw/python/utility/simulation/management.py
Normal file
239
sw/python/utility/simulation/management.py
Normal file
@@ -0,0 +1,239 @@
|
||||
import json
|
||||
import pandas as pd
|
||||
import typing
|
||||
import signal
|
||||
import pickle
|
||||
import os
|
||||
from pathlib import Path
|
||||
import platform
|
||||
from datetime import datetime
|
||||
import timeit
|
||||
import collections.abc
|
||||
|
||||
from utility import misc
|
||||
|
||||
|
||||
class SimulationDeSerializer:
|
||||
"""Class responsible for file management, de- and serialization of
|
||||
Simulator objects."""
|
||||
|
||||
def __init__(self, save_dir: str, results_dir: str):
|
||||
self._saves_dir = save_dir
|
||||
self._results_dir = results_dir
|
||||
|
||||
Path(self._saves_dir).mkdir(parents=True, exist_ok=True)
|
||||
Path(self._results_dir).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def _get_savefile_path(self, sim_name):
|
||||
return f"{self._saves_dir}/{misc.slugify(sim_name)}_state.pickle"
|
||||
|
||||
def _get_metadata_path(self, sim_name):
|
||||
return f"{self._results_dir}/{misc.slugify(sim_name)}_metadata.json"
|
||||
|
||||
def _get_results_path(self, sim_name):
|
||||
return f"{self._results_dir}/{misc.slugify(sim_name)}.csv"
|
||||
|
||||
def _read_metadata(self, sim_name) -> typing.Dict:
|
||||
with open(self._get_metadata_path(sim_name), 'r',
|
||||
encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
|
||||
def _save_metadata(self, sim_name, metadata) -> None:
|
||||
with open(self._get_metadata_path(sim_name), 'w+',
|
||||
encoding='utf-8') as f:
|
||||
json.dump(metadata, f, ensure_ascii=False, indent=4)
|
||||
|
||||
def unfinished_sim_present(self, sim_name: str):
|
||||
"""Check if the savefile of a previously paused simulation is
|
||||
present.
|
||||
|
||||
:param sim_name: Name
|
||||
:return: True if a paused simulation with the given name is found
|
||||
"""
|
||||
return os.path.isfile(
|
||||
self._get_savefile_path(sim_name)) and os.path.isfile(
|
||||
self._get_metadata_path(sim_name))
|
||||
|
||||
# TODO: Make the directories configurable in the init function
|
||||
def get_unfinished_sims(self) -> typing.List[str]:
|
||||
"""Get a list unfinished simulations."""
|
||||
save_files = [f for f in os.listdir(self._saves_dir) if
|
||||
os.path.isfile(os.path.join(self._saves_dir, f))]
|
||||
|
||||
state_files = [f for f in save_files if f.endswith("_state.pickle")]
|
||||
sim_slugs = [f.removesuffix("_state.pickle") for f in state_files]
|
||||
|
||||
sim_names = [self._read_metadata(slug)["name"] for slug in sim_slugs]
|
||||
|
||||
return sim_names
|
||||
|
||||
def remove_unfinished_sim(self, sim_name: str):
|
||||
"""Remove the savefile of a previously paused simulation.
|
||||
|
||||
:param sim_name: Name of the simulation
|
||||
"""
|
||||
os.remove(self._get_savefile_path(sim_name))
|
||||
# os.remove(self._get_metadata_path(sim_name))
|
||||
|
||||
def save_state(self, simulator: typing.Any, sim_name: str,
|
||||
metadata: typing.Dict) -> None:
|
||||
"""Save the state of a currently running simulation.
|
||||
|
||||
:param simulator: Simulator object
|
||||
:param sim_name: Name of the simulation
|
||||
:param metadata: Metadata to be saved besides the actual state
|
||||
"""
|
||||
# Save metadata
|
||||
self._save_metadata(sim_name, metadata)
|
||||
|
||||
# Save simulation state
|
||||
with open(self._get_savefile_path(sim_name), "wb") as file:
|
||||
pickle.dump(simulator, file)
|
||||
|
||||
def read_state(self, sim_name: str) -> typing.Tuple[
|
||||
typing.Any, typing.Dict]:
|
||||
"""Read the saved state of a paused simulation.
|
||||
|
||||
:param sim_name: Name of the simulation
|
||||
:return: Tuple of the form (simulator, metadata)
|
||||
"""
|
||||
# Read metadata
|
||||
metadata = self._read_metadata(sim_name)
|
||||
|
||||
# Read simulation state
|
||||
simulator = None
|
||||
with open(self._get_savefile_path(sim_name), "rb") as file:
|
||||
simulator = pickle.load(file)
|
||||
|
||||
return simulator, metadata
|
||||
|
||||
# TODO: Is the simulator object actually necessary here?
|
||||
def save_results(self, simulator: typing.Any, sim_name: str,
|
||||
metadata: typing.Dict) -> None:
|
||||
"""Save simulation results to file.
|
||||
|
||||
:param simulator: Simulator object. Used to obtain the data
|
||||
:param sim_name: Name of the simulation. Determines the filename
|
||||
:param metadata: Metadata to be saved besides the actual simulation
|
||||
results
|
||||
"""
|
||||
# Save metadata
|
||||
self._save_metadata(sim_name, metadata)
|
||||
|
||||
# Save current results
|
||||
simulator.current_results.to_csv(self._get_results_path(sim_name),
|
||||
index=False)
|
||||
|
||||
def read_results(self, sim_name: str) -> typing.Tuple[
|
||||
pd.DataFrame, typing.Dict]:
|
||||
"""Read simulation results from file.
|
||||
|
||||
:param sim_name: Name of the simulation.
|
||||
:return: Tuple of the form (data, metadata), where data is a pandas
|
||||
dataframe and metadata is a dict
|
||||
"""
|
||||
# Read metadata
|
||||
metadata = self._read_metadata(sim_name)
|
||||
|
||||
# Read results
|
||||
results = pd.read_csv(self._get_results_path(sim_name))
|
||||
|
||||
return results, metadata
|
||||
|
||||
|
||||
# TODO: Autosave simulation every so often
|
||||
# TODO: Comment explaining what a Simulator class is
|
||||
class SimulationManager:
|
||||
"""This class only contains functions relating to stopping and
|
||||
restarting of simulations (and storing of the simulation state in a
|
||||
file, to be resumed at a later date).
|
||||
|
||||
All actual work is outsourced to a provided simulator class.
|
||||
"""
|
||||
|
||||
def __init__(self, saves_dir: str, results_dir: str):
|
||||
"""Construct a SimulationManager object.
|
||||
|
||||
:param saves_dir: Directory in which the simulation state of a paused
|
||||
simulation should be stored
|
||||
:param results_dir: Directory in which the results of the simulation
|
||||
should be stored
|
||||
"""
|
||||
self._de_serializer = SimulationDeSerializer(saves_dir, results_dir)
|
||||
|
||||
self._simulator = None
|
||||
self._sim_name = None
|
||||
self._metadata = {"duration": 0}
|
||||
self._sim_start_time = None
|
||||
|
||||
def _sim_configured(self) -> bool:
|
||||
"""Check whether 'configure_simulation()' has been called."""
|
||||
return (self._simulator is not None) and (
|
||||
self._sim_name is not None) and (
|
||||
self._metadata is not None)
|
||||
|
||||
def configure_simulation(self, simulator: typing.Any, name: str,
|
||||
additional_metadata: dict = {}) -> None:
|
||||
"""Configure a new simulation."""
|
||||
self._simulator = simulator
|
||||
self._sim_name = name
|
||||
self._metadata["name"] = name
|
||||
self._metadata["platform"] = platform.platform()
|
||||
self._metadata.update(additional_metadata)
|
||||
|
||||
def get_unfinished(self) -> typing.List[str]:
|
||||
"""Get a list of names of all present unfinished simulations."""
|
||||
return self._de_serializer.get_unfinished_sims()
|
||||
|
||||
def load_unfinished(self, sim_name: str) -> None:
|
||||
"""Load the state of an unfinished simulation form its savefile.
|
||||
|
||||
Warning: This function deletes the savefile after loading.
|
||||
"""
|
||||
assert self._de_serializer.unfinished_sim_present(sim_name)
|
||||
|
||||
self._sim_name = sim_name
|
||||
self._simulator, self._metadata = self._de_serializer.read_state(
|
||||
sim_name)
|
||||
|
||||
self._de_serializer.remove_unfinished_sim(sim_name)
|
||||
|
||||
# TODO: Metadata is being written twice here. Should save_results() also
|
||||
# save the metadata?
|
||||
def _exit_gracefully(self, *args) -> None:
|
||||
"""Handler called when the program is interrupted. Pauses and saves
|
||||
the currently running simulation."""
|
||||
if self._sim_configured():
|
||||
self._simulator.stop()
|
||||
|
||||
self._metadata["end_time"] = f"{datetime.now(tz=None)}"
|
||||
self._metadata["duration"] \
|
||||
+= timeit.default_timer() - self._sim_start_time
|
||||
|
||||
self._de_serializer.save_state(self._simulator, self._sim_name,
|
||||
self._metadata)
|
||||
self._de_serializer.save_results(self._simulator, self._sim_name,
|
||||
self._metadata)
|
||||
|
||||
exit()
|
||||
|
||||
def simulate(self) -> None:
|
||||
"""Start the simulation. This is a blocking call."""
|
||||
assert self._sim_configured()
|
||||
|
||||
try:
|
||||
self._sim_start_time = timeit.default_timer()
|
||||
|
||||
self._simulator.start_or_continue()
|
||||
|
||||
self._metadata["end_time"] = f"{datetime.now(tz=None)}"
|
||||
self._metadata["duration"] \
|
||||
+= timeit.default_timer() - self._sim_start_time
|
||||
|
||||
self._de_serializer.save_results(self._simulator, self._sim_name,
|
||||
self._metadata)
|
||||
except KeyboardInterrupt:
|
||||
self._exit_gracefully()
|
||||
|
||||
def get_current_results(self) -> pd.DataFrame:
|
||||
return self._simulator.current_results
|
||||
121
sw/python/utility/simulation/simulators.py
Normal file
121
sw/python/utility/simulation/simulators.py
Normal file
@@ -0,0 +1,121 @@
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import typing
|
||||
from tqdm import tqdm
|
||||
from concurrent.futures import ProcessPoolExecutor, process, wait
|
||||
from functools import partial
|
||||
from multiprocessing import Lock
|
||||
|
||||
from utility import noise
|
||||
|
||||
|
||||
# TODO: Fix ProximalDecoder_Dynamic
|
||||
# from cpp_modules.cpp_decoders import ProximalDecoder_Dynamic as
|
||||
# ProximalDecoder
|
||||
|
||||
|
||||
def count_bit_errors(d: np.array, d_hat: np.array) -> int:
|
||||
"""Count the number of wrong bits in a decoded codeword.
|
||||
|
||||
:param d: Originally sent data
|
||||
:param d_hat: Received data
|
||||
:return: Number of bit errors
|
||||
"""
|
||||
return np.sum(d != d_hat)
|
||||
|
||||
|
||||
class HashableDict:
|
||||
"""Class behaving like an immutable dict. More importantly it is
|
||||
hashable and thus usable as a key type for another dict."""
|
||||
|
||||
def __init__(self, data_dict):
|
||||
assert (isinstance(data_dict, dict))
|
||||
for key, val in data_dict.items():
|
||||
self.__dict__[key] = val
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.__dict__[item]
|
||||
|
||||
def __str__(self):
|
||||
return str(self.__dict__)
|
||||
|
||||
|
||||
class GenericMultithreadedSimulator:
|
||||
def __init__(self, max_workers=8):
|
||||
self._format_func = None
|
||||
self._task_func = None
|
||||
self._task_params = None
|
||||
self._max_workers = max_workers
|
||||
|
||||
self._results = {}
|
||||
self._executor = None
|
||||
|
||||
@property
|
||||
def task_params(self):
|
||||
return self._task_params
|
||||
|
||||
@task_params.setter
|
||||
def task_params(self, sim_params):
|
||||
self._task_params = {HashableDict(iteration_params): iteration_params
|
||||
for iteration_params in sim_params}
|
||||
|
||||
@property
|
||||
def task_func(self):
|
||||
return self._task_func
|
||||
|
||||
@task_func.setter
|
||||
def task_func(self, func):
|
||||
self._task_func = func
|
||||
|
||||
@property
|
||||
def format_func(self):
|
||||
return self._format_func
|
||||
|
||||
@format_func.setter
|
||||
def format_func(self, func):
|
||||
self._format_func = func
|
||||
|
||||
def start_or_continue(self):
|
||||
assert self._task_func is not None
|
||||
assert self._task_params is not None
|
||||
assert self._format_func is not None
|
||||
|
||||
self._executor = ProcessPoolExecutor(max_workers=self._max_workers)
|
||||
|
||||
with tqdm(total=(len(self._task_params)), leave=False) as pbar:
|
||||
def done_callback(key, f):
|
||||
try:
|
||||
pbar.update(1)
|
||||
self._results[key] = f.result()
|
||||
del self._task_params[key]
|
||||
except process.BrokenProcessPool:
|
||||
# This exception is thrown when the program is
|
||||
# prematurely stopped with a KeyboardInterrupt
|
||||
pass
|
||||
|
||||
futures = []
|
||||
|
||||
for key, params in list(self._task_params.items()):
|
||||
future = self._executor.submit(self._task_func, params)
|
||||
future.add_done_callback(partial(done_callback, key))
|
||||
futures.append(future)
|
||||
|
||||
self._executor.shutdown(wait=True, cancel_futures=False)
|
||||
|
||||
def stop(self):
|
||||
assert self._executor is not None, "The simulation has to be started" \
|
||||
" before it can be stopped"
|
||||
self._executor.shutdown(wait=True, cancel_futures=True)
|
||||
|
||||
@property
|
||||
def current_results(self):
|
||||
return self._format_func(self._results)
|
||||
|
||||
def __getstate__(self):
|
||||
state = self.__dict__.copy()
|
||||
state["_executor"] = None
|
||||
return state
|
||||
|
||||
def __setstate__(self, state):
|
||||
self.__dict__.update(state)
|
||||
self._executor = ProcessPoolExecutor()
|
||||
1
sw/python/utility/test/__init__.py
Normal file
1
sw/python/utility/test/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""This package contains unit tests."""
|
||||
72
sw/python/utility/test/test_proximal.py
Normal file
72
sw/python/utility/test/test_proximal.py
Normal file
@@ -0,0 +1,72 @@
|
||||
import unittest
|
||||
import numpy as np
|
||||
from decoders import proximal
|
||||
|
||||
|
||||
class CheckParityTestCase(unittest.TestCase):
|
||||
"""Test case for the check_parity function."""
|
||||
|
||||
def test_check_parity(self):
|
||||
# Hamming(7,4) code
|
||||
G = np.array([[1, 1, 1, 0, 0, 0, 0],
|
||||
[1, 0, 0, 1, 1, 0, 0],
|
||||
[0, 1, 0, 1, 0, 1, 0],
|
||||
[1, 1, 0, 1, 0, 0, 1]])
|
||||
H = np.array([[1, 0, 1, 0, 1, 0, 1],
|
||||
[0, 1, 1, 0, 0, 1, 1],
|
||||
[0, 0, 0, 1, 1, 1, 1]])
|
||||
R = np.array([[0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1]])
|
||||
|
||||
decoder = proximal.ProximalDecoder(H)
|
||||
|
||||
d1 = np.array([0, 1, 0, 1])
|
||||
c1 = np.dot(np.transpose(G), d1) % 2
|
||||
|
||||
d2 = np.array([0, 0, 0, 0])
|
||||
c2 = np.dot(np.transpose(G), d2) % 2
|
||||
|
||||
d3 = np.array([1, 1, 1, 1])
|
||||
c3 = np.dot(np.transpose(G), d3) % 2
|
||||
|
||||
invalid_codeword = np.array([0, 1, 1, 0, 1, 1, 1])
|
||||
|
||||
self.assertEqual(decoder._check_parity(c1), True)
|
||||
self.assertEqual(decoder._check_parity(c2), True)
|
||||
self.assertEqual(decoder._check_parity(c3), True)
|
||||
self.assertEqual(decoder._check_parity(invalid_codeword), False)
|
||||
|
||||
|
||||
class GradientTestCase(unittest.TestCase):
|
||||
"""Test case for the calculation of the gradient of the
|
||||
code-constraint-polynomial."""
|
||||
|
||||
def test_grad_h(self):
|
||||
"""Test the gradient of the code-constraint polynomial."""
|
||||
# Hamming(7,4) code
|
||||
G = np.array([[1, 1, 1, 0, 0, 0, 0],
|
||||
[1, 0, 0, 1, 1, 0, 0],
|
||||
[0, 1, 0, 1, 0, 1, 0],
|
||||
[1, 1, 0, 1, 0, 0, 1]])
|
||||
H = np.array([[1, 0, 1, 0, 1, 0, 1],
|
||||
[0, 1, 1, 0, 0, 1, 1],
|
||||
[0, 0, 0, 1, 1, 1, 1]])
|
||||
R = np.array([[0, 0, 1, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 0, 0, 1, 0],
|
||||
[0, 0, 0, 0, 0, 0, 1]])
|
||||
|
||||
x = np.array([1, 2, -1, -2, 2, 1, -1]) # Some randomly chosen vector
|
||||
expected_grad_h = np.array(
|
||||
[4, 26, -8, -36, 38, 28, -32]) # Manually calculated result
|
||||
|
||||
decoder = proximal.ProximalDecoder(H)
|
||||
grad_h = decoder._grad_h(x)
|
||||
|
||||
self.assertEqual(np.array_equal(grad_h, expected_grad_h), True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
55
sw/python/utility/test/test_soft_decision.py
Normal file
55
sw/python/utility/test/test_soft_decision.py
Normal file
@@ -0,0 +1,55 @@
|
||||
import unittest
|
||||
import numpy as np
|
||||
from decoders import maximum_likelihood
|
||||
|
||||
|
||||
class CodewordGenerationTestCase(unittest.TestCase):
|
||||
def test_codeword_generation(self):
|
||||
"""Test case for data word and code word generation."""
|
||||
# Hamming(7,4) code
|
||||
G = np.array([[1, 1, 1, 0, 0, 0, 0],
|
||||
[1, 0, 0, 1, 1, 0, 0],
|
||||
[0, 1, 0, 1, 0, 1, 0],
|
||||
[1, 1, 0, 1, 0, 0, 1]])
|
||||
H = np.array([[1, 0, 1, 0, 1, 0, 1],
|
||||
[0, 1, 1, 0, 0, 1, 1],
|
||||
[0, 0, 0, 1, 1, 1, 1]])
|
||||
|
||||
decoder = maximum_likelihood.MLDecoder(G, H)
|
||||
|
||||
expected_datawords = np.array([[0, 0, 0, 0],
|
||||
[0, 0, 0, 1],
|
||||
[0, 0, 1, 0],
|
||||
[0, 0, 1, 1],
|
||||
[0, 1, 0, 0],
|
||||
[0, 1, 0, 1],
|
||||
[0, 1, 1, 0],
|
||||
[0, 1, 1, 1],
|
||||
[1, 0, 0, 0],
|
||||
[1, 0, 0, 1],
|
||||
[1, 0, 1, 0],
|
||||
[1, 0, 1, 1],
|
||||
[1, 1, 0, 0],
|
||||
[1, 1, 0, 1],
|
||||
[1, 1, 1, 0],
|
||||
[1, 1, 1, 1]])
|
||||
|
||||
expected_codewords = np.array([[0, 0, 0, 0, 0, 0, 0],
|
||||
[1, 1, 0, 1, 0, 0, 1],
|
||||
[0, 1, 0, 1, 0, 1, 0],
|
||||
[1, 0, 0, 0, 0, 1, 1],
|
||||
[1, 0, 0, 1, 1, 0, 0],
|
||||
[0, 1, 0, 0, 1, 0, 1],
|
||||
[1, 1, 0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 1, 1, 1, 1],
|
||||
[1, 1, 1, 0, 0, 0, 0],
|
||||
[0, 0, 1, 1, 0, 0, 1],
|
||||
[1, 0, 1, 1, 0, 1, 0],
|
||||
[0, 1, 1, 0, 0, 1, 1],
|
||||
[0, 1, 1, 1, 1, 0, 0],
|
||||
[1, 0, 1, 0, 1, 0, 1],
|
||||
[0, 0, 1, 0, 1, 1, 0],
|
||||
[1, 1, 1, 1, 1, 1, 1]])
|
||||
|
||||
self.assertEqual(np.array_equal(decoder._datawords, expected_datawords), True)
|
||||
self.assertEqual(np.array_equal(decoder._codewords, expected_codewords), True)
|
||||
48
sw/python/utility/test/test_utility.py
Normal file
48
sw/python/utility/test/test_utility.py
Normal file
@@ -0,0 +1,48 @@
|
||||
import unittest
|
||||
import numpy as np
|
||||
|
||||
from utility import noise, codes
|
||||
|
||||
|
||||
# TODO: Rewrite tests for new SNR calculation
|
||||
class NoiseAmpFromSNRTestCase(unittest.TestCase):
|
||||
"""Test case for noise amplitude calculation."""
|
||||
|
||||
def test_get_noise_amp_from_SNR(self):
|
||||
SNR1 = 0
|
||||
SNR2 = 3
|
||||
SNR3 = 20
|
||||
SNR4 = -20
|
||||
|
||||
var1 = noise.get_noise_variance_from_SNR(SNR1, n=8, k=8)
|
||||
var2 = noise.get_noise_variance_from_SNR(SNR2, n=8, k=8)
|
||||
var3 = noise.get_noise_variance_from_SNR(SNR3, n=8, k=8)
|
||||
var4 = noise.get_noise_variance_from_SNR(SNR4, n=8, k=8)
|
||||
|
||||
self.assertEqual(var1, 1 * 0.5)
|
||||
self.assertAlmostEqual(var2, 0.5 * 0.5, places=2)
|
||||
self.assertEqual(var3, 0.01 * 0.5)
|
||||
self.assertEqual(var4, 100 * 0.5)
|
||||
|
||||
|
||||
class CodesTestCase(unittest.TestCase):
|
||||
"""Tests relating to the 'codes' utilities."""
|
||||
|
||||
def test_get_systematic_H(self):
|
||||
# Hamming(7,4) code
|
||||
G = np.array([[1, 0, 0, 0, 0, 1, 1],
|
||||
[0, 1, 0, 0, 1, 0, 1],
|
||||
[0, 0, 1, 0, 1, 1, 0],
|
||||
[0, 0, 0, 1, 1, 1, 1]])
|
||||
|
||||
expected_H = np.array([[0, 1, 1, 1, 1, 0, 0],
|
||||
[1, 0, 1, 1, 0, 1, 0],
|
||||
[1, 1, 0, 1, 0, 0, 1]])
|
||||
|
||||
H = codes.get_systematic_H(G)
|
||||
|
||||
self.assertEqual(np.array_equal(expected_H, H), True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
24
sw/python/utility/test/test_visualization.py
Normal file
24
sw/python/utility/test/test_visualization.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import unittest
|
||||
from utility import visualization
|
||||
|
||||
|
||||
class NumRowsTestCase(unittest.TestCase):
|
||||
def test_get_num_rows(self):
|
||||
"""Test case for number of row calculation."""
|
||||
|
||||
num_rows1 = visualization._get_num_rows(num_graphs=4, num_cols=3)
|
||||
expected_rows1 = 2
|
||||
|
||||
num_rows2 = visualization._get_num_rows(num_graphs=5, num_cols=2)
|
||||
expected_rows2 = 3
|
||||
|
||||
num_rows3 = visualization._get_num_rows(num_graphs=4, num_cols=4)
|
||||
expected_rows3 = 1
|
||||
|
||||
num_rows4 = visualization._get_num_rows(num_graphs=4, num_cols=5)
|
||||
expected_rows4 = 1
|
||||
|
||||
self.assertEqual(num_rows1, expected_rows1)
|
||||
self.assertEqual(num_rows2, expected_rows2)
|
||||
self.assertEqual(num_rows3, expected_rows3)
|
||||
self.assertEqual(num_rows4, expected_rows4)
|
||||
75
sw/python/utility/visualization.py
Normal file
75
sw/python/utility/visualization.py
Normal file
@@ -0,0 +1,75 @@
|
||||
import seaborn as sns
|
||||
import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
import typing
|
||||
from itertools import chain
|
||||
import math
|
||||
|
||||
|
||||
def _get_num_rows(num_graphs: int, num_cols: int) -> int:
|
||||
"""Get the minimum number of rows needed to show a certain number of
|
||||
graphs, given a certain number of columns.
|
||||
|
||||
:param num_graphs: Number of graphs
|
||||
:param num_cols: Number of columns
|
||||
:return: Number of rows
|
||||
"""
|
||||
return math.ceil(num_graphs / num_cols)
|
||||
|
||||
|
||||
# TODO: Handle number of graphs not nicely fitting into rows and columns
|
||||
def plot_BERs(title: str,
|
||||
data: typing.Sequence[
|
||||
typing.Tuple[str, pd.DataFrame, typing.Sequence[str]]],
|
||||
num_cols: int = 3) -> plt.figure:
|
||||
"""This function creates a matplotlib figure containing a number of plots.
|
||||
|
||||
The plots created are logarithmic and the scaling is adjusted to be
|
||||
sensible for BER plots.
|
||||
|
||||
:param title: Title of the figure
|
||||
:param data: Sequence of tuples. Each tuple corresponds to a new plot and
|
||||
is of the following form: [graph_title, pd.Dataframe, [line_label_1,
|
||||
line_label2, ...]]. Each dataframe is assumed to have an "SNR" column
|
||||
that is used as the x axis.
|
||||
:param num_cols: Number of columns in which the graphs should be
|
||||
arranged in the resulting figure
|
||||
:return: Matplotlib figure
|
||||
"""
|
||||
# Determine layout and create figure
|
||||
|
||||
num_graphs = len(data)
|
||||
num_rows = _get_num_rows(num_graphs, num_cols)
|
||||
|
||||
fig, axes = plt.subplots(num_rows, num_cols,
|
||||
figsize=(num_cols * 4, num_rows * 4),
|
||||
squeeze=False)
|
||||
fig.suptitle(title)
|
||||
|
||||
fig.subplots_adjust(left=0.1,
|
||||
bottom=0.1,
|
||||
right=0.9,
|
||||
top=0.9,
|
||||
wspace=0.3,
|
||||
hspace=0.4)
|
||||
|
||||
axes = list(chain.from_iterable(axes))[
|
||||
:num_graphs] # Flatten the 2d axes array
|
||||
|
||||
# Populate axes
|
||||
|
||||
for axis, (graph_title, df, labels) in zip(axes, data):
|
||||
column_names = [column for column in df.columns.values.tolist() if
|
||||
not column == "SNR"]
|
||||
|
||||
for column, label in zip(column_names, labels):
|
||||
sns.lineplot(ax=axis, data=df, x="SNR", y=column, label=label)
|
||||
|
||||
axis.set_title(graph_title)
|
||||
axis.set(yscale="log")
|
||||
axis.set_xlabel("SNR")
|
||||
axis.set_ylabel("BER")
|
||||
axis.set_yticks([10e-5, 10e-4, 10e-3, 10e-2, 10e-1, 10e0])
|
||||
axis.legend()
|
||||
|
||||
return fig
|
||||
Reference in New Issue
Block a user