-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrow_echleon.py
156 lines (118 loc) · 4.38 KB
/
row_echleon.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import sympy as sympy
from sympy import GF
from sympy.polys.matrices import DomainMatrix
import numpy as np
from Hmatrixbaby import ParityCheckMatrix
def len_unique_elements(arr):
return len(set(arr))
def get_H_arr(dv, dc, k, n):
""" Gets Tanner Graph Connections for each Variable Node """
# Initialize an array of size dv*n and fill it with numbers for each variable node's connections
arr = np.arange(0, dv*n)
flag = 0
while True:
flag = 0
# Generate a random permutation of the array
arr = np.random.permutation(arr)
# Checking if each check node is connected to dv variable nodes
t = [arr[i:i+dv] for i in range(0, len(arr), dv)]
for i in t:
i = i//dc
if len_unique_elements(i) != dv:
flag +=1
# Break if all check nodes are connected to dv variable nodes
if flag == 0:
break
return arr
def get_H_Matrix(dv, dc, k, n, Harr=None):
""" Creates the H matrix from the Variable Node Connections of the Tanner Graph """
if Harr is None:
Harr = get_H_arr(dv, dc, k, n)
# Initialize H matrix - the size is wrong will need to fix at some point
H = np.zeros((n-k, n))
# Fill H matrix where Variable Node is connected to Check Node
for (i,j) in enumerate(Harr):
H[j//dc, i//dv] = 1
return H
def get_H_matrix_sclpdc(dv, dc, k, n, Harr):
""" Creates the H matrix from the Variable Node Connections of the variable Tanner Graph """
if Harr is None:
Harr = get_H_arr(dv, dc, k, n)
# Initialize H matrix - the size is wrong will need to fix at some point
H = np.zeros((n-k, n))
dv = dv[0]
# Fill H matrix where Variable Node is connected to Check Node
for (i,j) in enumerate(Harr):
H[j, i//dv] = 1
return H
def get_reduced_row_echleon_form_H(H, ffdim=2):
""" Returns the reduced row echleon form of H """
# Using the Domain Matrice Instead
ff = GF(ffdim)
H = DomainMatrix([[ff(H[i,j]) for j in range(H.shape[1])] for i in range(H.shape[0])], H.shape, ff)
H_rref = H.rref()[0]
return np.array(H_rref.to_Matrix())
def check_standard_form_variance(H):
""" Checks if the H matrix is in standard form and returns columns that need changing """
n = H.shape[1]
k = n - H.shape[0]
shape = H.shape
I_dim = n-k
I = np.eye(I_dim)
columns_to_change = {}
rows = shape[1]
print(H.shape)
# Check if the last I_dim columns are I
if np.all(H[:,k:n] == I):
return None
else:
# Find the columns that need changing
for i in range(k, n):
if not np.all(H[:,i] == I[:,i-k]):
columns_to_change[i] = I[:,i-k]
return columns_to_change
def switch_columns(H, columns_to_change):
""" Finds and makes the necessary column switches to convert H to standard form """
# If no columns need changing, return
if not columns_to_change:
return H, None
n = H.shape[1]
k = n - H.shape[0]
column_positions = list(columns_to_change.keys())
changes_made = []
switches = []
I = np.eye(n-k)
for i in column_positions:
for j in range(n):
if np.all(H[:,j] == I[:, i-k]):
if j in changes_made:
continue
changes_made.append(i)
switches.append((i,j))
t = H[:,i].copy()
H[:,i] = H[:,j]
H[:,j] = t
break
return H, switches
def standard_H_to_G(H, ffdim=2, switches = None):
""" Inverts the standard H matrix to get the Generator Matrix"""
n = H.shape[1]
k = n - H.shape[0]
P = -H[:,0:k]
G = np.hstack((np.eye(k), P.T)) % ffdim
if switches is None:
return G.astype(int)
# Since switches made forward, need to reverse list to undo
switches = list(reversed(switches))
if switches:
for i in switches:
t = G[:,i[0]].copy()
G[:,i[0]] = G[:,i[1]]
G[:,i[1]] = t
return G.astype(int)
def parity_to_generator(H, ffdim=2):
""" Converts a parity check matrix to a generator matrix """
H_rref = get_reduced_row_echleon_form_H(H, ffdim=ffdim)
H_st, switches = switch_columns(H_rref, check_standard_form_variance(H_rref))
G = standard_H_to_G(H_st, switches=switches, ffdim=ffdim)
return G