From 269f696d4bed7f76d61ef132ebae6360df4e0caa Mon Sep 17 00:00:00 2001 From: Cameron Date: Wed, 15 Nov 2017 02:50:25 -0500 Subject: [PATCH] Various changes --- commtools.py | 94 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 13 deletions(-) diff --git a/commtools.py b/commtools.py index f4d4946..92b7777 100644 --- a/commtools.py +++ b/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 +