一、基础问题
1. 如何实现两个矩阵的乘法?
问题描述:给定两个矩阵
A
A
A和
B
B
B,编写代码实现矩阵乘法。
解法:
使用三重循环实现标准矩阵乘法。
或者使用 NumPy 的 dot 方法进行高效计算。
def matrix_multiply(A, B):
m, n = len(A), len(A[0])
n, p = len(B), len(B[0])
C = [[0 for _ in range(p)] for _ in range(m)]
for i in range(m):
for j in range(p):
for k in range(n):
C[i][j] += A[i][k] * B[k][j]
return C
扩展问题:
如果矩阵维度不匹配(如
A
A
A是
m
m
m×
n
n
n,B是
p
p
p×
q
q
q,且
n
n
n≠p),如何处理?
答案:抛出异常或返回错误提示。
处理方法如下:
- 填充或截断:适用于矩阵加法、减法等需要维度一致的操作。
- 转置或调整维度:适用于矩阵乘法等需要特定维度匹配的操作。
- 降维或升维:适用于数据预处理或特征提取。
- 广播机制:适用于逐元素操作。
- 稀疏矩阵:适用于大规模稀疏数据。
2. 矩阵乘法的时间复杂度是多少?
答案:
标准矩阵乘法的时间复杂度为
O
O
O(
m
m
mx
n
n
nx
p
p
p),其中
A
A
A是
m
m
m×
n
n
n,B是
n
n
n×
p
p
p。
Strassen 算法的时间复杂度为
O
O
O(
A
log
2
7
A^{\log_{2}7}
Alog27)
≈
\approx
≈
O
O
O(
n
2.81
n^{2.81}
n2.81)。
扩展问题:
如何优化矩阵乘法以提高性能?
答案:分块矩阵乘法、使用 BLAS 库、GPU 加速等。
二、进阶问题
1. 如何判断一个矩阵是否可以与另一个矩阵相乘?
问题描述:给定两个矩阵
A
A
A和
B
B
B,判断它们是否可以相乘。
解法:
检查
A
A
A的列数是否等于
B
B
B的行数。
def can_multiply(A, B):
return len(A[0]) == len(B)
2. 如何实现稀疏矩阵的乘法?
问题描述:稀疏矩阵中大部分元素为零,如何高效地实现矩阵乘法?
解法:
只存储非零元素及其位置(如使用字典或压缩稀疏行格式 CSR)。
在乘法过程中跳过零元素。
def sparse_matrix_multiply(A, B):
# 假设 A 和 B 是稀疏矩阵,用字典表示
result = {}
for (i, k), a_val in A.items():
for (k2, j), b_val in B.items():
if k == k2:
result[(i, j)] = result.get((i, j), 0) + a_val * b_val
return result
3. 如何实现矩阵的幂运算?
问题描述:给定一个方阵
A
A
A和整数n,计算
解法:
使用快速幂算法(Binary Exponentiation)。
import numpy as np
def matrix_power(A, n):
result = np.eye(len(A)) # 单位矩阵
base = np.array(A)
while n > 0:
if n % 2 == 1:
result = np.dot(result, base)
base = np.dot(base, base)
n //= 2
return result
三、高级问题
1. 如何实现 Strassen 矩阵乘法?
问题描述:使用 Strassen 算法实现矩阵乘法。
解法:
将矩阵递归分割成四个子矩阵,通过 7 次递归乘法和若干加减法完成计算。
def strassen_multiply(A, B):
n = len(A)
if n == 1:
return [[A[0][0] * B[0][0]]]
mid = n // 2
A11, A12, A21, A22 = split_matrix(A)
B11, B12, B21, B22 = split_matrix(B)
P1 = strassen_multiply(A11, subtract_matrix(B12, B22))
P2 = strassen_multiply(add_matrix(A11, A12), B22)
P3 = strassen_multiply(add_matrix(A21, A22), B11)
P4 = strassen_multiply(A22, subtract_matrix(B21, B11))
P5 = strassen_multiply(add_matrix(A11, A22), add_matrix(B11, B22))
P6 = strassen_multiply(subtract_matrix(A12, A22), add_matrix(B21, B22))
P7 = strassen_multiply(subtract_matrix(A11, A21), add_matrix(B11, B12))
C11 = add_matrix(subtract_matrix(add_matrix(P5, P4), P2), P6)
C12 = add_matrix(P1, P2)
C21 = add_matrix(P3, P4)
C22 = subtract_matrix(subtract_matrix(add_matrix(P5, P1), P3), P7)
return merge_matrix(C11, C12, C21, C22)
def split_matrix(M):
mid = len(M) // 2
return [row[:mid] for row in M[:mid]], [row[mid:] for row in M[:mid]], \
[row[:mid] for row in M[mid:]], [row[mid:] for row in M[mid:]]
def merge_matrix(C11, C12, C21, C22):
return [C11[i] + C12[i] for i in range(len(C11))] + [C21[i] + C22[i] for i in range(len(C21))]
2. 如何利用 GPU 加速矩阵乘法?
问题描述:如何在 Python 中利用 GPU 加速矩阵乘法?
解法:
使用 CuPy 或 PyTorch 实现。
CuPy 实现:
import cupy as cp
def gpu_matrix_multiply(A, B):
A_gpu = cp.array(A)
B_gpu = cp.array(B)
C_gpu = cp.dot(A_gpu, B_gpu)
return cp.asnumpy(C_gpu)
PyTorch实现:
import time
# 创建更大的矩阵以突出性能差异
A = torch.randn(5000, 5000)
B = torch.randn(5000, 5000)
# CPU 计算
start_time = time.time()
C_cpu = torch.matmul(A, B)
cpu_time = time.time() - start_time
print(f"CPU 时间: {cpu_time:.4f} 秒")
# GPU 计算
A_gpu = A.to(device)
B_gpu = B.to(device)
start_time = time.time()
C_gpu = torch.matmul(A_gpu, B_gpu)
gpu_time = time.time() - start_time
print(f"GPU 时间: {gpu_time:.4f} 秒")
# 验证结果一致性
assert torch.allclose(C_cpu, C_gpu.cpu()), "结果不一致!"
print("CPU 和 GPU 结果一致!")
四、综合问题
1. 如何验证矩阵乘法的正确性?
问题描述:给定两个矩阵
A
A
A和
B
B
B,以及结果矩阵
C
C
C,如何验证
C
C
C=
A
A
A⋅
B
B
B 是否正确?
解法:
计算
A
A
A⋅
B
B
B 并与
C
C
C 对比。
def verify_matrix_multiply(A, B, C):
computed_C = np.dot(A, B)
return np.allclose(computed_C, C)
2. 如何实现矩阵链乘法的最优括号化?
问题描述:给定一组矩阵,找到一种括号化顺序,使得矩阵链乘法的计算代价最小。
解法:
使用动态规划解决矩阵链乘法问题。
def matrix_chain_order(dimensions):
n = len(dimensions) - 1
dp = [[0] * n for _ in range(n)]
split = [[0] * n for _ in range(n)]
for length in range(2, n + 1):
for i in range(n - length + 1):
j = i + length - 1
dp[i][j] = float('inf')
for k in range(i, j):
cost = dp[i][k] + dp[k+1][j] + dimensions[i] * dimensions[k+1] * dimensions[j+1]
if cost < dp[i][j]:
dp[i][j] = cost
split[i][j] = k
return dp[0][n-1], split