# -*- coding: utf-8 -*- """tropic.ipynb Automatically generated by Colab. Original file is located at https://colab.research.google.com/drive/14lR3A29PgCuP9jUS9quiNFYPcYhZvxLi """ class TropicZ(object): def __init__(self, infty = 1000, add_op = 'max'): self.__infty = infty self._posinf = infty self._neginf = -infty self.add_op = max if add_op == 'min': self.add_op = min @property def neginf(self): return TropicZ.TropicElement(self, self._neginf) @property def posinf(self): return TropicZ.TropicElement(self, self._posinf) def elem(self, val = 0): ''' Формирует тропический элемента из целого числа val ''' return TropicZ.TropicElement(self, val) class TropicElement(object): def __init__(self, outer_instance, val = 0): self.__outer_instance = outer_instance self._val = self.bound(val) def bound(self, val = 0): neginf = self.__outer_instance._neginf posinf = self.__outer_instance._posinf return min(max(int(val), neginf), posinf) def __repr__(self): return str(self) def __str__(self): return str(self._val) def __iter__(self): return self.entries.__iter__() def add(self, val): ''' Тропическое сложение текущего элемента с значением val ''' if isinstance(val, TropicZ.TropicElement): result = val._val else: result = int(val) op = self.__outer_instance.add_op result = op(self._val, result) return TropicZ.TropicElement(self.__outer_instance, result) def __add__(self, val): return self.add(val) def __iadd__(self, val): self._val = self.add(val)._val return self def __neg__(self): result = self.bound(-self._val) return TropicZ.TropicElement(self.__outer_instance, result) def mult(self, val): ''' Тропическое умножение текущего элемента на val ''' if isinstance(val, TropicZ.TropicElement): result = val._val else: result = int(val) result = self._val + result return TropicZ.TropicElement(self.__outer_instance, result) def __mul__(self, val): return self.mult(val) def __imul__(self, val): self._val = self.mult(val)._val return self def div(self, val): ''' Тропическое деление текущего элемента на val ''' if isinstance(val, TropicZ.TropicElement): result = val._val else: result = int(val) result = self._val - result return TropicZ.TropicElement(self.__outer_instance, result) def __truediv__(self, val): return self.div(val) def __floordiv__(self, val): return self.div(val) TZ = TropicZ(1000, 'max') TZmin = TropicZ(1000, 'min') TZmax = TropicZ(1000, 'max') a = TZ.elem(5) b = TZ.elem(6) stroka = TropicZ.TropicElement.__repr__(a) print(stroka) print(int(stroka)+5) print(-a) print(a * b) print(a + b) L = [TZ.elem(i) for i in range(7)] print(L) print(sum(L, TZ.neginf)) print(a * TZ.neginf) import math class TropicalMatrix: def __init__(self, entries): self.entries = entries def __str__(self): return str(self.entries) def get_entry(self, i, j): return self.entries[i][j] def dual(self, dual): n = 2 new_matrix = [[0, 0], [0, 0]] for i in range(n): for j in range(n): new_matrix[i][j] = dual.elem(self[i][j]) return TropicalMatrix(new_matrix) def add_tropical_matrix(self, matrix, dual): n = 2 new_matrix = [[0, 0], [0, 0]] self = TropicalMatrix.dual(self, dual) matrix = TropicalMatrix.dual(matrix, dual) for i in range(n): for j in range(n): new_matrix[i][j] = self.get_entry(i, j) + matrix.get_entry(i, j) return TropicalMatrix(new_matrix) def mult_scalar(self, scalar, dual): n = 2 new_matrix = [[0, 0], [0, 0]] self = TropicalMatrix.dual(self, dual) for i in range(n): for j in range(n): new_matrix[i][j] = self.get_entry(i, j) * scalar return TropicalMatrix(new_matrix) def mult_tropical_matrix(self, matrix, dual): n = 2 new_matrix = [[0, 0], [0, 0]] self = TropicalMatrix.dual(self, dual) matrix = TropicalMatrix.dual(matrix, dual) for i in range(n): for j in range(n): sum_list = [] for k in range(n): sum_list.append(self.get_entry(i, k) * matrix.get_entry(k, j)) new_matrix[i][j] = sum_list[0] + sum_list[1] return TropicalMatrix(new_matrix) def get_dimension(self): return len(self.entries) def __iter__(self): # метод для превращения тропической матрицы в список return self.entries.__iter__() if __name__ == "__main__": M = [[-1000, 10], [5, 3]] N = [[3, 6], [15, 1000]] A = [[5, -1000], [-1000, 5]] B = [[2, -1000], [-1000, 2]] p = TropicalMatrix.add_tropical_matrix(M, A, TZmax) t = TropicalMatrix.mult_tropical_matrix(N, N, TZmin) q = TropicalMatrix.add_tropical_matrix(M, B, TZmax) r = TropicalMatrix.mult_scalar(N, 3, TZmin) print('p(x) =', p) print('t(x) =', t) print('q(x) =', q) print('r(x) =', r) import math import random import numpy as np class TropicalMatrix_without_dual: def __init__(self, entries): self.entries = entries def __str__(self): return str(self.entries) def add_tropical_matrix_without_dual(self, matrix): n = 2 new_matrix = [[0, 0], [0, 0]] for i in range(n): for j in range(n): new_matrix[i][j] = self.get_entry(i, j) + matrix.get_entry(i, j) return TropicalMatrix_without_dual(new_matrix) def mult_tropical_matrix_without_dual(self, matrix): n = 2 new_matrix = [[0, 0], [0, 0]] for i in range(n): for j in range(n): sum_list = [] for k in range(n): sum_list.append(self.get_entry(i, k) * matrix.get_entry(k, j)) new_matrix[i][j] = sum_list[0] + sum_list[1] return TropicalMatrix(new_matrix) def get_entry(self, i, j): return self.entries[i][j] def __iter__(self): # метод для превращения тропической матрицы в список return self.entries.__iter__() if __name__ == "__main__": M = TropicalMatrix.dual([[-1000, 10], [5, 3]], TZmax) N = TropicalMatrix.dual([[3, 6], [15, 1000]], TZmin) l = TropicalMatrix_without_dual.add_tropical_matrix_without_dual(M, N) m = TropicalMatrix_without_dual.mult_tropical_matrix_without_dual(M, N) print(m) def convert(matrix): s = list(matrix) for i in range(2): for j in range(2): s[i][j] = int(TropicZ.TropicElement.__repr__(s[i][j])) return s def generate_random_matrix(n, min_elem, max_elem): new_matrix = [[0, 0], [0, 0]] for i in range(n): for j in range(n): new_matrix[i][j] = random.randint(min_elem, max_elem) return new_matrix def generate_random_tropical_poly(max_degree, min_coefficient, max_coefficient): """ Генерирует случайный (не константу) тропический многочлен с точностью до заданной степени. """ coefficients = [] for d in range(0, random.randint(1, max_degree) + 1): coefficients.append(random.randint(min_coefficient, max_coefficient)) return coefficients def MatrixMul(a, n): if (n <= 1): return a else: return TropicalMatrix_without_dual.mult_tropical_matrix_without_dual(MatrixMul(a, n-1), a) def evaluate_polynomial(tropical_matrix, coefficient_list, dual): """ Вычисляет многочлен (списком), заданный тропической матрицей. """ identity_matrix_Zmax = [[0, -1000], [-1000, 0]] identity_matrix_Zmin = [[0, 1000], [1000, 0]] null_matrix_Zmax = [[-1000, -1000], [-1000, -1000]] null_matrix_Zmin = [[1000, 1000], [1000, 1000]] sum_list = [] # свободный член if coefficient_list[0] != 0: if dual == TZmin: sum_list.append(TropicalMatrix.mult_scalar(identity_matrix_Zmin, coefficient_list[0], dual)) else: sum_list.append(TropicalMatrix.mult_scalar(identity_matrix_Zmax, coefficient_list[0], dual)) if coefficient_list[0] == 0: if dual == TZmin: sum_list.append(TropicalMatrix.dual(null_matrix_Zmin, dual)) else: sum_list.append(TropicalMatrix.dual(null_matrix_Zmax, dual)) # для многочлена первой степени if (coefficient_list[1] != 0) and (coefficient_list[1] != 1): sum_list.append(TropicalMatrix.mult_scalar(tropical_matrix, coefficient_list[1], dual)) if coefficient_list[1] == 1: sum_list.append(TropicalMatrix.dual(tropical_matrix, dual)) if coefficient_list[1] == 0: if dual == TZmin: sum_list.append(TropicalMatrix.dual(null_matrix_Zmin, dual)) else: sum_list.append(TropicalMatrix.dual(null_matrix_Zmax, dual)) # для многочлена второй степени и выше for i in range(2, len(coefficient_list)): sum_list.append(TropicalMatrix.dual(tropical_matrix, dual)) sum_list[i] = MatrixMul(sum_list[i], i) if (coefficient_list[i] != 1) and (coefficient_list[i] != 0): sum_list[i] = TropicalMatrix.mult_scalar(convert(sum_list[i]), coefficient_list[i], dual) if coefficient_list[i] == 0: if dual == TZmin: sum_list.append(TropicalMatrix.dual(null_matrix_Zmin, dual)) else: sum_list.append(TropicalMatrix.dual(null_matrix_Zmax, dual)) new_matrix = sum_list[0] # складываем все матрицы в sum_list for matrix in sum_list: new_matrix = TropicalMatrix_without_dual.add_tropical_matrix_without_dual(new_matrix, matrix) return TropicalMatrix(new_matrix) def get_polynomial_representation(coefficient_list): term_list = [str(coefficient_list[0])] for i in range(1, len(coefficient_list)): term_list.append(str(coefficient_list[i]) + "x^" + str(i)) return " + ".join(term_list) def generate_key(public_term, public_matrix_a, public_matrix_b): left_term = TropicalMatrix.mult_tropical_matrix(public_matrix_a, public_term, TZmax) right_term = TropicalMatrix.mult_tropical_matrix(convert(left_term), public_matrix_b, TZmin) return right_term if __name__ == "__main__": p_x = [5, 1] t_x = [0, 0, 1] q_x = [2, 1] r_x = [0, 3] X = [[1, 2], [6, 10]] M = [[-1000, 10], [5, 3]] N = [[3, 6], [15, 1000]] p_M = convert(evaluate_polynomial(M, p_x, TZmax)) t_N = convert(evaluate_polynomial(N, t_x, TZmin)) q_M = convert(evaluate_polynomial(M, q_x, TZmax)) r_N = convert(evaluate_polynomial(N, r_x, TZmin)) print('p(x) =', p_M) print('t(x) =', t_N) print('q(x) =', q_M) print('r(x) =', r_N) Alica = TropicalMatrix.mult_tropical_matrix(p_M, X, TZmax) alice_public_key = TropicalMatrix.mult_tropical_matrix(convert(Alica), t_N, TZmin) print('Открытый ключ Алисы: ', alice_public_key) Bob = TropicalMatrix.mult_tropical_matrix(q_M, X, TZmax) bob_public_key = TropicalMatrix.mult_tropical_matrix(convert(Bob), r_N, TZmin) print('Открытый ключ Боба: ', bob_public_key) print('Секретный ключ Алисы: ', generate_key(convert(bob_public_key), p_M, t_N)) print('Секретный ключ Боба: ', generate_key(convert(alice_public_key), q_M, r_N)) import random def pprint_matrix(matrix): print('\n'.join([' '.join([str(cell) for cell in row]) for row in matrix.entries])) if __name__ == "__main__": matrix_size = 2 min_matrix_term = -15 max_matrix_term = 15 min_polynomial_coefficient = -10 max_polynomial_coefficient = 10 max_polynomial_degree = 5 print('Генерация многочленов') print("Секретные многочлены Алисы: ") p_x = generate_random_tropical_poly(max_polynomial_degree, min_polynomial_coefficient, max_polynomial_coefficient) t_x = generate_random_tropical_poly(max_polynomial_degree, min_polynomial_coefficient, max_polynomial_coefficient) print('p(x) =', get_polynomial_representation(p_x)) print('t(x) =', get_polynomial_representation(t_x)) print('Секретные многочлены Боба: ') q_x = generate_random_tropical_poly(max_polynomial_degree, min_polynomial_coefficient, max_polynomial_coefficient) r_x = generate_random_tropical_poly(max_polynomial_degree, min_polynomial_coefficient, max_polynomial_coefficient) print('q(x) =', get_polynomial_representation(q_x)) print('r(x) =', get_polynomial_representation(r_x)) print('Открытая матрица Алисы: ') #M = generate_random_matrix(matrix_size, min_matrix_term, max_matrix_term) M = [[68, 1000],[-1000, 11]] print('M = ', M) print('Открытая матрица Боба: ') #N = generate_random_matrix(matrix_size, min_matrix_term, max_matrix_term) N = [[15, 122],[78, 12]] print('N = ', N) X_matrix = generate_random_matrix(matrix_size, min_matrix_term, max_matrix_term) print('Матрица X: ', X_matrix) print('Алиса отправляет Бобу следующую матрицу') p_M = convert(evaluate_polynomial(M, p_x, TZmax)) t_N = convert(evaluate_polynomial(N, t_x, TZmin)) Alica = TropicalMatrix.mult_tropical_matrix(p_M, X, TZmax) alice_public_key = TropicalMatrix.mult_tropical_matrix(convert(Alica), t_N, TZmin) print('Открытый ключ Алисы: ') pprint_matrix(alice_public_key) print('Боб отправляет Алисе следующую матрицу') q_M = convert(evaluate_polynomial(M, q_x, TZmax)) r_N = convert(evaluate_polynomial(N, r_x, TZmin)) Bob = TropicalMatrix.mult_tropical_matrix(q_M, X, TZmax) bob_public_key = TropicalMatrix.mult_tropical_matrix(convert(Bob), r_N, TZmin) print('Открытый ключ Боба: ') pprint_matrix(bob_public_key) print('Алиса и Боб вычисляют секретные ключи') print('Секретный ключ Алисы: ') alice_key = generate_key(convert(bob_public_key), p_M, t_N) pprint_matrix(alice_key) print('Секретный ключ Боба: ') bob_key = generate_key(convert(alice_public_key), q_M, r_N) pprint_matrix(bob_key)