Example #1
0
def invertMatrixZN(M, N):
    """Invertiert eine Matrix M in ZN mit dem Gauss-Jordan-Algorithmus, indem
    die Matrix zu einer Einheitsmatrix umgeformt und die entsprechenden Schritte
    auf einer Einheitsmatrix wiederholt werden, die dann am Schluss die Inverse
    darstellt.
    """
    n = M.shape[0]  # shape = (nzeilen, nspalten), also shape[0] = nzeilen
    M = M.copy() # nicht an der Originalmatrix rumspielen
    I = np.identity(n, int) # Einheitsmatrix -> wird später das Ergebnis
    for row in range(n):
        if not invertierbar(M[row, row], N):
            # müssen Zeilen tauschen
            for j in range(row+1, n):
                if invertierbar(M[j, row], N):
                    tmp = M[row, :].copy()
                    M[row, :] = M[j, :]
                    M[j, :] = tmp
                    tmp = I[row, :].copy()
                    I[row, :] = I[j, :]
                    I[j, :] = tmp
                    break
            else:
                # hier kommen wir hin wenn die for-Schleife nicht durch ein
                # break beendet wurde, also keine geeignete Zeile zum Tauschen
                # existiert
                raise ValueError("Matrix nicht invertierbar")
        # Zeile mit dem Inversen des Pivot-Elements multiplizieren, um eine 1
        # auf der Diagonalen zu erreichen
        faktor = invertZN(M[row, row], N)
        M[row, :] = (M[row, :] * faktor) % N
        I[row, :] = (I[row, :] * faktor) % N
        
        # Nullen unterhalb des aktuellen Pivots erzeugen
        for j in range(row + 1, n):
            if invertierbar(M[j, row], N):
                faktor = invertZN(M[j, row], N)
                M[j, :] = (M[j, :] * faktor - M[row, :]) % N
                I[j, :] = (I[j, :] * faktor - I[row, :]) % N
            elif M[j, row] != 0:
                # In Z_N können Nullteiler auftreten, z.B. die 8 in Z_{12}.
                # Um dort eine 0 zu erzeugen, müssen wir mit dem kgV der beiden
                # Zahlen multiplizieren. Da ggt*kgv = mn gilt, können wir dazu
                # den bereits implementierten ggt-Algorithmus nehmen.
                faktor = N * M[j, row] // krypto1.ggT(N, M[j, row])
                M[j, :] = (M[j, :] * faktor) % N
                I[j, :] = (I[j, :] * faktor) % N
    # jetzt haben wir eine obere Dreiecksmatrix. Um daraus eine Diagonalmatrix
    # zu machen, müssen wir nun noch einmal von unten nach oben durchgehen
    # um die Einträge oberhalb der Diagonalen zu Nullen zu machen.
    for row in range(n-1, -1, -1):
        for j in range(row + 1, n):
            faktor = M[row, j]
            M[row, :] = (M[row, :] - faktor*M[j, :]) % N
            I[row, :] = (I[row, :] - faktor*I[j, :]) % N
    return I
Example #2
0
def invertierbar(a, N):
    """Gibt an ob eine Zahl a invertierbar in Z_N ist."""
    return krypto1.ggT(a, N) == 1