Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 带模的Numpy矩阵幂/指数?_Python_Matrix_Modulo_Exponent - Fatal编程技术网

Python 带模的Numpy矩阵幂/指数?

Python 带模的Numpy矩阵幂/指数?,python,matrix,modulo,exponent,Python,Matrix,Modulo,Exponent,有没有可能使用numpy的linalg.matrix_幂加模,这样元素的增长不会超过某个值?这种明显的方法有什么问题 例如 为了防止溢出,您可以使用这样一个事实,即如果您首先取每个输入数字的模,您将得到相同的结果;事实上: (M**k) mod p = ([M mod p]**k) mod p, 对于矩阵M。这来自以下两个基本恒等式,它们对整数x和y有效: (x+y) mod p = ([x mod p]+[y mod p]) mod p # All additions can be don

有没有可能使用numpy的linalg.matrix_幂加模,这样元素的增长不会超过某个值?

这种明显的方法有什么问题

例如


为了防止溢出,您可以使用这样一个事实,即如果您首先取每个输入数字的模,您将得到相同的结果;事实上:

(M**k) mod p = ([M mod p]**k) mod p,
对于矩阵
M
。这来自以下两个基本恒等式,它们对整数
x
y
有效:

(x+y) mod p = ([x mod p]+[y mod p]) mod p  # All additions can be done on numbers *modulo p*
(x*y) mod p = ([x mod p]*[y mod p]) mod p  # All multiplications can be done on numbers *modulo p*
同样的恒等式也适用于矩阵,因为矩阵加法和乘法可以通过标量加法和乘法来表示。使用这种方法,您只需对较小的数字进行指数运算(n mod p通常比n小得多),并且不太可能出现溢出。因此,在NumPy中,您只需

((arr % p)**k) % p
为了获得
(arr**k)mod p

如果这仍然不够(即,如果存在
[n mod p]**k
导致溢出的风险,尽管
n mod p
很小),您可以将求幂分解为多个求幂。屈服之上的基本恒等式

(n**[a+b]) mod p = ([{n mod p}**a mod p] * [{n mod p}**b mod p]) mod p


因此,您可以将电源分解为
a+b+…
a*b*…
或其任何组合。上述标识允许您仅对小数值执行小数值的幂运算,这大大降低了整数溢出的风险。

使用Numpy的实现:

我通过添加一个模项对其进行了修改。但是,存在一个错误,即如果发生溢出,则不会引发
overflowerrror
或任何其他类型的异常。从那时起,解决方案将是错误的。有一个bug报告

这是代码。小心使用:

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
来自numpy.core.numeric import concatenate、isscalar、binary_repr、identity、asanyarray、dot
从numpy.core.numerictypes导入issubdtype
def矩阵功率(M、n、mod值):
#实现了numpy的矩阵幂,但包含了模
M=asanyarray(M)
如果len(M.shape)!=2或M.形状[0]!=M.shape[1]:
raise VALUERROR(“输入必须是方形数组”)
如果不是issubdtype(类型(n),int):
raise TypeError(“指数必须是整数”)
来自numpy.linalg进口投资部
如果n==0:
M=M.copy()
M[:]=标识(M.shape[0])
返回M

elif n我以前的所有解决方案都存在溢出问题,因此我必须编写一个算法来解释每次整数乘法后的溢出。我就是这样做的:

def matrix_power_mod(x, n, modulus):
    x = np.asanyarray(x)
    if len(x.shape) != 2:
        raise ValueError("input must be a matrix")
    if x.shape[0] != x.shape[1]:
        raise ValueError("input must be a square matrix")
    if not isinstance(n, int):
        raise ValueError("power must be an integer")

    if n < 0:
        x = np.linalg.inv(x)
        n = -n
    if n == 0:
        return np.identity(x.shape[0], dtype=x.dtype)
    y = None
    while n > 1:
        if n % 2 == 1:
            y = _matrix_mul_mod_opt(x, y, modulus=modulus)
        x = _matrix_mul_mod(x, x, modulus=modulus)
        n = n // 2
    return _matrix_mul_mod_opt(x, y, modulus=modulus)


def matrix_mul_mod(a, b, modulus):
    if len(a.shape) != 2:
        raise ValueError("input a must be a matrix")
    if len(b.shape) != 2:
        raise ValueError("input b must be a matrix")
    if a.shape[1] != a.shape[0]:
        raise ValueError("input a and b must have compatible shape for multiplication")
    return _matrix_mul_mod(a, b, modulus=modulus)


