Numpy matrix power/exponent with modulo?

后端 未结 4 1741
慢半拍i
慢半拍i 2021-01-01 21:20

Is it possible to use numpy\'s linalg.matrix_power with a modulo so the elements don\'t grow larger than a certain value?

4条回答
  •  暖寄归人
    2021-01-01 21:27

    Using the implementation from Numpy:

    https://github.com/numpy/numpy/blob/master/numpy/matrixlib/defmatrix.py#L98

    I adapted it by adding a modulo term. HOWEVER, there is a bug, in that if an overflow occurs, no OverflowError or any other sort of exception is raised. From that point on, the solution will be wrong. There is a bug report here.

    Here is the code. Use with care:

    from numpy.core.numeric import concatenate, isscalar, binary_repr, identity, asanyarray, dot
    from numpy.core.numerictypes import issubdtype    
    def matrix_power(M, n, mod_val):
        # Implementation shadows numpy's matrix_power, but with modulo included
        M = asanyarray(M)
        if len(M.shape) != 2 or M.shape[0] != M.shape[1]:
            raise ValueError("input  must be a square array")
        if not issubdtype(type(n), int):
            raise TypeError("exponent must be an integer")
    
        from numpy.linalg import inv
    
        if n==0:
            M = M.copy()
            M[:] = identity(M.shape[0])
            return M
        elif n<0:
            M = inv(M)
            n *= -1
    
        result = M % mod_val
        if n <= 3:
            for _ in range(n-1):
                result = dot(result, M) % mod_val
            return result
    
        # binary decompositon to reduce the number of matrix
        # multiplications for n > 3
        beta = binary_repr(n)
        Z, q, t = M, 0, len(beta)
        while beta[t-q-1] == '0':
            Z = dot(Z, Z) % mod_val
            q += 1
        result = Z
        for k in range(q+1, t):
            Z = dot(Z, Z) % mod_val
            if beta[t-k-1] == '1':
                result = dot(result, Z) % mod_val
        return result % mod_val
    

提交回复
热议问题