mirror of
https://github.com/Ikatono/CommTools.git
synced 2025-10-28 20:45:33 -05:00
Various changes
This commit is contained in:
94
commtools.py
94
commtools.py
@@ -2,6 +2,9 @@ from collections import deque
|
|||||||
from collections import Iterable
|
from collections import Iterable
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from math import log2
|
from math import log2
|
||||||
|
#import sympy as sp
|
||||||
|
from sympy.polys.domains import ZZ
|
||||||
|
from sympy.polys.galoistools import gf_factor
|
||||||
|
|
||||||
#basic structure of objects used in this package
|
#basic structure of objects used in this package
|
||||||
#feed() is used to send data to the object
|
#feed() is used to send data to the object
|
||||||
@@ -49,10 +52,11 @@ class Chain(CommObject):
|
|||||||
def clear(self):
|
def clear(self):
|
||||||
[i.clear() for i in self.comms]
|
[i.clear() for i in self.comms]
|
||||||
|
|
||||||
|
#creates inverses for each component and places them in reverse order
|
||||||
def getinverse(self):
|
def getinverse(self):
|
||||||
ln = len(self.comms)
|
ln = len(self.comms)
|
||||||
inv = [None] * ln
|
inv = [None] * ln
|
||||||
for i in range(ln)):
|
for i in range(ln):
|
||||||
inv[i] = self.comms[ln-i-1]
|
inv[i] = self.comms[ln-i-1]
|
||||||
return Chain(inv)
|
return Chain(inv)
|
||||||
|
|
||||||
@@ -65,18 +69,14 @@ class LinearBlockEncoder(CommObject):
|
|||||||
self.datalen = self.gen.shape[0]
|
self.datalen = self.gen.shape[0]
|
||||||
self.codelen = self.gen.shape[1]
|
self.codelen = self.gen.shape[1]
|
||||||
self.buff = Queue()
|
self.buff = Queue()
|
||||||
|
self.dist = self.distance(self.gen)
|
||||||
def distance(self):
|
|
||||||
datawords = [tobin(i,self.datalen) for i in range(2**self.datalen)]
|
|
||||||
codewords = [mul(i.T, self.gen) for i in datawords]
|
|
||||||
return min([int(sum(i.T)) for i in codewords if int(sum(i.T))>0])
|
|
||||||
|
|
||||||
def feed(self, data):
|
def feed(self, data):
|
||||||
self.buff.add(data)
|
self.buff.add(data)
|
||||||
out = []
|
out = []
|
||||||
while len(self.buff) >= self.datalen:
|
while len(self.buff) >= self.datalen:
|
||||||
datavect = np.matrix(self.buff.pop(self.datalen))
|
datavect = np.matrix(self.buff.pop(self.datalen))
|
||||||
codevect = datavect * self.gen
|
codevect = mul(datavect,self.gen)
|
||||||
out.append(codevect.tolist()[0])
|
out.append(codevect.tolist()[0])
|
||||||
return out
|
return out
|
||||||
|
|
||||||
@@ -93,6 +93,13 @@ class LinearBlockEncoder(CommObject):
|
|||||||
def getinverse(self):
|
def getinverse(self):
|
||||||
return LinearBlockDecoder(self.checkmat())
|
return LinearBlockDecoder(self.checkmat())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def distance(gen):
|
||||||
|
datalen = gen.shape[0]
|
||||||
|
datawords = [tobin(i,datalen) for i in range(2**datalen)]
|
||||||
|
codewords = [mul(i.T, gen) for i in datawords]
|
||||||
|
return min(int(sum(i.T)) for i in codewords if int(sum(i.T))>0)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def standard(mat):
|
def standard(mat):
|
||||||
if not isinstance(mat, np.matrix):
|
if not isinstance(mat, np.matrix):
|
||||||
@@ -135,9 +142,56 @@ class LinearBlockDecoder(CommObject):
|
|||||||
while len(self.buff) >= self.codelen:
|
while len(self.buff) >= self.codelen:
|
||||||
code = np.matrix(self.buff.pop(self.codelen)).T
|
code = np.matrix(self.buff.pop(self.codelen)).T
|
||||||
synd = self.chk * code
|
synd = self.chk * code
|
||||||
data =
|
#data =
|
||||||
|
#creates a cyclic encoder, a type of linear block code
|
||||||
|
#can be used in two different ways:
|
||||||
|
#CyclicEncoder(n, k) creates an [n,k] code from a code polynomial of max distance
|
||||||
|
#raises a ValueError if no such polynomial exists
|
||||||
|
#CyclicEncoder(poly [, n]) creates a code using poly as the code polynomial
|
||||||
|
#poly is a list of 1 and 0, where poly[i] is the coefficient of X**i
|
||||||
|
#if n is not defined then it is infered as len(poly)-1
|
||||||
|
#raises a ValueError if poly is invalid for this order of code
|
||||||
|
class CyclicEncoder(LinearBlockEncoder):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
#TODO validate inputs better
|
||||||
|
if 'standard' in kwargs:
|
||||||
|
tostand = kwargs['standard']
|
||||||
|
else:
|
||||||
|
tostand = True
|
||||||
|
if isinstance(args[0], list):
|
||||||
|
#TODO implement polynomial loading
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
n, k = args
|
||||||
|
outerpoly = [1] + [0]*(n-1) + [1]
|
||||||
|
factors = gf_factor(ZZ.map(outerpoly), 2, ZZ)
|
||||||
|
doms = [len(factor[0])-1 for factor in factors[1]]
|
||||||
|
#print(factors)
|
||||||
|
#print(doms)
|
||||||
|
if n-k not in doms:
|
||||||
|
raise ValueError('there is no cyclic code with these values')
|
||||||
|
#list of all factors of the correct order
|
||||||
|
facts = [i for i, x in enumerate(doms) if x == n-k]
|
||||||
|
facts = [factors[1][i][0] for i in facts]
|
||||||
|
dists = [0] * len(facts)
|
||||||
|
gens = [None] * len(facts)
|
||||||
|
for i in range(len(facts)):
|
||||||
|
gen = np.matrix(np.zeros((k,n)))
|
||||||
|
l = len(facts[i])
|
||||||
|
for j in range(k):
|
||||||
|
poly = np.matrix([0]*j + facts[i][::-1] + [0]*(n-j-k))
|
||||||
|
gen[j] = poly
|
||||||
|
gens[i] = gen
|
||||||
|
dists[i] = self.distance(gen)
|
||||||
|
#chooses arbitrary factor of maximum distance
|
||||||
|
choice = dists.index(max(dists))
|
||||||
|
self.poly = facts[choice]
|
||||||
|
self.dist = dists[choice]
|
||||||
|
self.gen = gens[choice]
|
||||||
|
self.buff = Queue()
|
||||||
|
self.datalen = self.gen.shape[0]
|
||||||
|
self.codelen = self.gen.shape[1]
|
||||||
|
|
||||||
|
|
||||||
class HammingEncoder(LinearBlockEncoder):
|
class HammingEncoder(LinearBlockEncoder):
|
||||||
def __init__(self, paritybits=3):
|
def __init__(self, paritybits=3):
|
||||||
@@ -150,12 +204,12 @@ class Queue:
|
|||||||
self.data = deque(data)
|
self.data = deque(data)
|
||||||
|
|
||||||
#TODO add __blah__ functions
|
#TODO add __blah__ functions
|
||||||
#or don't, this shouldn't be used outisde this module
|
#or don't, this shouldn't be used outside this module
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.data)
|
return len(self.data)
|
||||||
|
|
||||||
def __getiten__(self, key):
|
def __getitem__(self, key):
|
||||||
return self.data[key]
|
return self.data[key]
|
||||||
|
|
||||||
def add(self, data):
|
def add(self, data):
|
||||||
@@ -194,7 +248,7 @@ def mul(x1, x2):
|
|||||||
def bininput(x):
|
def bininput(x):
|
||||||
if isinstance(x, np.matrix):
|
if isinstance(x, np.matrix):
|
||||||
#TODO make this less bad
|
#TODO make this less bad
|
||||||
return np.matrix([[1 if elem else -1 for elem in row] for row in x])
|
return np.matrix([[1 if elem else 0 for elem in row] for row in x])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -220,3 +274,17 @@ def tobin(num, bits=0):
|
|||||||
#thanks Sven Marnach!
|
#thanks Sven Marnach!
|
||||||
def arreq_in_list(myarr, list_arrays):
|
def arreq_in_list(myarr, list_arrays):
|
||||||
return any((myarr == x).all() for x in list_arrays)
|
return any((myarr == x).all() for x in list_arrays)
|
||||||
|
|
||||||
|
#adds row a to row b, mod 2
|
||||||
|
def rowadd(mat, a, b):
|
||||||
|
mat[a] += mat[b]
|
||||||
|
mat %= 2
|
||||||
|
|
||||||
|
#TODO finish this
|
||||||
|
#left=True if identity matrix is on the left side
|
||||||
|
def standard(mat, left):
|
||||||
|
k = mat.shape[1]
|
||||||
|
for i in mat.T[:k]:
|
||||||
|
if not i.any():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user