Various changes

This commit is contained in:
2017-11-15 02:50:25 -05:00
parent 1db1aa46a0
commit 269f696d4b

View File

@@ -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