实现科拉兹猜想(3X+1)动画情节时的思考与疑问

Thoughts and question when implementing animation plot of Collatz Conjecture (3X+1)

感谢 Veritasium 关于该主题的精彩视频,我正计划快速复制他在视频中展示的动画,其中数字上下跳动直到达到数字 1,具体取决于初始数字。

下面我想出了一个实现动画的代码版本。但是我在构建代码的过程中有一个疑问和困惑。

我发现如果我不将 y 数据初始化为 y=np.empty(100) 而不是空列表,它会抛出错误 list assignment index out of range

所以我很困惑为什么我不能从空列表开始,因为我知道,根据 y_start 的值,len(y) 会有所不同。如果我可以将那些计算出的 y 值收集到一个列表中(稍后将它们转换成数组),那么我就不必去整个夜场设置 plt.xlim(1,100)(相反,我可以只设置 plt.xlim(0,len(y))还由于最终 y 数据中可能剩余 0.0 值,我必须在 if 语句中添加附加条件(and 之后的第 2 个)-> if y[i] % 2 == 0 and y[i] != 0: 否则,即使达到 y 后它也会失控值 1....

此外,我想添加显示在每个单独点之上的 y 数据的值,但我不知道如何在代码中实现它...如果有人能提供帮助,我将不胜感激这个问题让动画看起来更“完整”!

这是我测试过的代码

import numpy as np
from matplotlib.animation import FuncAnimation
from matplotlib import pyplot as plt

def odd(num):
    return (num*3)+1

def even(num):
    return num // 2

y_start = 33
x = np.linspace(0, 100, 100)
# y = []
def collatz():
    y = np.empty(100)
    y[0] = y_start
    for i in range(0,100):
            if y[i] % 2 == 0 and y[i] != 0:
                y[i+1] = even(y[i])
            else:
                y[i+1] = odd(y[i])
            if y[i+1] == 1:
                break
    return y

y = collatz()

fig = plt.figure()
plt.xlim(1,100)
plt.ylim(1,max(y))

draw, = plt.plot([],[])
def update(idx):
    draw.set_data(x[:idx], y[:idx])
    return draw,

a = FuncAnimation(fig, update, frames=len(x), interval=90)
plt.show()

所以,我的问题是,

为什么从空列表开始包含计算的 y 失败?

此外,在早期版本中,在 collatz 函数定义中,我的代码如下:

def collatz():
    y = np.empty(100)
    y[0] = y_start
    for i in range(0,100):
        while y[i] != 1:
            if y[i] % 2 == 0 and y[i] != 0:
                y[i+1] = even(y[i])
            else:
                y[i+1] = odd(y[i])
        if y[i+1] == 1:
            break
    return y

编译卡死,代码似乎在无限循环...我不知道,是 while statement 的用法吗?我应该如何 do/add 来纠正它?

我已经重写了您的代码(在我的机器上可以运行),并会尽力回答您的问题

您不能从 y 的空列表开始,因为 collatz() 函数需要一个起点。因此,如果 y 为空,则无从开始,函数失败。在下面的新代码中,我向您的函数添加了一个参数 start(在代码中:49)。现在这是您函数的新起点。请注意,如果您想要一个随机起点而不是您定义的起点,您可以删除开始,并将 y = [start] 替换为 y = [int(np.random.randint(1, 100, 1))] 或其他绘制随机整数的代码。

现在 collat​​z 使用 while 循环:只要 y 大于 1,它就会工作(因此当 y = 0 或 1 时它会停止)。请注意,-1 运算符表示 'the last element added to y'。对于每个数字,它执行 even()odd() 函数,然后使用 append 将数字添加到列表中。这确保了列表的长度只在需要的时候。请注意,在这种情况下,while 循环是最佳选择,因为您不知道循环将持续多长时间。当你有固定的迭代次数时,应该选择for循环。

最后根据y的长度确定x

from matplotlib.animation import FuncAnimation
from matplotlib import pyplot as plt

def odd(num):
    return (num*3)+1

def even(num):
    return num // 2

def collatz(start):
    y = [start]
    while y[-1] > 1:
            if y[-1] % 2 == 0:
                y.append(even(y[-1]))
            else:
                y.append(odd(y[-1]))

    return y

y = collatz(49)
x = list(range(len(y)))

fig = plt.figure()
plt.xlim(1,len(y))
plt.ylim(1,max(y))

draw, = plt.plot([],[])
def update(idx):
    draw.set_data(x[:idx], y[:idx])
    return draw

a = FuncAnimation(fig, update, frames=len(x), interval=90)
plt.show()