在numpy中实现奇特的复数

2 投票
3 回答
1290 浏览
提问于 2025-04-17 05:01

我正在使用 Python、NumPy 和 SciPy 对一个复杂数字数组进行卷积滤波。

field = np.zeros((field_size, field_size), dtype=complex)
...
field = scipy.signal.convolve(field, kernel, 'same')

所以,当我想在 NumPy 中使用复杂数组时,只需要传入 dtype=complex 这个参数就可以了。为了我的研究,我需要实现另外两种复杂数字类型:一种是双重(i*i=0),另一种是双倍(i*i=1)。这并不难——我只需要拿到 Python 的复杂数字源代码,然后修改一下乘法函数就行了。问题是:我该如何创建一个包含这些特殊数字类型的 NumPy 数组呢?

3 个回答

0

把东西翻转过来会有效吗?我的意思是,通常我们用一个数组作为外层容器,里面放着小容器,这些小容器里装着几个浮点数,表示一个复数。现在我们把这个思路反过来,把复数当作外层容器。这样的话,你就会有两个数组,一个存放实部的浮点数,另一个存放虚部的浮点数。基本的快速卷积器还是能正常工作,不过你需要写代码来处理四种情况,分别是两个因子的实部和虚部的所有组合。

在处理彩色图像时,我经常把代码从使用RGB值的数组重构为三个标量值的数组,这样做让我发现速度提升了很多,因为在字节或浮点数数组上进行卷积和其他操作要简单得多,速度也快。

你的情况可能会有所不同,因为复数(或颜色)的组成部分的局部性可能很重要。

4

看起来你想为双数(dual numbers)创建一种新的数据类型。你可以用下面的代码来实现:

dual_type = np.dtype([("a", np.float), ("b", np.float)])
dual_array = np.zeros((10,), dtype=dual_type)

不过这只是存储数据类型的一种方式,并没有告诉numpy关于它所遵循的特殊代数规则。

你可以通过继承 numpy.ndarray 类,并重写一些相关的成员函数,比如乘法的 __mul__,来部分实现你想要的效果。这在任何Python代码中应该都能正常工作,但我比较确定,任何基于C或Fortran的程序(也就是大部分的numpy和scipy)会直接进行数字相乘,而不是调用 __mul__。我怀疑 convolve 也会这样,所以除非你自己写一个纯Python版本,否则它不会遵循你定义的规则。

1

这是我的解决方案:

from iComplex import SplitComplex as c_split
...
ctype = c_split
constructor = np.vectorize(ctype, otypes=[np.object])
field = constructor(np.zeros((field_size, field_size)))

这是一种简单的方法来创建numpy对象数组。至于scipy.signal.convolve,它似乎不支持我的复数,所以我不得不自己写一个卷积的函数,但速度非常慢。因此,我现在在寻找加快速度的方法。

撰写回答