Самый простой способ выполнить модульную инверсию матрицы с Python? - PullRequest
20 голосов
/ 26 ноября 2010

Я бы хотел взять модульную инверсию матрицы, как [[1,2], [3,4]] mod 7 в Python. Я посмотрел на numpy (который выполняет инверсию матрицы, но не инверсию модульной матрицы) и увидел в сети несколько пакетов теории чисел, но ничего такого, что, кажется, не делает эту относительно распространенную процедуру (по крайней мере, для меня это кажется относительно обычной) 1001 *

Кстати, обратная матрица выше [[5,1], [5,3]] (мод 7). Я бы хотел, чтобы Python сделал это для меня.

Ответы [ 7 ]

12 голосов
/ 15 июля 2011

Хакерский трюк, который работает, когда ошибки округления не являются проблемой:

  • находит регулярное обратное (может иметь нецелые записи) и определитель (целое число), оба реализованные вnumpy
  • умножить обратное на определитель и округлить до целых (хаки)
  • теперь умножить все на умножительное обратное определителя (по модулю ваш модуль, код ниже)
  • doentrywise mod по вашему модулю

Менее хакерский способ - это реализовать гауссово исключение.Вот мой код с использованием исключения Гаусса, который я написал для своих собственных целей (ошибки округления были проблемой для меня).q - это модуль, который не обязательно прост.

def generalizedEuclidianAlgorithm(a, b):
    if b > a:
        return generalizedEuclidianAlgorithm(b,a);
    elif b == 0:
        return (1, 0);
    else:
        (x, y) = generalizedEuclidianAlgorithm(b, a % b);
        return (y, x - (a / b) * y)

def inversemodp(a, p):
    a = a % p
    if (a == 0):
        print "a is 0 mod p"
        return None
    if a > 1 and p % a == 0:
        return None
    (x,y) = generalizedEuclidianAlgorithm(p, a % p);
    inv = y % p
    assert (inv * a) % p == 1
    return inv

def identitymatrix(n):
    return [[long(x == y) for x in range(0, n)] for y in range(0, n)]

def inversematrix(matrix, q):
    n = len(matrix)
    A = np.matrix([[ matrix[j, i] for i in range(0,n)] for j in range(0, n)], dtype = long)
    Ainv = np.matrix(identitymatrix(n), dtype = long)
    for i in range(0, n):
        factor = inversemodp(A[i,i], q)
        if factor is None:
             raise ValueError("TODO: deal with this case")
        A[i] = A[i] * factor % q
        Ainv[i] = Ainv[i] * factor % q
        for j in range(0, n):
            if (i != j):
                factor = A[j, i]
                A[j] = (A[j] - factor * A[i]) % q
                Ainv[j] = (Ainv[j] - factor * Ainv[i]) % q
    return Ainv

РЕДАКТИРОВАТЬ: как указывают комментаторы, в некоторых случаях этот алгоритм не работает.Это немного нетривиально исправить, и у меня нет времени в настоящее время.Тогда в моем случае это работало для случайных матриц (модули были произведениями больших простых чисел).По сути, первая ненулевая запись не может быть относительно простой по отношению к модулю.Основной случай прост, так как вы можете искать другую строку и менять местами.В не простом случае, я думаю, что все ведущие записи не являются относительно простыми, поэтому вы должны объединить их

9 голосов
/ 27 ноября 2010

Хорошо ... для тех, кому все равно, я решил свою проблему.Это заняло у меня некоторое время, но я думаю, что это работает.Это, вероятно, не самый элегантный и должен включать в себя еще несколько обработчиков ошибок, но он работает:

import numpy
import math
from numpy import matrix
from numpy import linalg

def modMatInv(A,p):       # Finds the inverse of matrix A mod p
  n=len(A)
  A=matrix(A)
  adj=numpy.zeros(shape=(n,n))
  for i in range(0,n):
    for j in range(0,n):
      adj[i][j]=((-1)**(i+j)*int(round(linalg.det(minor(A,j,i)))))%p
  return (modInv(int(round(linalg.det(A))),p)*adj)%p

