def nonsingular(size): """Return non-singular binary square matrix. Function uses algorithm of Dana Randall https://www.researchgate.net/publication/2729950_Efficient_Generation_of_Random_Nonsingular_Matrices """ size = max(0, size) matr_a_rows = [vector.Vector(0, size) for i in range(size)] matr_t_rows = {} restricted = [] for i in range(size): vec_v = vector.Vector(randint(1, (1 << (size - i)) - 1), size - i) for j, bit in enumerate(vec_v): if bit: val_r = [k for k in range(size) if k not in restricted][j] break matr_a_rows[i][val_r] = 1 # There is mistake in the paper of Dana Randall: this code was missing # in her paper for k in range(i + 1, size): matr_a_rows[k][val_r] = randint(0, 1) # -------------------------------------------------------------------- matr_t_rows[val_r] = vector.Vector(0, size) for j, k in enumerate(j for j in range(size) if j not in restricted): matr_t_rows[val_r][k] = vec_v[j] restricted.append(val_r) return Matrix((row.value for row in matr_a_rows), size) * Matrix( (matr_t_rows[i].value for i in sorted(matr_t_rows)), size)
def test_support(self): """Test evaluation ot vector's support.""" vec1 = vector.Vector(0b10011, 5) vec2 = vector.Vector(0b01100, 5) vec3 = vector.Vector(0b00100, 5) vec4 = vector.Vector(0b00000, 5) vec5 = vector.Vector() self.assertEqual(vec1.support, [0, 3, 4]) self.assertEqual(vec2.support, [1, 2]) self.assertEqual(vec3.support, [2]) self.assertEqual(vec4.support, []) self.assertEqual(vec5.support, []) self.assertEqual(list(vec1.iter_support()), [0, 3, 4]) self.assertEqual(list(vec2.iter_support()), [1, 2]) self.assertEqual(list(vec3.iter_support()), [2]) self.assertEqual(list(vec4.iter_support()), []) self.assertEqual(list(vec5.iter_support()), []) self.assertEqual(vec1.support_supplement, [1, 2]) self.assertEqual(vec2.support_supplement, [0, 3, 4]) self.assertEqual(vec3.support_supplement, [0, 1, 3, 4]) self.assertEqual(vec4.support_supplement, [0, 1, 2, 3, 4]) self.assertEqual(vec5.support_supplement, []) self.assertEqual(list(vec1.iter_support_supplement()), [1, 2]) self.assertEqual(list(vec2.iter_support_supplement()), [0, 3, 4]) self.assertEqual(list(vec3.iter_support_supplement()), [0, 1, 3, 4]) self.assertEqual(list(vec4.iter_support_supplement()), [0, 1, 2, 3, 4]) self.assertEqual(list(vec5.iter_support_supplement()), [])
def test_bool(self): """Test comparison with None.""" vec1 = vector.Vector(0b10011, 5) vec2 = vector.Vector(0b00000, 5) vec3 = vector.Vector() self.assertTrue(vec1) self.assertTrue(vec2) self.assertFalse(vec3)
def test_not_eq(self): """Test not equality of vectors.""" vec1 = vector.Vector(0b01101, 5) vec2 = vector.Vector() vec3 = vector.Vector(0b01001, 5) self.assertNotEqual(vec1, vec3) self.assertNotEqual(vec1, vec2) self.assertNotEqual(vec1, vec3)
def test_set_size_and_resize(self): """Test resizing of vector.""" vec1 = vector.Vector(0b10011, 5) vec2 = vector.Vector(0b011, 3) vec3 = vector.Vector(0b0010011, 7) self.assertEqual(vec2, vec1.copy().set_length(3)) self.assertEqual(vec3, vec1.copy().set_length(7)) self.assertEqual(vec2, vec1.copy().resize(-2)) self.assertEqual(vec3, vec1.copy().resize(2))
def test_concatenate(self): """Test concatenation of vectors.""" vec1 = vector.Vector(0b10011, 5) vec2 = vector.Vector(0b00000, 5) vec3 = vector.Vector() self.assertEqual(vec1.concatenate(vec2).value, 0b1001100000) self.assertEqual(vec1.concatenate(vec3).value, 0b1001100000) self.assertEqual( vector.concatenate(vec1, vec1).value, 0b10011000001001100000) self.assertEqual(vector.concatenate(vec3, vec1).value, 0b1001100000)
def test_add(self): """Test v1 + v2.""" vec1 = vector.Vector(0b01101, 5) vec2 = vector.Vector() vec3 = vector.Vector(0b00101, 5) summ = vector.Vector(0b01000, 5) self.assertEqual(vec1 + vec3, summ) self.assertEqual(vec1 + vec2, vec1) vec1 += vec3 self.assertEqual(vec1, summ)
def test_or(self): """Test v1 | v2.""" vec1 = vector.Vector(0b01101, 5) vec2 = vector.Vector() vec3 = vector.Vector(0b00101, 5) vec_or = vector.Vector(0b01101, 5) self.assertEqual(vec1 | vec3, vec_or) self.assertEqual(vec1 | vec2, vec1) vec1 |= vec3 self.assertEqual(vec1, vec_or)
def test_bitwise_not(self): """Test ~v.""" vec1 = vector.Vector(0b01101, 5) vec2 = vector.Vector() vec3 = vector.Vector(0b00000, 5) self.assertEqual(vec1.bitwise_not().value, 0b10010) self.assertEqual(vec2.bitwise_not().value, 0) self.assertEqual(vec3.bitwise_not().value, 0b11111) self.assertEqual(vector.bitwise_not(vec1).value, 0b01101) self.assertEqual(vector.bitwise_not(vec2).value, 0) self.assertEqual(vector.bitwise_not(vec3).value, 0)
def test_and(self): """Test v1 & v2.""" vec1 = vector.Vector(0b01101, 5) vec2 = vector.Vector() vec3 = vector.Vector(0b00101, 5) zero = vector.Vector(0, 5) mul = vector.Vector(0b00101, 5) self.assertEqual(vec1 & vec3, mul) self.assertEqual(vec1 & vec2, zero) vec1 &= vec3 self.assertEqual(vec1, mul)
def test_scalar_product(self): """Test scalar product of vectors.""" vec1 = vector.Vector(0b10011, 5) vec2 = vector.Vector(0b00000, 5) vec3 = vector.Vector() vec4 = vector.Vector(0b00011, 5) self.assertEqual(vector.scalar_product(vec1, vec1), 1) self.assertEqual(vector.scalar_product(vec1, vec2), 0) self.assertEqual(vector.scalar_product(vec1, vec4), 0) self.assertEqual(vector.scalar_product(vec1, vec3), 0) self.assertEqual(vector.scalar_product(vec3, vec3), 0) self.assertEqual(vector.scalar_product(vec4, vec3), 0)
def __make_row_from_value(self, value): """Make row from value of various type.""" try: value = value.value new_row = vector.Vector(value, self._ncolumns) except AttributeError: if isinstance(value, int): new_row = vector.Vector(value, self._ncolumns) elif isinstance(value, str): new_row = vector.from_string(value) new_row.set_length(self._ncolumns) else: new_row = vector.from_iterable(value) new_row.set_length(self._ncolumns) return new_row
def test_shifting(self): """Test vector shift operators.""" vec1 = vector.Vector(0b10011, 5) vec2 = vector.Vector(0b01100, 5) vec3 = vector.Vector(0b00100, 5) vec4 = vector.Vector(0b00001, 5) vec_empty = vector.Vector() self.assertEqual(vec2, vec1 << 2) self.assertEqual(vec3, vec1 >> 2) vec1 <<= 2 self.assertEqual(vec2, vec1) vec1 >>= 3 self.assertEqual(vec4, vec1) self.assertEqual(vec_empty, vec_empty << 10) self.assertEqual(vec_empty, vec_empty >> 10)
def test_hamming_weight(self): """Test evaluation ot Hamming weight.""" vec1 = vector.Vector(0b10011, 5) vec2 = vector.Vector(0b01100, 5) vec3 = vector.Vector(0b00100, 5) vec4 = vector.Vector(0b00000, 5) vec5 = vector.Vector() self.assertEqual(vec1.hamming_weight, 3) self.assertEqual(vec2.hamming_weight, 2) self.assertEqual(vec3.hamming_weight, 1) self.assertEqual(vec4.hamming_weight, 0) self.assertEqual(vec5.hamming_weight, 0) self.assertEqual(vector.hamming_distance(vec1, vec2), 5) self.assertEqual(vector.hamming_distance(vec1, vec3), 4) self.assertEqual(vector.hamming_distance(vec3, vec4), 1) self.assertEqual(vector.hamming_distance(vec2, vec3), 1) self.assertEqual(vector.hamming_distance(vec2, vec5), 2)
def test_getitem(self): """Test to get item and set item.""" vec = vector.Vector(0b0111100110, 10) self.assertEqual(vec[2], 1) self.assertEqual(vec[0], 0) self.assertEqual(vec[-1], 0) self.assertEqual(vec[-8], 1) self.assertEqual(vec[-5], 0) self.assertEqual(int(vec[1:6:2]), 0b110)
def generator(param_r, param_m): """Make Reed-Muller RM(r,m) generator matrix.""" param_m = max(0, param_m) monoms = [] for i, j in ((1 << (param_m - p - 1), 1 << p) for p in range(param_m)): monoms.append( vector.Vector(int(('0' * i + '1' * i) * j, 2), 1 << param_m)) gen_matrix = [vector.Vector(int('1' * (1 << param_m), 2), 1 << param_m)] for i in range(1, param_r + 1): if i == 1: curr_layer = [(i, monoms[i]) for i in range(len(monoms))] gen_matrix += [monoms[i] for i in range(len(monoms))] continue next_layer = [] for max_monom, row in curr_layer: for j in range(max_monom + 1, param_m): next_layer.append((j, row * monoms[j])) gen_matrix.append(next_layer[-1][1]) curr_layer = next_layer return matrix.Matrix((row.value for row in gen_matrix), 1 << param_m)
def test_setitem_negative_positions(self): """Test to set item for negative positions.""" vec = vector.Vector(0b0111100110, 10) vec[-1] = 1 vec[-2] = '' vec[-3] = '0' vec[-4] = '1' vec[-5] = 0 vec[-6] = False vec[-7] = True vec[-8] = 'UUU' vec[-9] = -9 self.assertEqual(vec.value, 0b0111001001)
def solve(self, vect_b): """Solve linear equation Ax^T = vect_b^T.""" if not vect_b.value: # vect_b == 0 return (self.orthogonal, vector.Vector(0, self.ncolumns)) extend_mat = concatenate(self, Matrix(vect_b, 1)) orthogonal = extend_mat.orthogonal fundamental = Matrix( (row.value >> 1 for row in orthogonal if not row[-1]), self.ncolumns) vec_solve = [row for row in orthogonal if row[-1]] if vec_solve: return (fundamental, (vec_solve[0] >> 1).set_length(self.ncolumns)) return None, None
def test_setitem_positive_positions(self): """Test to set item for positive positions.""" vec = vector.Vector(0b0111100110, 10) vec[0] = 1 vec[1] = 1 vec[2] = '' vec[3] = '0' vec[4] = '1' vec[5] = 0 vec[6] = False vec[7] = True vec[8] = 'UUU' vec[9] = -9 self.assertEqual(vec.value, 0b1100100111)
def concatenate(self, other, by_rows=False): """Concatenate two matrices.""" if by_rows: self._ncolumns = max(self.ncolumns, other.ncolumns) self._matrix = tuple( vector.Vector(row.value, self._ncolumns) for row in self._matrix + tuple(other)) else: self._matrix = tuple( row_self.concatenate(row_other) for row_self, row_other in zip(self, other)) self._ncolumns = self.ncolumns + other.ncolumns if len(self._matrix) == 0: return self.__class__() return self
def __mul__(self, other): """Multiply of two matrices. return self * other """ if self.ncolumns != other.nrows: raise ValueError('wrong shapes of matrices: the number of ' 'columns of the first matrix must be equal the ' 'number of rows of other matrix, ' 'but {} != {}'.format(self.ncolumns, other.nrows)) result = [] for row in self: sum_row = vector.Vector(0, other.ncolumns) for vec in (other_row for i, other_row in enumerate(other) if row[i]): sum_row += vec result.append(sum_row.value) return self.__class__(result, other.ncolumns)
def __init__(self, value=None, ncolumns=0): """Create new matrix. :param: value - any iterable of integers :param: ncolumns - number of columns in the matrix """ if not isinstance(ncolumns, int): raise TypeError('expected `ncolumns` is integer, but ' 'got {}'.format(type(ncolumns))) if ncolumns < 0: raise ValueError('expected `ncolumns` is not less then 0, but ' '{} < 0'.format(ncolumns)) self._ncolumns = ncolumns if not value: value = [] if self._ncolumns: self._matrix = tuple(vector.Vector(i, ncolumns) for i in value) else: self._matrix = tuple() if not self._matrix: self._ncolumns = 0
def test_default_to_str_empty(self): """Test representation as string.""" vec = vector.Vector() self.assertEqual(str(vec), '')
def test_function_to_str(self): """Test general function to_str().""" vec = vector.Vector(0b0111100110, 10) self.assertEqual(vec.to_str(), str(vec)) vec = vector.Vector() self.assertEqual(vec.to_str(), str(vec))
def test_default_to_str(self): """Test representation as string.""" vec = vector.Vector(0b0111100110, 10) self.assertEqual(str(vec), '0111100110')
def test_get_int_value_default(self): """Test to get value and represent as integer of default Vector.""" vec = vector.Vector() self.assertEqual(int(vec), vec.value)
def test_function_to_str_with_fillers(self): """Test representation as string using various fillers.""" vec = vector.Vector(0b0111100110, 10) self.assertEqual(vec.to_str(zerofiller='-', onefiller='$'), '-$$$$--$$-')
def test_repr_function_for_empty_vector(self): """Test repr function for empty Vector object.""" self.assertEqual(repr(vector.Vector()), 'Vector(len=0, [])')
def test_repr_function(self): """Test repr function for Vector object.""" self.assertEqual(repr(vector.Vector(0b0111100110, 10)), 'Vector(len=10, [0111100110])')
def test_to_latex_str(self): """Test function to_latex_str().""" vec1 = vector.Vector(0b0111100110, 10) vec2 = vector.Vector() self.assertEqual(vec1.to_latex_str(), '0&1&1&1&1&0&0&1&1&0') self.assertEqual(vec2.to_latex_str(), '')