实现科拉兹猜想(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))]
或其他绘制随机整数的代码。
现在 collatz 使用 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()
感谢 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))]
或其他绘制随机整数的代码。
现在 collatz 使用 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()