def modInv(a,p):          # Finds the inverse of a mod p, if it exists
  for i in range(1,p):
    if (i*a)%p==1:
      return i
  raise ValueError(str(a)+" has no inverse mod "+str(p))

def minor(A,i,j):    # Return matrix A with the ith row and jth column deleted
  A=numpy.array(A)
  minor=numpy.zeros(shape=(len(A)-1,len(A)-1))
  p=0
  for s in range(0,len(minor)):
    if p==i:
      p=p+1
    q=0
    for t in range(0,len(minor)):
      if q==j:
        q=q+1
      minor[s][t]=A[p][q]
      q=q+1
    p=p+1
  return minor
3 голосов
/ 22 октября 2014

Его можно рассчитать, используя Sage ( www.sagemath.org ) как

Matrix (IntegerModRing (7), [[1, 2], [3,4]]). Inverse ()

Несмотря на то, что Sage очень прост в установке, вам придется использовать версию Python, которая идет с ним, что очень неудобно.

2 голосов
/ 26 ноября 2010

К сожалению, numpy не имеет модульных арифметических реализаций.Вы всегда можете закодировать предложенный алгоритм, используя сокращение строки или определители, как показано здесь .Модульное обратное представляется весьма полезным для криптографии.

1 голос
/ 02 мая 2018

Пакет «sympy» Функция класса Matrix «sqMatrix.inv_mod (mod)» вычисляет обратную матрицу по модулю для малых и сколь угодно больших модулей. Комбинируя sympy с numpy, становится легко вычислять обратное по модулю двумерных массивов numpy (см. Фрагмент кода ниже):

enter code here

import numpy
from sympy import Matrix

    def matInvMod (vmnp, mod):
    nr = vmnp.shape[0]
    nc = vmnp.shape[1]
    if (nr!= nc):
        print "Error: Non square matrix! exiting"
        exit()
    vmsym = Matrix(vmnp)
    vmsymInv = vmsym.inv_mod(mod)
    vmnpInv = numpy.array(vmsymInv)
    print "vmnpInv: ", vmnpInv, "\n"
    k = nr
   vmtest = [[1 for i in range(k)] for j in range(k)]  # just a 2-d list
   vmtestInv = vmsym*vmsymInv
   for i in range(k):
      for j in range(k):
         #print i, j, vmtrx2[i,j] % mod
         vmtest[i][j] = vmtestInv[i,j] % mod
   print "test vmk*vkinv % mod \n:", vmtest
   return vmnpInv

if __name__ == '__main__':
    #p = 271
    p = 

115792089210356248762697446949407573530086143415290314195533631308867097853951 vm = numpy.array ([[1,1,1,1], [1, 2, 4, 8], [1, 4, 16, 64], [1,5, 25, 125]])
#vminv = modMatInv (vm, p) vminv = matInvMod (vm, p) печать vminv vmtestnp = vm.dot (vminv)% p # test инверсия mtrx печать vmtestnp

0 голосов
/ 30 апреля 2018

как сделать матрицу модульности.Вычислить модульную матрицу.Разделите основной граф на кластеры, используя собственный вектор для модульной матрицы.Сделайте это для каждого созданного кластера, итеративно (каждый кластер будет разделен на два кластера и так далее ...).После выполнения каждого шага количество кластеров будет в два раза больше.Критерием кластеризации в этом вопросе является модульность.Для этого на каждом шаге рассчитайте критерий модульности и остановите алгоритм там, где он уменьшается.

в питоне

0 голосов
/ 26 ноября 2010

Этот небольшой фрагмент кода, кажется, делает это: ссылка

Обратите внимание на комментарий ниже для небольшого улучшенияКажется, чтобы сделать правильную линейную алгебру, насколько я могу видеть.Я никогда не находил ни одной опции в обычных пакетах, поэтому, вероятно, самый простой подход - взять фрагмент кода из Интернета (их гораздо больше).

...