430 lines
15 KiB
Python
430 lines
15 KiB
Python
# -*- 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)
|
||
|