Skip to content

Matrix Power

Compute arbitrary matrix powers \(A^p\) including fractional exponents.

Mental Model

Fractional matrix powers generalize the idea of "square root of a matrix" to arbitrary exponents. If \(A = V \Lambda V^{-1}\), then \(A^p = V \Lambda^p V^{-1}\) -- each eigenvalue is raised to the power \(p\). This lets you smoothly interpolate between the identity (\(A^0\)) and the matrix itself (\(A^1\)), which is useful in diffusion processes, interpolation, and numerical methods.

linalg.fractional_matrix_power

1. Basic Usage

```python import numpy as np from scipy import linalg

def main(): A = np.array([[4, 0], [0, 9]])

# A^{0.5} = sqrt(A)
A_half = linalg.fractional_matrix_power(A, 0.5)

print("A =")
print(A)
print()
print("A^{0.5} =")
print(A_half)

if name == "main": main() ```

2. Various Powers

```python import numpy as np from scipy import linalg

def main(): A = np.array([[2, 1], [0, 3]])

powers = [-1, -0.5, 0, 0.5, 1, 2]

for p in powers:
    A_p = linalg.fractional_matrix_power(A, p)
    print(f"A^{p:4.1f} =")
    print(A_p.real.round(4))
    print()

if name == "main": main() ```

3. Verify A^p @ A^q = A^{p+q}

```python import numpy as np from scipy import linalg

def main(): A = np.array([[2, 1], [1, 2]])

p, q = 0.3, 0.7

A_p = linalg.fractional_matrix_power(A, p)
A_q = linalg.fractional_matrix_power(A, q)
A_pq = linalg.fractional_matrix_power(A, p + q)

print(f"A^{p} @ A^{q} =")
print((A_p @ A_q).real.round(6))
print()
print(f"A^{p+q} =")
print(A_pq.real.round(6))

if name == "main": main() ```

Special Cases

1. Integer Powers

```python import numpy as np from scipy import linalg

def main(): A = np.array([[1, 2], [3, 4]])

# Integer power via fractional_matrix_power
A_3 = linalg.fractional_matrix_power(A, 3)

# Direct computation
A_3_direct = A @ A @ A

print("A³ via fractional_matrix_power:")
print(A_3.real.round(6))
print()
print("A³ direct:")
print(A_3_direct)

if name == "main": main() ```

2. Negative Powers

```python import numpy as np from scipy import linalg

def main(): A = np.array([[2, 1], [1, 2]])

# A^{-1}
A_inv = linalg.fractional_matrix_power(A, -1)

# Verify
print("A^{-1} @ A =")
print((A_inv @ A).real.round(10))

if name == "main": main() ```

3. Zero Power

```python import numpy as np from scipy import linalg

def main(): A = np.array([[1, 2], [3, 4]])

# A^0 = I
A_0 = linalg.fractional_matrix_power(A, 0)

print("A^0 =")
print(A_0.real.round(10))

if name == "main": main() ```

Applications

1. Matrix Interpolation

```python import numpy as np from scipy import linalg

def main(): A = np.array([[1, 0], [0, 1]]) B = np.array([[4, 0], [0, 9]])

# Interpolate: C(t) = A^{1-t} @ B^t
for t in [0, 0.25, 0.5, 0.75, 1.0]:
    A_1mt = linalg.fractional_matrix_power(A, 1-t)
    B_t = linalg.fractional_matrix_power(B, t)
    C_t = A_1mt @ B_t
    print(f"t={t}: diag = {np.diag(C_t.real).round(2)}")

if name == "main": main() ```

2. Diffusion Process

```python import numpy as np from scipy import linalg

def main(): # Transition matrix P = np.array([[0.7, 0.3], [0.4, 0.6]])

# Fractional steps
for t in [0.5, 1, 2, 10]:
    P_t = linalg.fractional_matrix_power(P, t)
    print(f"P^{t} =")
    print(P_t.real.round(4))
    print()

if name == "main": main() ```

Summary

Function Description
linalg.fractional_matrix_power(A, p) Compute \(A^p\)

Key: Works for any real \(p\). Uses principal branch for non-integer powers.


Exercises

Exercise 1. Compute \(A^{1/3}\) (the cube root) for \(A = \begin{pmatrix} 8 & 0 \\ 0 & 27 \end{pmatrix}\) using fractional_matrix_power. Verify the result by cubing it: check that \((A^{1/3})^3 \approx A\) with Frobenius norm error below \(10^{-10}\).

Solution to Exercise 1
import numpy as np
from scipy import linalg

A = np.array([[8, 0],
               [0, 27]], dtype=float)

A_third = linalg.fractional_matrix_power(A, 1/3)
A_cubed = A_third @ A_third @ A_third

error = np.linalg.norm(A_cubed.real - A)
print(f"A^(1/3) =\n{A_third.real.round(6)}")
print(f"(A^(1/3))^3 =\n{A_cubed.real.round(6)}")
print(f"Error: {error:.2e}")
assert error < 1e-10

Exercise 2. For the matrix \(A = \begin{pmatrix} 2 & 1 \\ 1 & 3 \end{pmatrix}\), verify the power law \(A^p \cdot A^q = A^{p+q}\) for \(p = 0.4\) and \(q = 0.6\). Print the Frobenius norm of the difference between the two sides.

Solution to Exercise 2
import numpy as np
from scipy import linalg

A = np.array([[2, 1],
               [1, 3]], dtype=float)
p, q = 0.4, 0.6

Ap = linalg.fractional_matrix_power(A, p)
Aq = linalg.fractional_matrix_power(A, q)
Apq = linalg.fractional_matrix_power(A, p + q)

product = Ap @ Aq
error = np.linalg.norm(product.real - Apq.real)
print(f"A^{p} @ A^{q} =\n{product.real.round(8)}")
print(f"A^{p+q} =\n{Apq.real.round(8)}")
print(f"Difference norm: {error:.2e}")

Exercise 3. Create a \(3 \times 3\) transition matrix \(P = \begin{pmatrix} 0.8 & 0.1 & 0.1 \\ 0.2 & 0.7 & 0.1 \\ 0.1 & 0.2 & 0.7 \end{pmatrix}\). Compute \(P^{0.5}\) (the "half-step" transition matrix) and verify that each row sums to 1 and all entries are non-negative (a valid stochastic matrix).

Solution to Exercise 3
import numpy as np
from scipy import linalg

P = np.array([[0.8, 0.1, 0.1],
               [0.2, 0.7, 0.1],
               [0.1, 0.2, 0.7]])

P_half = linalg.fractional_matrix_power(P, 0.5).real

row_sums = P_half.sum(axis=1)
all_nonneg = np.all(P_half >= -1e-10)
print(f"P^0.5 =\n{P_half.round(6)}")
print(f"Row sums: {row_sums.round(10)}")
print(f"All rows sum to 1: {np.allclose(row_sums, 1)}")
print(f"All entries non-negative: {all_nonneg}")