NumPy对称矩阵数组与Voigt记号双向转换的高效实现方法
批量3×3对称矩阵与Voigt记号双向转换最优实现
最高效的实现方案是预定义固定索引+NumPy原生高级索引,全程无Python层循环,无多余计算和内存拷贝,性能远高于循环、einsum、三角提取等其他方案,且兼容任意多维度的批量输入。
首先明确形状约定:
- 原始堆叠对称矩阵数组形状为
(..., 3, 3),前面的...可以是任意数量的批量维度(比如N个矩阵就是(N,3,3),多批次就是(B,N,3,3)) - 目标Voigt格式数组形状为
(..., 6),单组顺序严格匹配需求:[a11, a22, a33, a12, a23, a31]
3×3对称矩阵转Voigt格式
索引映射关系是固定的,提前定义一次索引即可反复调用,无重复计算开销:
import numpy as np # 预定义索引:对应Voigt每个位置在原矩阵中的(i,j)坐标 _MAT_TO_VOIGT_IDX = (..., [0, 1, 2, 0, 1, 2], [0, 1, 2, 1, 2, 0]) def mat_to_voigt(mat_arr: np.ndarray) -> np.ndarray: # 可选形状校验 if mat_arr.shape[-2:] != (3, 3): raise ValueError("输入数组最后两维必须为3×3矩阵") return mat_arr[_MAT_TO_VOIGT_IDX]
Voigt格式转回3×3对称矩阵
同样提前写死每个矩阵位置对应的Voigt索引,直接向量化映射即可,自动保证对称性:
# 预定义映射表:mat_map[i,j]存的是3x3矩阵(i,j)位置对应的Voigt数组索引 _VOIGT_TO_MAT_MAP = np.array([ [0, 3, 5], [3, 1, 4], [5, 4, 2] ]) def voigt_to_mat(voigt_arr: np.ndarray) -> np.ndarray: # 可选形状校验 if voigt_arr.shape[-1] != 6: raise ValueError("输入数组最后一维必须为长度6的Voigt序列") return voigt_arr[..., _VOIGT_TO_MAT_MAP]
性能说明
- 所有操作均在NumPy C层执行,哪怕是百万级批量矩阵的转换,也能在数毫秒内完成
- 无多余临时内存开销,转换过程仅申请最终结果需要的内存空间
- 自动兼容任意前置批量维度,不需要针对不同输入形状修改代码
- 索引硬编码完全匹配需求的Voigt顺序,不会出现顺序错配问题
测试验证
if __name__ == "__main__": # 构造2个测试对称矩阵 test_mat = np.array([ [[1, 2, 3], [2, 4, 5], [3, 5, 6]], [[7, 8, 9], [8, 10, 11], [9, 11, 12]] ]) # 转Voigt voigt_res = mat_to_voigt(test_mat) print("Voigt转换结果:\n", voigt_res) # 输出: # [[ 1 4 6 2 5 3] # [ 7 10 12 8 11 9]] # 完全匹配[a11,a22,a33,a12,a23,a31]的顺序要求 # 转回矩阵 recover_mat = voigt_to_mat(voigt_res) print("转换回矩阵与原矩阵是否一致:", np.allclose(recover_mat, test_mat)) # 输出:True
不推荐使用逐元素循环、三角矩阵提取、einsum映射等方案:这类方案要么存在Python层循环开销,要么存在多余计算步骤,性能比直接索引方案低1~2个数量级。
内容的提问来源于stack exchange,提问作者Odirlei Santana
相关产品推荐
相关产品推荐

