Matlab可交换超复数类如何重载基础函数实现逐元素运算?
项目背景
我正在编写**可交换超复数(commutative hypercomplex number)**类。
首先说明:若已有相关实现,请告知。 我暂未找到对应实现,注:四元数(Quaternion)已有官方实现,但不具备交换性。
我希望复刻Matlab对实数、复数的全部操作能力,将其扩展到超复数场景。目前我采用自定义类的方案实现,若有更优的实现方法,欢迎告知。
现有大量面向复数的代码,我的核心目标是通过合理的运算符重载,让这些现有程序无需修改即可适配超复数运算,该成果可服务于大量相关领域开发者。
本实现的核心数学原理参考Ablamowicz1996年发表的《Clifford Algebras with Numeric and Symbolic Computations》。
现有实现进展
目前我的超复数类已支持基础运算:我已重载了mtimes(a,b) = a*b操作,示例如下:
A = MyClass(1); B = MyClass(2); A*B; % ->可正常运行
核心问题
我遇到的核心问题是:例如在2D场景下,我希望能够运行[A B C].*[D ; E]这类运算,同时兼容Matlab原生的逐元素运算规则,支持任意维度的兼容尺寸数组运算,且采用我自定义的*运算规则。例如针对尺寸兼容但不相等的矩阵:
A = [1 2 3]; B = [1;2]
原生Matlab运行结果为:
A.*B ans = 1 2 3 2 4 6
该规则在N维数组尺寸兼容时同样生效。请问我该如何重载times(a,b) = a.*b、power、rdivide等函数,实现和原生Matlab一致的逐元素运算行为?
现有代码
以下是我当前的类实现代码:
classdef Hypercomplex < handle properties (SetAccess = public, GetAccess = public) A end properties (SetAccess = private, GetAccess = private) eps,nu,e1,e2 end methods function s = Hypercomplex(Z) %% 构造函数 % Z可为实数、复数或超复数 if isa(Z,'Hypercomplex') % 输入为超复数 s = Z; elseif ~isreal(Z) && length(Z) == 1 % 输入为复数 s = Hypercomplex([real(Z) imag(Z) 0 0]); elseif isreal(Z) && length(Z) < 5 s.A = zeros(1,4); for ii = 1:length(Z) % 输入为向量 s.A(ii) = Z(ii); end end end function s = epsnu(s) s.eps = (s.A(1) - s.A(4)) + 1i*(s.A(2)+s.A(3)); s.nu = (s.A(1) + s.A(4)) + 1i*(s.A(2)-s.A(3)); end function s = e1e2(s) s.e1 = Hypercomplex([0.5 0 0 -0.5]); s.e2 = Hypercomplex([0.5 0 0 0.5]); end %% 重载函数 function out = cos(a) a.epsnu.e1e2; out = cos(a.eps)*a.e1 + cos(a.nu)*a.e2; % 后续还可实现sin、exp、sqrt等函数 end function out = mtimes(a,b) % '*'运算符 a = Hypercomplex(a).epsnu; b = Hypercomplex(b).epsnu; eps12 = 0.5*(a.eps * b.eps);% 复数乘法 nu12 = 0.5*(a.nu * b.nu );% 复数乘法 h1 = Hypercomplex([real(eps12) imag(eps12) imag(eps12) -real(eps12)]); h2 = Hypercomplex([real(nu12) imag(nu12) -imag(nu12) real(nu12) ]); out = h1+h2; end function out = mrdivide(a,b) a = Hypercomplex(a); b = Hypercomplex(b); out = a * b.inverse; end function s = inverse(s) s = Hypercomplex(s).epsnu.e1e2; s = 1/(s.eps)*s.e1 + 1/(s.nu)*s.e2; end function out = plus(a,b) a = Hypercomplex(a); b = Hypercomplex(b); out = Hypercomplex(a.A + b.A); end function out = minus(a,b) a = Hypercomplex(a); b = Hypercomplex(b); out = Hypercomplex(a.A - b.A); end end end
运算示例
运算示例(i^2 = -1):
>> Ni = Hypercomplex([0 1 0 0]) ; >> Ni*Ni Hypercomplex with properties: A: [-1 0 0 0]

你可以借助Matlab内置的数组隐式扩展机制,结合逐元素调用已实现的标量超复数运算逻辑,实现符合原生规则的逐元素运算符重载,具体实现方案如下:
重载times函数(对应.*运算符)
在类的methods块中添加如下代码即可直接使用,该实现会自动适配Matlab原生的隐式尺寸扩展规则,支持任意维度兼容的数组运算,且复用你已写好的超复数乘法逻辑,无需重复开发数学计算部分:
function out = times(a,b) % 统一将输入转为Hypercomplex类型的元胞数组,支持混合实数、复数输入 a = arrayfun(@Hypercomplex, a, 'UniformOutput', false); b = arrayfun(@Hypercomplex, b, 'UniformOutput', false); % 逐元素调用已实现的mtimes标量乘法,自动匹配尺寸扩展规则 out = cell2mat(arrayfun(@(x,y) mtimes(x{1}, y{1}), a, b, 'UniformOutput', false)); end
重载其他逐元素运算符
其余power(对应.^)、rdivide(对应./)等运算符的重载逻辑完全一致,只需替换内部调用的运算函数即可:
重载power函数示例
function out = power(a, b) a = arrayfun(@Hypercomplex, a, 'UniformOutput', false); b = arrayfun(@Hypercomplex, b, 'UniformOutput', false); % 逐元素调用你后续实现的超复数标量幂运算函数即可 out = cell2mat(arrayfun(@(x,y) hypercomplex_pow(x{1}, y{1}), a, b, 'UniformOutput', false)); end
重载rdivide函数示例
function out = rdivide(a, b) a = arrayfun(@Hypercomplex, a, 'UniformOutput', false); b = arrayfun(@Hypercomplex, b, 'UniformOutput', false); % 直接复用已实现的mrdivide标量除法逻辑 out = cell2mat(arrayfun(@(x,y) mrdivide(x{1}, y{1}), a, b, 'UniformOutput', false)); end
性能优化建议
如果需要提升高维数组的运算效率,可以将arrayfun遍历逻辑替换为向量化操作,直接对所有超复数实例的A属性批量计算,避免循环开销。
内容的提问来源于stack exchange,提问作者ApneaDeepBlue

