Files
TropicZ/tropicZ.ipynb
T

26 KiB

In [ ]:
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)
In [ ]:
TZ = TropicZ(1000, 'max')
TZmin = TropicZ(1000, 'min')
TZmax = TropicZ(1000, 'max')
In [ ]:
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)
5
10
-5
11
6
[0, 1, 2, 3, 4, 5, 6]
6
-995
In [ ]:
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)
p(x) = [[5, 10], [5, 5]]
t(x) = [[6, 9], [18, 21]]
q(x) = [[2, 10], [5, 3]]
r(x) = [[6, 9], [18, 1000]]
In [ ]:
import math
import random
import numpy as np
In [ ]:
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)
[[25, 1000], [18, 1000]]
In [ ]:
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))
p(x) = [[5, 10], [5, 5]]
t(x) = [[6, 9], [18, 21]]
q(x) = [[2, 10], [5, 3]]
r(x) = [[6, 9], [18, 1000]]
Открытый ключ Алисы:  [[22, 25], [17, 20]]
Открытый ключ Боба:  [[22, 25], [15, 18]]
Секретный ключ Алисы:  [[33, 36], [33, 36]]
Секретный ключ Боба:  [[33, 36], [33, 36]]
In [ ]:
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)
Генерация многочленов
Секретные многочлены Алисы: 
p(x) = 9 + -4x^1 + 9x^2 + 7x^3
t(x) = 10 + -8x^1 + -5x^2 + -7x^3
Секретные многочлены Боба: 
q(x) = 2 + 9x^1 + -4x^2 + 8x^3
r(x) = 5 + 6x^1 + 8x^2 + 3x^3
Открытая матрица Алисы: 
M =  [[68, 1000], [-1000, 11]]
Открытая матрица Боба: 
N =  [[15, 122], [78, 12]]
Матрица X:  [[14, 5], [14, 1]]
Алиса отправляет Бобу следующую матрицу
Открытый ключ Алисы: 
1000  1000
88  89
Боб отправляет Алисе следующую матрицу
Открытый ключ Боба: 
1000  1000
87  91
Алиса и Боб вычисляют секретные ключи
Секретный ключ Алисы: 
1000  1000
169  170
Секретный ключ Боба: 
1000  1000
169  170
In [ ]: