|
| 1 | +from operator import mul |
| 2 | +from sage.matrix.constructor import matrix |
| 3 | +from sage.functions.other import binomial |
| 4 | +from sage.calculus.var import var |
| 5 | +from sage.misc.functional import symbolic_sum |
| 6 | +from sage.coding.linear_code import AbstractLinearCode, LinearCodeSyndromeDecoder |
| 7 | +from sage.coding.encoder import Encoder |
| 8 | +import sage.combinat as subsets |
| 9 | +from sage.rings.finite_rings.finite_field_base import FiniteField |
| 10 | + |
| 11 | +#to compute the sum of n chose i where i ranges from 0 to k |
| 12 | +def binomialSum(n,k): |
| 13 | + s=1 |
| 14 | + nCi=1 |
| 15 | + for i in range(k): |
| 16 | + nCi=((n-i)*nCi)/(i+1) |
| 17 | + s=nCi+s |
| 18 | + return s |
| 19 | + |
| 20 | +#to use the evaluation of polynomial at the points to obtain the polynomial |
| 21 | +def multivariatePolynomialInterpolation(evaluation, numberOfVariable, order, q, finiteField, _R): |
| 22 | + if numberOfVariable==0 or order==0: |
| 23 | + return evaluation[0] |
| 24 | + xcordinate=finiteField.list() |
| 25 | + nq=q**(numberOfVariable-1) |
| 26 | + d=min(order+1,q) |
| 27 | + evaluation2=[] |
| 28 | + uniPolyRing=PolynomialRing(finiteField,'x') |
| 29 | + for k in range(nq): |
| 30 | + points=[(xcordinate[i], evaluation[k+i*nq]) for i in range(q)] |
| 31 | + polyVector=uniPolyRing.lagrange_polynomial(points).coefficients(sparse=False) |
| 32 | + if len(polyVector)<d: |
| 33 | + #adding zeros to represet a (d-1) degree polynomial |
| 34 | + polyVector=polyVector+[0 for i in range(d-len(polyVector))] |
| 35 | + evaluation2.append(polyVector) |
| 36 | + poly=0 |
| 37 | + z=1 |
| 38 | + x=_R.gen(numberOfVariable-1) |
| 39 | + for k in range(d):#computing the polynomial |
| 40 | + poly=poly+z*multivariatePolynomialInterpolation([evaluation2[i][k] for i in range(nq)], numberOfVariable-1, order-k, q, finiteField, _R) |
| 41 | + z=z*x |
| 42 | + return poly |
| 43 | + |
| 44 | +def ReedMullerCode(finiteField, order, numberOfVariable): |
| 45 | + if (isinstance(finiteField,FiniteField)): |
| 46 | + baseField=finiteField |
| 47 | + q=baseField.cardinality() |
| 48 | + elif (isinstance(finiteField, Integer)): |
| 49 | + baseField=GF(finiteField, 'x') |
| 50 | + q=finiteField |
| 51 | + if q == 2: |
| 52 | + return BinaryReedMullerCode(order, numberOfVariable) |
| 53 | + else: |
| 54 | + return QAryReedMullerCode(baseField, order, numberOfVariable) |
| 55 | + |
| 56 | +class QAryReedMullerCode(AbstractLinearCode): |
| 57 | + _registered_encoders={} |
| 58 | + _registered_decoders={} |
| 59 | + |
| 60 | + def __init__(self, finiteField, order, numberOfVariable): |
| 61 | + #to handle the case when the base field is directly given and input sanitization |
| 62 | + if (isinstance(finiteField,FiniteField)): |
| 63 | + baseField=finiteField |
| 64 | + q=baseField.cardinality() |
| 65 | + elif (isinstance(finiteField, Integer)): |
| 66 | + baseField=GF(finiteField, 'x') |
| 67 | + q=finiteField |
| 68 | + else: |
| 69 | + raise ValueError("Incorrect data-type of input: You must either give the size of the finite field or the finite field itself") |
| 70 | + if not(isinstance(order,Integer)): |
| 71 | + raise ValueError("Incorrect data-type of input: The order of the code must be an integer") |
| 72 | + if not(isinstance(numberOfVariable, Integer)): |
| 73 | + raise ValueError("Incorrect data-type of input: The number of variables must be an integer") |
| 74 | + if (order>=q): |
| 75 | + raise ValueError("The order must be less than %s" % q) |
| 76 | + |
| 77 | + super(QAryReedMullerCode, self).__init__(baseField,q**numberOfVariable,"ReedMullerVectorEncoder","Syndrome") |
| 78 | + self.order=order |
| 79 | + self.numberOfVariable=numberOfVariable |
| 80 | + self.q=q |
| 81 | + self._dimension=binomial(numberOfVariable+order, order) |
| 82 | + |
| 83 | + def _repr_(self): |
| 84 | + return "%s-ary Reed Muller Code of order %s and number of variables %s" % (self.q, self.order, self.numberOfVariable) |
| 85 | + |
| 86 | + def _latex_(self): |
| 87 | + return "%s\textnormal{-ary Reed Muller Code of order} %s \textnormal{and number of variables} %s" % (self.q, self.order, self.numberOfVariable) |
| 88 | + |
| 89 | + def __eq__(self,other): |
| 90 | + return (isinstance(other, QAryReedMullerCode)) and self.q==other.q and self.order==other.order and self.numberOfVariable==other.numberOfVariable |
| 91 | + |
| 92 | +class BinaryReedMullerCode(AbstractLinearCode): |
| 93 | + _registered_encoders={} |
| 94 | + _registered_decoders={} |
| 95 | + |
| 96 | + def __init__(self, order, numberOfVariable): |
| 97 | + #input sanitization |
| 98 | + if not(isinstance(order,Integer)): |
| 99 | + raise ValueError("Incorrect data-type of input: The order of the code must be an integer") |
| 100 | + if not(isinstance(numberOfVariable, Integer)): |
| 101 | + raise ValueError("Incorrect data-type of input: The number of variables must be an integer") |
| 102 | + if (numberOfVariable<order): |
| 103 | + raise ValueError("The order must be less than %s" % numberOfVariable) |
| 104 | + |
| 105 | + super(BinaryReedMullerCode, self).__init__(GF(2), 2**numberOfVariable,"ReedMullerVectorEncoder","Syndrome") |
| 106 | + self.order=order |
| 107 | + self.numberOfVariable=numberOfVariable |
| 108 | + self.q=2 |
| 109 | + self._dimension=binomialSum(numberOfVariable,order) |
| 110 | + |
| 111 | + def _repr_(self): |
| 112 | + return "Binary Reed Muller Code of order %s and number of variables %s" % (self.order, self.numberOfVariable) |
| 113 | + |
| 114 | + def _latex_(self): |
| 115 | + return "\textnormal{Binary Reed Muller Code of order} %s \textnormal{and number of variables} %s" % (self.q, self.order, self.numberOfVariable) |
| 116 | + |
| 117 | + def __eq__(self,other): |
| 118 | + return (isinstance(other, BinaryReedMullerCode)) and self.order==other.order and self.numberOfVariable==other.numberOfVariable |
| 119 | + |
| 120 | +class ReedMullerVectorEncoder(Encoder): |
| 121 | + def __init__(self, code): |
| 122 | + super(ReedMullerVectorEncoder, self).__init__(code) |
| 123 | + |
| 124 | + def _repr_(self): |
| 125 | + return "Evaluation polynomial-style encoder for %s" % self.code() |
| 126 | + |
| 127 | + def _latex_(self): |
| 128 | + return "\textnormal{Evaluation polynomial-style encoder for }%s" % self.code()._latex_() |
| 129 | + |
| 130 | + def __eq__(self,other): |
| 131 | + return (isinstance(other, ReedMullerVectorEncoder)) and self.code==other.code |
| 132 | + |
| 133 | + def generator_matrix(self): |
| 134 | + C=self.code() |
| 135 | + baseField=C.base_field() |
| 136 | + order=C.order |
| 137 | + numberOfVariable=C.numberOfVariable |
| 138 | + q=C.q |
| 139 | + baseFieldTuple=Tuples(baseField.list(),numberOfVariable) |
| 140 | + exponents=Subsets(range(numberOfVariable)*(q-1), submultiset=True)[0:C.dimension()] |
| 141 | + return Matrix(baseField, [[reduce(mul, [x[i] for i in exponent],1) for x in baseFieldTuple] for exponent in exponents]) |
| 142 | + |
| 143 | +class ReedMullerPolynomialEncoder(Encoder): |
| 144 | + def __init__(self, code): |
| 145 | + super(ReedMullerPolynomialEncoder, self).__init__(code) |
| 146 | + self._R=PolynomialRing(self.code().base_field(),self.code().numberOfVariable,"x") |
| 147 | + |
| 148 | + def _repr_(self): |
| 149 | + return "Evaluation polynomial-style encoder for %s" % self.code() |
| 150 | + |
| 151 | + def _latex_(self): |
| 152 | + return "\textnormal{Evaluation polynomial-style encoder for }%s" % self.code()._latex_() |
| 153 | + |
| 154 | + def __eq__(self,other): |
| 155 | + return (isinstance(other, ReedMullerPolynomialEncoder)) and self.code==other.code |
| 156 | + |
| 157 | + def encode(self, p): |
| 158 | + M = self.message_space() |
| 159 | + if p not in M: |
| 160 | + raise ValueError("The value to encode must be in %s" % M) |
| 161 | + C=self.code() |
| 162 | + if p.degree() > C.order: |
| 163 | + raise ValueError("The polynomial to encode must have degree at most %s" % C.order) |
| 164 | + baseFieldTuple = Tuples(C.base_field().list(), C.numberOfVariable) |
| 165 | + return vector(C.base_ring(), [p(x) for x in baseFieldTuple]) |
| 166 | + |
| 167 | + def unencode_nocheck(self, c): |
| 168 | + return multivariatePolynomialInterpolation(c, self.code().numberOfVariable, self.code().order, self.code().q, self.code().base_field(), self._R) |
| 169 | + |
| 170 | + |
| 171 | + def message_space(self): |
| 172 | + return self._R |
| 173 | + |
| 174 | +QAryReedMullerCode._registered_encoders["ReedMullerVectorEncoder"] = ReedMullerVectorEncoder |
| 175 | +QAryReedMullerCode._registered_encoders["ReedMullerPolynomialEncoder"] = ReedMullerPolynomialEncoder |
| 176 | + |
| 177 | +QAryReedMullerCode._registered_decoders["Syndrome"] = LinearCodeSyndromeDecoder |
| 178 | + |
| 179 | +BinaryReedMullerCode._registered_encoders["ReedMullerVectorEncoder"] = ReedMullerVectorEncoder |
| 180 | +BinaryReedMullerCode._registered_encoders["ReedMullerPolynomialEncoder"] = ReedMullerPolynomialEncoder |
| 181 | + |
| 182 | +BinaryReedMullerCode._registered_decoders["Syndrome"] = LinearCodeSyndromeDecoder |
0 commit comments