def matrix_power(M, n): """Raise a square matrix to the (integer) power `n`. Args: M (~cupy.ndarray): Matrix to raise by power n. n (~int): Power to raise matrix to. Returns: ~cupy.ndarray: Output array. .. note:: M must be of dtype `float32` or `float64`. ..seealso:: :func:`numpy.linalg.matrix_power` """ if M.ndim != 2 or M.shape[0] != M.shape[1]: raise ValueError('input must be a square array') if not isinstance(n, int): raise TypeError('exponent must be an integer') if n == 0: return cupy.identity(M.shape[0], dtype=M.dtype) elif n < 0: M = inv(M) n *= -1 # short-cuts if n <= 3: if n == 1: return M elif n == 2: return cupy.matmul(M, M) else: return cupy.matmul(cupy.matmul(M, M), M) # binary decomposition to reduce the number of Matrix # multiplications for n > 3. result, Z = None, None for b in cupy.binary_repr(n)[::-1]: Z = M if Z is None else cupy.matmul(Z, Z) if b == '1': result = Z if result is None else cupy.matmul(result, Z) return result
def matrix_power(M, n): """Raise a square matrix to the (integer) power `n`. Args: M (~cupy.ndarray): Matrix to raise by power n. n (~int): Power to raise matrix to. Returns: ~cupy.ndarray: Output array. ..seealso:: :func:`numpy.linalg.matrix_power` """ _util._assert_cupy_array(M) _util._assert_stacked_2d(M) _util._assert_stacked_square(M) if not isinstance(n, int): raise TypeError('exponent must be an integer') if n == 0: return _util.stacked_identity_like(M) elif n < 0: M = _solve.inv(M) n *= -1 # short-cuts if n <= 3: if n == 1: return M elif n == 2: return cupy.matmul(M, M) else: return cupy.matmul(cupy.matmul(M, M), M) # binary decomposition to reduce the number of Matrix # multiplications for n > 3. result, Z = None, None for b in cupy.binary_repr(n)[::-1]: Z = M if Z is None else cupy.matmul(Z, Z) if b == '1': result = Z if result is None else cupy.matmul(result, Z) return result