コード例 #1
0
def row_echelon(A: nmod_mat) -> None:
    """
    Convert A in place to row echelon (upper triangular) form
    with ones along the diagonal (if possible)
    """
    nrows: int = A.nrows()
    ncols: int = A.ncols()
    h: int = 0  # pivot row
    k: int = 0  # pivot column
    while h < nrows and k < ncols:
        try:
            swap_rows_to_get_nonzero_pivot_point(A, h, k)
            assert A[h, k] != nmod(0, A.modulus())
            scale: nmod = 1 / A[h, k]
            for i in range(k, ncols):
                A[h, i] *= scale
            for i in range(h + 1, nrows):
                f: nmod = A[i, k]
                A[i, k] = 0
                for j in range(k + 1, ncols):
                    A[i, j] -= A[h, j] * f
            h += 1
            k += 1
        except GetRowIndexError:
            k += 1
コード例 #2
0
def solve_singular_case(A: nmod_mat) -> nmod_mat:
    """
    Return a solution for a singular set of equations.
    The system may be singular because there are
    multiple solutions. In this case I will return
    a particular solution.
    If the solution does not exist raise a NoSolution
    exception.
    """
    nrows = A.nrows()
    ncols = A.ncols()
    null_count = count_null_rows(A)
    if null_count == 0:
        raise NoSolutionError()
    # a solution exists create a return value with all zeros
    X = nmod_mat(ncols - 1, 1, A.modulus())
    # starting at the bottom, skip over the null rows
    for row in range(nrows - null_count - 1, -1, -1):
        col = find_leading_one(A, row)
        # pick off the value of the solution from the last column
        X[col, 0] = A[row, ncols - 1]
        # back substitute this row on the remaining rows
        for row1 in range(row - 1, -1, -1):
            f = A[row1, col]
            A[row1, col] = 0
            for col1 in range(col + 1, ncols):
                A[row1, col1] -= f * A[row, col1]
    return X
コード例 #3
0
def solve_normal_case(A: nmod_mat) -> nmod_mat:
    """
    Completes the solution for the non-singular case
    by performing back substution on the matrix
    A which must be in echelon form comming in.
    """
    nrows = A.nrows()
    ncols = A.ncols()
    back_substitution(A)
    X = nmod_mat(nrows, 1, A.modulus())
    for i in range(nrows):
        X[i, 0] = A[i, ncols - 1]
    return X
コード例 #4
0
def back_substitution(A: nmod_mat) -> None:
    """
    Assuming A is in row echelon form with A[i,i] == 1 (mod p)
    then perform back substitution
    """
    nrows = A.nrows()
    ncols = A.ncols()
    last = ncols - 1
    # leave the last row alone
    for row in range(nrows - 1, 0, -1):
        assert int(A[row, row]) == 1
        for row1 in range(row - 1, -1, -1):
            temp = A[row1, row] * A[row, last]
            A[row1, row] = 0
            A[row1, last] -= temp
コード例 #5
0
def count_null_rows(A: nmod_mat) -> int:
    """
    Starting from the bottom. Count the number
    of rows consisting of all zeros in the
    matrix A. A must be in row echelon form.
    """
    nrows = A.nrows()
    ncols = A.ncols()
    count = 0
    for row in range(nrows - 1, -1, -1):
        for col in range(ncols):
            if int(A[row, col]) != 0:
                return count
        count += 1
    return count
コード例 #6
0
def is_singular(A: nmod_mat) -> bool:
    """
    Checks to see if the system of equations is singular.
    A must be in row-echelon form.
    """
    for row in range(A.nrows()):
        if int(A[row, row]) == 0:
            return True
    return False
コード例 #7
0
def swap_rows(A: nmod_mat, i: int, j: int) -> None:
    """
    Swap rows i and j of the matrix A
    """
    if i == j:
        return
    for col in range(A.ncols()):
        temp = A[i, col]
        A[i, col] = A[j, col]
        A[j, col] = temp
コード例 #8
0
def find_leading_one(A: nmod_mat, row: int) -> int:
    """
    Assuming that A is in echelon form where the
    leading value on a row is 1, find the zero-based
    column of the leading one for that row
    """
    for col in range(0, A.ncols()):
        if int(A[row, col]) == 1:
            return col
    raise NoSolutionError
コード例 #9
0
def get_row_index(A: nmod_mat, h: int, k: int) -> int:
    """
    Starting at row h and going down, find a
    row where where the k'th element is non-zero
    return the index of that row. If no row is found
    raise an IndexError exception
    """
    nrows = A.nrows()
    for i in range(h, nrows):
        if int(A[i, k]) != 0:
            return i
    raise GetRowIndexError
コード例 #10
0
def augment(M: nmod_mat, Y: nmod_mat) -> nmod_mat:
    """
    Create a matrix representing a set of linear
    equations by gluing on Y to the right side of M
    """
    nrows = M.nrows()
    ncols = M.ncols()
    if not (nrows > 0 and nrows == ncols):
        raise ValueError
    if not (Y.nrows() == nrows and Y.ncols() == 1):
        raise ValueError
    if not Y.modulus() == M.modulus():
        raise ValueError
    A = nmod_mat(nrows, ncols + 1, M.modulus())
    for row in range(nrows):
        for col in range(ncols):
            A[row, col] = M[row, col]
        A[row, ncols] = Y[row, 0]
    return A