NumPy中的数组表示法数组不明确

c9qzyr3d  于 2022-11-10  发布在  其他
关注(0)|答案(1)|浏览(152)

我正在理解一种计算(和绘制)Julia集的矢量化方法。在网上,我找到了以下代码(注解主要是我的,基于我对代码背后思想的日益加深的理解):

import numpy as np
import matplotlib.pyplot as plt

c = -0.74543+0.11301j                                           # Example value for this picture (Julia set)
n = 512                                                         # Maximum number of iterations

x = np.linspace(-1.5, 1.5, 2000).reshape((1, 2000))             # 1 row, 2000 columns
y = np.linspace(-1.2, 1.2, 1600).reshape((1600, 1))             # 1600 rows, 1 column
z = x + 1j*y                                                    # z is an array with 1600 * 2000 complex entries

c = np.full(z.shape, c)             # c is a complex number matrix to be added for the iteration

diverge = np.zeros(z.shape)         # 1600 * 2000 zeroes (0s), contains divergent iteration counts
m = np.full(z.shape, True)          # 1600 * 2000 True, used as a kind of mask (convergent values)

for i in range(0,n):          # Do at most n iterations
    z[m] = z[m]**2 + c[m]     # Matrix op: Complex iteration for fixed c (Julia set perspective)
    m[np.abs(z) > 2] = False  # threshold for convergence of absolute(z) is 2
    diverge[m] = i

plt.imshow(diverge, cmap='magma')   # Color map "magma" applied to the iterations for each point
plt.show()                          # Display image plotted

我不理解diverge[m] = i行的原理,我猜m是一个1600*2000元素的布尔数组。似乎m被用作一种掩码,只允许Diverge[]中m中相应元素为True的那些值成立。然而,我想更详细地理解这个概念。语法diverge[m] = i似乎意味着一个数组被用作另一个数组(分歧)的某种广义“索引”,我可能需要一些帮助来理解这个概念。(代码按预期运行,我只是在理解它的工作原理时遇到了问题。)
谢谢。

rn0zuynd

rn0zuynd1#

是的,您可以使用一个数组来索引另一个数组。在很多很多方面。这是一件复杂的事情。即使我自以为是地理解了NumPy,有时我仍然会在理解之前对数组进行索引,这会让我有点抓狂。
但这个案子并不是很复杂

M=np.array([[1,2,3], 
            [4,5,6],
            [7,8,9]])
msk=np.array([[True,  False,  True],
              [True,  True,   True],
              [False, True,   False]])
M[msk]

返回array([1, 3, 4, 5, 6, 8])。我相信,你可以很容易地理解其中的逻辑。
但更重要的是,指数化是一个l值。这意味着M[msk]可以在=的左侧。然后M的值受到影响
所以,这意味着

M[msk]=0
M

展示会

array([[0, 2, 0],
       [0, 0, 0],
       [7, 0, 9]])

同样,

M=np.array([[1,2,3], 
            [4,5,6],
            [7,8,9]])
A=np.array([[2,2,4],
            [4,6,6],
            [8,8,8]])
msk=np.array([[True,  False,  True],
              [True,  True,   True],
              [False, True,   False]])
M[msk] = M[msk]+A[msk]
M

结果是

array([[ 3,  2,  7],
       [ 8, 11, 12],
       [ 7, 16,  9]])

所以回到你的案子上来,

z[m] = z[m]**2 + c[m]     # Matrix op: Complex iteration for fixed c (Julia set perspective)

不知何故只是一种优化。您也可以只使用z=z**2+c。但为什么即使在已经发生溢出的地方也要进行计算呢?因此,它只在还没有溢出的地方计算z=z**2+c

m[np.abs(z) > 2] = False  # threshold for convergence of absolute(z) is 2

np.abs(s)>2是True/False值的二维数组。对于|z|>2的每个“像素”,m被设置为FALSE。M的其他值保持不变。因此,如果它们已经是假的,它们仍然是假的。请注意,这个有点过于复杂。由于前一行的原因,z在变为>2后不会改变,因此实际上,在np.abs(z)<=2m已经为FALSE的地方没有像素。所以

m=np.abs(z)<=2

也会奏效的。而且它也不会更慢,因为原始版本无论如何都会进行计算。事实上,它会更快,因为我们省去了索引/影响操作。在我的电脑上,我的版本比原始版本快1.3秒(计算时间为12秒)。因此约为10%。)但原始版本的优点是使下一行更容易理解,因为它明确了一点:M从所有True值开始,然后只要算法运行,一些值就会变成False,但没有一个永远不会再次成为True。

diverge[m] = i

M是尚未发散的像素的掩码(它以所有True开始,只要我们迭代,就会有越来越多的m值为False)。因此,这样做,UPDATE DISTURE to i Everywhere都没有出现分歧(变量的名称不是最相关的)。
因此,其z值在迭代50处变为>2的像素,因此其m值在迭代50处变为假的像素将通过这条线被更新为1,然后是2,然后是3,然后是4,...,然后是48,然后是49。但不是50,51,..。
所以最后,留在“分歧”中的是最后一个i,对于它,m仍然为真。这是算法仍在收敛的最后一个i。或者,在1个单位班次时,算法有分歧的第一个单位。

相关问题