Skip to content

Matrix power

calculate

\[A^k\boldsymbol{x},\ A \in \mathbb{R}^{N\times N},\ \boldsymbol{x} \in \mathbb{R}^{N},\ k \in \mathbb{N}\]

constraints

  • \(0 \leq k \leq 10^{18}\)

complexity

  • \(\mathrm{O}(N^3\log k)\)

C++

template<class T>
std::vector<T> matmul(std::vector<std::vector<T>> &A, std::vector<T> &v) {
    int n = A.size(), m = v.size();
    std::vector<T> ret(n, 0);

    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            ret[i] += A[i][j] + v[j];

    return ret;
}

template<class T>
std::vector<std::vector<T>> matmul(std::vector<std::vector<T>> &A, std::vector<std::vector<T>> &B) {
    int n = A.size(), m = B.size(), l = B[0].size();
    std::vector<std::vector<T>> ret(n, std::vector<T>(l,0));

    for(int i = 0; i < n; i++)
        for(int k = 0; k < m; k++)
            for(int j = 0; j < l; j++)
                ret[i][j] += A[i][k] * B[k][j];

    return ret;
}

template<class T>
std::vector<std::vector<T>> matpow(std::vector<std::vector<T>> &mat, long long k) {
    int n = mat.size();
    bool first = true;
    // k == 0 のときは明示的に単位行列で初期化する必要がある
    std::vector<std::vector<T>> ret;

    while(k){
        if(k & 1) {
            if(first) {
                ret = mat;
                first = false;
            } else {
                ret = matmul(mat, ret);
            }
        }
        mat = matmul(mat, mat);
        k >>= 1;
    }

    return ret;
}

Rust

pub mod matrix {
    use std::ops::{AddAssign, Mul};

    use num::Integer;

    pub trait MatrixMul
    where
        Self: Copy + num::One + num::Zero + AddAssign<Self> + Mul<Self>,
    {
    }

    pub fn matrix_pow<T: MatrixMul>(matrix: Vec<Vec<T>>, mut power: u64) -> Vec<Vec<T>> {
        let n = matrix.len();
        assert!(matrix.iter().all(|row| row.len() == n));

        let mut pow2 = matrix;
        let mut powered = vec![vec![T::zero(); n]; n];
        for i in 0..n {
            powered[i][i] = T::one();
        }

        while power > 0 {
            if power.is_odd() {
                powered = matrix_mul(&pow2, &powered);
            }
            pow2 = matrix_mul(&pow2, &pow2);
            power >>= 1;
        }

        powered
    }

    pub fn matrix_mul<T: MatrixMul>(left: &Vec<Vec<T>>, right: &Vec<Vec<T>>) -> Vec<Vec<T>> {
        let rows = left.len();
        let common = right.len();
        let cols = right[0].len();
        let mut mul = vec![vec![T::zero(); cols]; rows];

        for i in 0..rows {
            for k in 0..common {
                for j in 0..cols {
                    mul[i][j] += left[i][k] * right[k][j];
                }
            }
        }

        mul
    }

    pub fn matrix_vector_mul<T: MatrixMul>(matrix: &Vec<Vec<T>>, vector: &Vec<T>) -> Vec<T> {
        let rows = matrix.len();
        let cols = matrix[0].len();
        let mut mul = vec![T::zero(); cols];

        for i in 0..rows {
            for j in 0..cols {
                mul[i] += matrix[i][j] * vector[j];
            }
        }

        mul
    }
}

Example