Skip to main content

Matrix Exponentiation

Author: @Ishwarendra

Overview

First and foremost, it is highly recommended to go through Binary Exponentiation, if you are not acquainted with it or don't remember it clearly. It is expected that reader knows Multiplication of two matrices.

Matrix exponentiation is very useful in solving problems that involve finding nthn^{th} term of a linear recurrence with constant coefficients in order of log(n)log(n).

Matrix exponentiation is all about finding a matrix TT such that TA=BT \cdot A = B where AA and BB are two matrices of appropriate order. Before we delve deeper let's us recall two things:

  1. Matrix Multiplication is associative i.e.i.e., A(BC)=(AB)CA \cdot (B \cdot C) = (A \cdot B) \cdot C
  2. A matrix AA of order (n×m)(n \times m) can be multiplied with another matrix of order (m×p)(m \times p) only.

Q.1.Q.1. Before we go any further, let us solve a problem. Find a matrix TT such that TAT \cdot A = BB, where

A=[abc];B=[2a+3ba+2b+4c]A = \begin{bmatrix} a \\ b \\ c \end{bmatrix} ; B = \begin{bmatrix} 2 a + 3 b \\ a + 2 b + 4 c \end{bmatrix}
Answer
T=[230122]T = \begin{bmatrix} 2 & 3 & 0 \\ 1 & 2 & 2 \end{bmatrix}

Verify the following yourself:

[230122][abc]=[2a+3ba+2b+4c]\begin{bmatrix} 2 & 3 & 0 \\ 1 & 2 & 2 \end{bmatrix} \cdot \begin{bmatrix} a \\ b \\ c \end{bmatrix} = \begin{bmatrix} 2 a + 3 b \\ a + 2 b + 4 c \end{bmatrix}

If you are struggling with matrix multiplication remember that Bi,jB_{i, j} comes from sum and product of ithi^{th} row of AA and jthj^{th} column of BB.

Q.2.Q.2. Find a matrix TT such that TA=BT \cdot A = B, where

A=[abc]B=[a+3b2b+3c5a+3b+7c6a]A = \begin{bmatrix} a \\ b \\ c \end{bmatrix} B = \begin{bmatrix} a + 3b \\ 2b + 3c \\ 5a + 3b + 7c \\ 6a \end{bmatrix}
Answer
T=[130023537600]T = \begin{bmatrix} 1 & 3 & 0 \\ 0 & 2 & 3 \\ 5 & 3 & 7 \\ 6 & 0 & 0 \end{bmatrix}

Verify it yourself!

Let us now see a concrete problem that can be solved using Matrix Exponentiation.

Example #1: 509. Fibonacci Number

We can solve the problem using top-down dynamic programming or by bottom-up dynamic programming, but let us see how we can solve it using Matrix Exponentiation first. The recurrence for fibonacci series is:

f(x)={f(x1)+f(x2),x2x,0x1f(x) = \begin{cases} f(x - 1) + f(x - 2), & x \geq 2\\ x, & 0 \leq x \leq 1 \\ \end{cases}

Let us try to find a matrix TT such that

T[f(x)f(x1)]=[f(x+1)f(x)]T \cdot \begin{bmatrix} f(x) \\ f(x - 1) \end{bmatrix} = \begin{bmatrix} f(x + 1) \\ f(x) \end{bmatrix}
Finding T

We can rewrite the above equation as:

T[f(x)f(x1)]=[f(x)+f(x1)f(x)]T \cdot \begin{bmatrix} f(x) \\ f(x - 1) \end{bmatrix} = \begin{bmatrix} f(x) + f(x - 1) \\ f(x) \end{bmatrix}

or even simpler by putting a=f(x)a = f(x) and b=f(x1)b = f(x - 1)

T[ab]=[a+ba]T \cdot \begin{bmatrix} a \\ b \end{bmatrix} = \begin{bmatrix} a + b \\ a \end{bmatrix}

It is now easy to see that T=[1110].T = \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}.

[1110][f(1)f(0)]=[f(2)f(1)]\begin{equation} \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} \cdot \begin{bmatrix} f(1) \\ f(0) \end{bmatrix} = \begin{bmatrix} f(2) \\ f(1) \end{bmatrix} \end{equation} [1110][f(2)f(1)]=[f(3)f(2)]\begin{equation} \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} \cdot \begin{bmatrix} f(2) \\ f(1) \end{bmatrix} = \begin{bmatrix} f(3) \\ f(2) \end{bmatrix} \end{equation}

Using equation (1)(1) and (2)(2) we get,