def _matrix_mul_mod_opt(a, b, modulus):
    if b is None:
        return a
    return _matrix_mul_mod(a, b, modulus=modulus)


def _matrix_mul_mod(a, b, modulus):
    r = np.zeros((a.shape[0], b.shape[1]), dtype=a.dtype)
    bT = b.T
    for rowindex in range(r.shape[0]):
        x = (a[rowindex, :] * bT) % modulus
        x = np.sum(x, 1) % modulus
        r[rowindex, :] = x
    return r
def矩阵功率模(x,n,模数):
x=np.asanyarray(x)
如果len(x.shape)!=2:
提升值错误(“输入必须是矩阵”)
如果x.shape[0]!=x、 形状[1]:
raise VALUE ERROR(“输入必须是方阵”)
如果不是isinstance(n,int):
raise VALUERROR(“幂必须是整数”)
如果n<0:
x=np.linalg.inv(x)
n=-n
如果n==0:
返回np.identity(x.shape[0],dtype=x.dtype)
y=无
当n>1时:
如果n%2==1:
y=_矩阵_mul_mod_opt(x,y,模数=模数)
x=_矩阵_mul_模(x,x,模=模)
n=n//2
返回矩阵mulmod opt(x,y,模数=模数)
def矩阵(a、b、模数):
如果len(a.shape)!=2:
提升值错误(“输入a必须是矩阵”)
如果len(b.shape)!=2:
提升值错误(“输入b必须是矩阵”)
如果a.shape[1]!=a、 形状[0]:
raise VALUERROR(“输入a和b必须具有相乘的兼容形状”)
返回矩阵模(a,b,模=模)
def(矩阵)mul(模)opt(a,b,模):
如果b为无:
归还
返回矩阵模(a,b,模=模)
定义矩阵多模(a、b、模数):
r=np.zero((a.shape[0],b.shape[1]),dtype=a.dtype)
bT=b.T
对于范围(r.shape[0])中的行索引:
x=(a[rowindex,:]*bT)%modules
x=np.和(x,1)%模数
r[rowindex,:]=x
返回r

您能否定义模数的含义。模数=余数运算。比如10 mod 3=1,24 mod 5=4,等等。linalg.matrix_幂很快,但我希望能够在元素变得太大之前将模运算应用到元素上。啊,模:对,但在元素膨胀之前与矩阵幂运算结合使用是的,模是一个名词(某物的模:向量,复数等)。,“符号乘以模数格式”),而模(通常缩写为'mod')是……不同的东西(副词,分词?)。这将帮助我不再将余数称为模,但我仍然无法在NumPy中找到向量化的元素级幂,比如内置的
pow(x,y,z=None,/)
,它是
等价于x**y(有两个参数)或x**y%z(有三个参数)
可能OP使用了大指数,并且出现了溢出问题。例如,在加密内容中,通常在大整数上使用指数运算与模运算相结合的算法
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
def matrix_power_mod(x, n, modulus):
    x = np.asanyarray(x)
    if len(x.shape) != 2:
        raise ValueError("input must be a matrix")
    if x.shape[0] != x.shape[1]:
        raise ValueError("input must be a square matrix")
    if not isinstance(n, int):
        raise ValueError("power must be an integer")

    if n < 0:
        x = np.linalg.inv(x)
        n = -n
    if n == 0:
        return np.identity(x.shape[0], dtype=x.dtype)
    y = None
    while n > 1:
        if n % 2 == 1:
            y = _matrix_mul_mod_opt(x, y, modulus=modulus)
        x = _matrix_mul_mod(x, x, modulus=modulus)
        n = n // 2
    return _matrix_mul_mod_opt(x, y, modulus=modulus)


def matrix_mul_mod(a, b, modulus):
    if len(a.shape) != 2:
        raise ValueError("input a must be a matrix")
    if len(b.shape) != 2:
        raise ValueError("input b must be a matrix")
    if a.shape[1] != a.shape[0]:
        raise ValueError("input a and b must have compatible shape for multiplication")
    return _matrix_mul_mod(a, b, modulus=modulus)


def _matrix_mul_mod_opt(a, b, modulus):
    if b is None:
        return a
    return _matrix_mul_mod(a, b, modulus=modulus)


def _matrix_mul_mod(a, b, modulus):
    r = np.zeros((a.shape[0], b.shape[1]), dtype=a.dtype)
    bT = b.T
    for rowindex in range(r.shape[0]):
        x = (a[rowindex, :] * bT) % modulus
        x = np.sum(x, 1) % modulus
        r[rowindex, :] = x
    return r