La façon la plus simple d'effectuer une inversion de matrice modulaire avec Python?

j'aimerais prendre l'inverse modulaire d'une matrice comme [1,2], [3,4]] mod 7 en Python. J'ai regardé numpy (qui fait l'inversion de matrice mais pas l'inversion de matrice modulaire) et j'ai vu quelques paquets de théorie des nombres en ligne, mais rien qui semble faire cette procédure relativement commune (au moins, il semble relativement commun pour moi).

soit dit en passant, l'inverse de la matrice ci-dessus est [[5,1],[5,3]] (mod 7). J'aimerais que Python le fasse pour moi.

17
demandé sur Shai 2010-11-26 21:28:03

7 réponses

un truc hackish qui fonctionne quand les erreurs d'arrondi ne sont pas un problème:

  • trouver l'inverse régulier (peut avoir des entrées non-entières), et le déterminant( un entier), tous les deux implémentés dans numpy
  • multiplier l'inverse par le déterminant, et Rond À entier (hacky)
  • maintenant, multipliez tout par l'inverse multiplicatif du déterminant (modulo votre module, code ci-dessous)
  • ne entrywise mod par votre module

Un moins de manière hackish est de mettre en œuvre l'élimination gaussienne. Voici mon code utilisant L'élimination gaussienne, que j'ai écrit pour mes propres fins (les erreurs d'arrondissement étaient un problème pour moi). q est le module, qui n'est pas nécessairement premier.

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

EDIT: comme le font remarquer les commentateurs, il y a des cas où cet algorithme échoue. C'est un peu banal à réparer, et je n'ai pas le temps de nos jours. À l'époque, il fonctionnait pour des matrices aléatoires dans mon cas (les modules étaient des produits de grands nombres premiers). Fondamentalement, la première entrée non nulle pourrait ne pas être relativement premier au module. Le cas principal est facile puisque vous pouvez rechercher une ligne différente et échanger. Dans le cas de non-prime, je pense que ça pourrait être ça les entrées de tête ne sont pas relativement premier donc vous devez les combiner

11
répondu WuTheFWasThat 2017-11-20 18:12:22

Ok...pour ceux que ça intéresse, j'ai résolu mon problème. Ça m'a pris du temps, mais je pense que ça marche. C'est probablement pas le plus élégant, et devrait inclure plus d'erreur de manipulation, mais il fonctionne:

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
9
répondu John 2010-11-27 18:55:50

il peut être calculé en utilisant Sage (www.sagemath.org) comme

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

bien que Sage est énorme à installer et vous devez utiliser la version de python qui vient avec elle qui est une douleur.

3
répondu Ben Reynwar 2014-10-21 23:27:54

malheureusement numpy n'a pas d'implémentations arithmétiques modulaires. Vous pouvez toujours coder l'algorithme proposé en utilisant la réduction de ligne ou les déterminants comme démontré ici. Une inversion modulaire semble être très utile pour la cryptographie.

2
répondu whatnick 2010-11-27 01:51:23

Ce petit morceau de code semble le faire: lien

Notez le commentaire ci-dessous pour une petite amélioration. Il semble faire l'algèbre linéaire correcte aussi loin que je puisse voir. Je n'ai jamais trouvé d'option dans les paquets réguliers donc probablement prendre un extrait de code sur le web (il y en a beaucoup plus disponible) est l'approche la plus facile.

0
répondu bastijn 2010-11-26 19:06:04

'sympy' l'ensemble de la Matrice de fonction de classe 'sqMatrix.inv_mod (mod)' calcule une matrice de modulo inverse pour un module petit et arbitrairement grand. En combinant sympy avec numpy, il devient facile de calculer modulo inverse de tableaux numpy 2-D (voir l'extrait de code ci-dessous):

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.tableau([[1,1,1,1], [1, 2, 4, 8], [1, 4, 16, 64], [1, 5, 25, 125]])

# vminv = modMatInv (vm, p) vminv = matInvMod(vm, p) imprimer vminv vmtestnp = vm.dot (vminv)%P # test MTRX inversion imprimer vmtestnp

0
répondu user1864863 2018-05-03 12:48:23

comment faire la matrice de modularité. Calculez la matrice modulaire. Divisez le graphique principal en grappes en utilisant le vecteur d'eigen pour la matrice modulaire. Faites ceci pour chaque cluster créé, de façon itérative( chaque cluster sera alors divisé en deux clusters et ainsi de suite...). Après chaque étape, le nombre de grappes sera deux fois plus élevé. Le critère de regroupement dans cette question Est la modularité. À cette fin, à chaque étape calculer le critère de modularité et arrêter l'algorithme où il est dégressif.

en python

-2
répondu hussain 2018-04-30 12:47:52