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
|
||||
import numpy as np
|
||||
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
|
||||
#feed() is used to send data to the object
|
||||
@@ -49,10 +52,11 @@ class Chain(CommObject):
|
||||
def clear(self):
|
||||
[i.clear() for i in self.comms]
|
||||
|
||||
#creates inverses for each component and places them in reverse order
|
||||
def getinverse(self):
|
||||
ln = len(self.comms)
|
||||
inv = [None] * ln
|
||||
for i in range(ln)):
|
||||
for i in range(ln):
|
||||
inv[i] = self.comms[ln-i-1]
|
||||
return Chain(inv)
|
||||
|
||||
@@ -65,18 +69,14 @@ class LinearBlockEncoder(CommObject):
|
||||
self.datalen = self.gen.shape[0]
|
||||
self.codelen = self.gen.shape[1]
|
||||
self.buff = Queue()
|
||||
|
||||
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])
|
||||
self.dist = self.distance(self.gen)
|
||||
|
||||
def feed(self, data):
|
||||
self.buff.add(data)
|
||||
out = []
|
||||
while len(self.buff) >= self.datalen:
|
||||
datavect = np.matrix(self.buff.pop(self.datalen))
|
||||
codevect = datavect * self.gen
|
||||
codevect = mul(datavect,self.gen)
|
||||
out.append(codevect.tolist()[0])
|
||||
return out
|
||||
|
||||
@@ -93,6 +93,13 @@ class LinearBlockEncoder(CommObject):
|
||||
def getinverse(self):
|
||||
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
|
||||
def standard(mat):
|
||||
if not isinstance(mat, np.matrix):
|
||||
@@ -135,9 +142,56 @@ class LinearBlockDecoder(CommObject):
|
||||
while len(self.buff) >= self.codelen:
|
||||
code = np.matrix(self.buff.pop(self.codelen)).T
|
||||
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):
|
||||
def __init__(self, paritybits=3):
|
||||
@@ -150,12 +204,12 @@ class Queue:
|
||||
self.data = deque(data)
|
||||
|
||||
#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):
|
||||
return len(self.data)
|
||||
|
||||
def __getiten__(self, key):
|
||||
def __getitem__(self, key):
|
||||
return self.data[key]
|
||||
|
||||
def add(self, data):
|
||||
@@ -194,7 +248,7 @@ def mul(x1, x2):
|
||||
def bininput(x):
|
||||
if isinstance(x, np.matrix):
|
||||
#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!
|
||||
def arreq_in_list(myarr, 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