Можно ли использовать numpy linalg.matrix_power с модулем, чтобы элементы не становились больше определенного значения?
Численная мощность матрицы/показатель по модулю?
Ответ 1
Чтобы предотвратить переполнение, вы можете использовать тот факт, что вы получаете тот же результат, если сначала принимаете по модулю каждого из ваших номеров ввода; на самом деле:
(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
и
(n**[a*b]) mod p = ([n mod p]**a mod p)**b mod p.
Таким образом, вы можете разбить мощность k
как a+b+…
или a*b*…
или любую их комбинацию. Вышеупомянутые тождества позволяют выполнять только экспоненциальные числа небольших чисел по малым числам, что значительно снижает риск переполнения целых чисел.
Ответ 2
Использование реализации из Numpy:
https://github.com/numpy/numpy/blob/master/numpy/matrixlib/defmatrix.py#L98
Я адаптировал его, добавив модульный термин. ОДНАКО, есть ошибка, в которой, если происходит переполнение, не возникает OverflowError
или любое другое исключение. С этого момента решение будет неправильным. Существует отчет об ошибке здесь.
Вот код. Используйте с осторожностью:
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 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
Ответ 3
Что не так с очевидным подходом?
например.
import numpy as np
x = np.arange(100).reshape(10,10)
y = np.linalg.matrix_power(x, 2) % 50