T(T[f(1)f(0)])=[f(3)f(2)]    (TT)[f(1)f(0)]=[f(3)f(2)]( Matrix multiplication is associative.)T \cdot \begin{pmatrix} T \cdot \begin{bmatrix} f(1) \\ f(0) \end{bmatrix} \end{pmatrix} = \begin{bmatrix} f(3) \\ f(2) \end{bmatrix} \implies (T \cdot T) \cdot \begin{bmatrix} f(1)\\ f(0) \end{bmatrix} = \begin{bmatrix} f(3)\\ f(2) \end{bmatrix} \text{(}\because \text{ Matrix multiplication is associative.)}     T2[f(1)f(0)]=[f(3)f(2)]=[f(1+2)f(0+2)]\implies T^2 \cdot \begin{bmatrix} f(1) \\ f(0) \end{bmatrix} = \begin{bmatrix} f(3) \\ f(2) \end{bmatrix} = \begin{bmatrix} f(1 + 2) \\ f(0 + 2) \end{bmatrix}

From above pattern, we can conclude that,

(T)n[f(1)f(0)]=[f(1+n)f(0+n)](T)^n \cdot \begin{bmatrix} f(1)\\ f(0) \end{bmatrix} = \begin{bmatrix} f(1 + n)\\ f(0 + n) \end{bmatrix}

But this solution is not better than dynamic programming solution which runs in O(n)O(n) time, infact our matrix exponentiation runs in O(n23)O(n \cdot 2^3) time. The extra factor of 232^3 comes from matrix multiplication (Matrix multiplication of two (n×n)(n \times n) matrix takes O(n3)O(n^3) time). To optimise our solution further we can use binary exponentiation to calculate TnT^n in O(log(n)k3)O(log(n) \cdot k^3) time, where kk is the dimension of matrix. In this case k=2k = 2.

Let us see the code for the above idea. Our code can be divided into three broad functions:

S.No.Function NameParameter DescriptionWhat does the function do?
1.multiply(A, B)A,B:A, B: Matrix (2D array/list)Returns a new matrix C=ABC = A \cdot B
2.power(A, exp)A:A: A Square Matrix (2D array/list), exp:exp: integerReturns a new matrix C=AexpC = A^{exp} in O(log(exp))k3O(log(exp)) \cdot k^3 time, where kk is order of matrix
3.fib(n)n:n: integerReturns nthn^{th} term of fibonacci series

Let us implement them one by one. First one is multiply(A, B).

Written by @Ishwarendra
vector<vector<int>> multiply(const vector<vector<int>> A,
const vector<vector<int>> B) {
int n1 = size(A), m1 = size(A[0]);
int n2 = size(B), m2 = size(B[0]);

// If m1 != n2, program will give runtime error
assert(m1 == n2);

vector<vector<int>> C(n1, vector<int>(m2));
for (int i = 0; i < n1; i++) {
for (int j = 0; j < m2; j++) {
for (int k = 0; k < m1; k++) C[i][j] += A[i][k] * B[k][j];
}
}

return C;
}
Written by @Ishwarendra
vector<vector<int>> power(vector<vector<int>> A, int exp) {
int n = size(A), m = size(A[0]);
assert(n == m);

// We need to start with identity matrix because (A^0 = Identity Matrix)
vector res(n, vector<int>(n));
for (int i = 0; i < n; i++) res[i][i] = 1;

while (exp > 0) {
if (exp & 1) res = multiply(res, A);

A = multiply(A, A);
exp >>= 1;
}
return res;
}
Written by @Ishwarendra
int fib(int n) {
vector<vector<int>> T {{1, 1}, {1, 0}};
vector<vector<int>> A {{1}, {0}};

/*
T^n * A = B = {{F(1 + n)},
{F(0 + n)}}
*/
auto B = multiply(power(T, n), A);
return B[1][0];
}

In the given problem it was guaranteed that answer would fit in signed integer range. But if instead of exact number, the problem asked for fib(n)modP,fib(n) \mod P, where P=1e9+7P = 1e9 + 7 then we will have to modify our multiply function so it performs modulo operation while multiplying the numbers.

The only change is in the block inside innermost for-loop\textbf{for-loop}. The following line:

C[i][j] += A[i][k] * B[k][j];

changes to

// Multiplying A[i][k] with 1LL converts it into long long type, 
// which prevents overflow during multiplication.
// Max Value of A[i][k] = P - 1 and max value of B[k][j] = P - 1. Both of them fit in integer range
// But there product doesn't fit in the integer range before we perform modulo operation.
C[i][j] += (1LL * A[i][k] * B[k][j]) % P;
C[i][j] %= P;
  • Time Complexity: O(log(n))O(log(n))
  • Space Complexity: O(1)O(1) as we only made matrices of constant dimension.

Example #2: 1220. Count Vowels Permutation

Let us try to solve this problem using dynamic programming.

f(len,j)=Number of ways to make a string of length len such that it ends with character j,f(len, j) = \text{Number of ways to make a string of length len such that it ends with character j,}, here j{a,e,i,o,u}.j \in \{a, e, i, o, u\}.

If we know the current character then we know which characters can come after it. For example, if our string ends at character ’a’\text{'a'} then we know that the next character is bound to be ’e’\text{'e'}. Simiarly, if our string ends at character ’o’\text{'o'} then the next character must be either ’i’\text{'i'} or ’u’.\text{'u'}.

We try to see the constraints in reverse, i.e., if we want our string of length nn to have jj as its ending character then what all possible string of length (n1)(n - 1) are there which can be extended. Our final answer will be i{a, e, i, o, u}f(n,i)\sum^{i \in \text{\{a, e, i, o, u\}}} f(n, i).

Time Complexity of above solution is O(n)O(n), which can be reduced to O(log(n))O(log(n)) by using matrix exponentiation. Let us see how we can do so. First let us form the recurrence.

f(len,j)={f(len1, e)+f(len, i)+f(i, u) j=af(len1, a)+f(len1, i) j=ef(len1, e)+f(len1, o) j=if(len1, i) j=of(len1, i)+f(len1, o) j=uf(len, j) = \begin{cases} f(len - 1,\ e) + f(len,\ i) + f(i,\ u)\ & j = a\\ f(len - 1,\ a) + f(len - 1,\ i)\ & j = e\\ f(len - 1,\ e) + f(len - 1,\ o)\ & j = i\\ f(len - 1,\ i)\ & j = o\\ f(len - 1,\ i) + f(len - 1,\ o)\ & j = u \end{cases}

One can easily verify the recurrence. For example, if we want our string of length nn to end at character ’i’\text{'i'} then we can only extend strings which ended at character ’e’\text{'e'} or ’o’\text{'o'} and which have length (n1)(n - 1).

Now, we have a linear recurrence. For Let us try to find the matrix TT such that

T[f(len1,a)f(len1,e)f(len1,i)f(len1,o)f(len1,u)]=[f(len,a)f(len,e)f(len,i)f(len,o)f(len,u)]=[f(len1,e)+f(len1,i)+f(len1,u)f(len1,a)+f(len1,i)f(len1,e)+f(len1,o)f(len1,i)f(len1,i)+f(len1,o)]T \cdot \begin{bmatrix} f(len - 1, a) \\ f(len - 1, e) \\ f(len - 1, i) \\ f(len - 1, o) \\ f(len - 1, u) \end{bmatrix} = \begin{bmatrix} f(len, a) \\ f(len, e) \\ f(len, i) \\ f(len, o) \\ f(len, u) \end{bmatrix} = \begin{bmatrix} \begin{array}{l} f(len - 1, e) + f(len - 1, i) + f(len - 1, u)\\ f(len - 1, a) + f(len - 1, i)\\ f(len - 1, e) + f(len - 1, o)\\ f(len - 1, i) \\ f(len - 1, i) + f(len - 1, o) \end{array} \end{bmatrix}
Finding T
T=[0110110100010100010000110]T = \begin{bmatrix} 0 & 1 & 1 & 0 & 1 & \\ 1 & 0 & 1 & 0 & 0 & \\ 0 & 1 & 0 & 1 & 0 & \\ 0 & 0 & 1 & 0 & 0 & \\ 0 & 0 & 1 & 1 & 0 & \end{bmatrix}

If you are unable to see how we came up with matrix TT, then for simplicity let us write f(len1,ch)f(len - 1, ch) as only chch. Now TA=BT \cdot A = B looks as shown below:

T[aeiou]=[e+i+ua+ie+oii+o]T \cdot \begin{bmatrix} a \\ e \\ i \\ o \\ u \end{bmatrix} = \begin{bmatrix} e + i + u \\ a + i \\ e + o \\ i \\ i + o \end{bmatrix}

Our multiply function has one change that was mentioned at the end of last problem (taking modulo at each operation) and the power function remains unchanged.

Written by @Ishwarendra
const int MOD = 1e9 + 7;

int countVowelPermutation(int n) {
vector T(5, vector<int>(5, 0));
T[0][1] = T[0][2] = T[0][4] = 1;
T[1][0] = T[1][2] = 1;
T[2][1] = T[2][3] = 1;
T[3][2] = 1;
T[4][2] = T[4][3] = 1;

// There is 1 way to make string of length-1 whose ending character is fixed.
vector A(5, vector(1, 1));

// Since our base case is string of length-1 so we need T^(n - 1) only to get answer for string of length n = (1 + (n - 1))
auto B = multiply(power(T, n - 1), A);

int ans = 0;
for (int i = 0; i < size(B); i++) {
ans = (ans + B[i][0]) % MOD;
}

return ans;
}
  • Time Complexity: O(log(n)O(log(n)
  • Space Complexity: O(1)O(1) as we have created 2D vector of constant dimension only.

General Advice:

  • You can use matrix exponentiation only if the recurrence is linear and has constant coefficients.
  • Matrix exponentiation can often be used as an optimisation for dynamic programming solutions. Again check if the recurrence formed is linear with constant coefficients or not!.

Suggested Problems

Problem NameDifficultySolution Link
1137. N-th Tribonacci NumberEasyView Solutions