0

我正在研究关于 Jacobsthal 序列 (A001045) 以及如何将它们视为由一些不同的子序列组成的论文。我已经对 A077947 发表了评论,表明了这一点,并包含了一个 python 程序。不幸的是,编写的程序还有很多不足之处,所以我当然想求助于 Stack 看看这里是否有人知道如何改进代码!

这是代码:

a=1
b=1
c=2
d=5
e=9
f=18
for x in range(0, 100):
  print(a, b, c, d, e, f)
  a = a+(36*64**x)
  b = b+(72*64**x)
  c = c+(144*64**x)
  d = d+(288*64**x)
  e = e+(576*64**x)
  f = f+(1152*64**x) 

我解释这背后的原因如下:

序列A077947由6个数字保根序列拼接而成;根据 Python 代码,这些序列从种子值 af 开始。计算给定 A077947 a(n) 所需的迭代次数约为 n/6。执行时的代码将返回 A077947 的所有值,直到 range(x),或 A077947 的 ~x*6 项。我发现重复的数字根很有趣,因为我在序列中寻找周期性的数字根保存作为识别数据中模式的方法。例如,在估计需要维护的大型 IT 生态系统(mod7 环境)中警报的真假状态时,数字根保留序列可以对大型数据集进行时间序列分析;这种分析也与预测消费者需求/行为模式有关。采用这些分析方法,将 A077947 雕刻成 6 个数字根保留序列旨在降低复杂性;Python 代码在 6 个“通道”中使用种子值 af 再现 A077947。这一长段归结为声明,“序列项的数字根在模式中重复(1、1、2、5、9、9)。” 更大的说法是,其数字根以某种模式重复的所有序列都可以被分割/分离成相等数量的不同序列,并且这些序列可以独立计算。有一个与这个序列有关的赏金。更大的说法是,其数字根以某种模式重复的所有序列都可以被分割/分离成相等数量的不同序列,并且这些序列可以独立计算。有一个与这个序列有关的赏金。更大的说法是,其数字根以某种模式重复的所有序列都可以被分割/分离成相等数量的不同序列,并且这些序列可以独立计算。有一个与这个序列有关的赏金。

这段代码很难看,但如果不这样编码,我似乎无法得到正确的答案;

由于我似乎无法将重复值正确存储在函数中,因此我还没有弄清楚如何将其编写为函数。

因此,当然,如果这产生了良好的结果,我们希望将讨论与 OEIS 参考文献联系起来。

这是序列的链接: https ://oeis.org/A077947

4

4 回答 4

2

这是一种无需第二个 for 循环的替代方法:

sequences   = [ 1,  1,  2,   5,   9,   18   ]
multipliers = [ 36, 72, 144, 288, 576, 1152 ]

for x in range(100):
    print(*sequences)
    sequences = [ s + m*64**x for s,m in zip(sequences,multipliers) ]

[编辑] 查看我注意到这个特定序列的值也可以通过以下方式获得:

N[i+1] = 2 * N[i] + (-1,0,1 旋转)

或者

N[i+1] = 2 * N[i] + i mod 3 - 1 (假设从零开始的索引)

i  N[i] [-1,0,1]             N[i+1]
0  1    -1   --> 2*1 - 1 --> 1
1  1     0   --> 2*1 + 0 --> 2
2  2     1   --> 2*2 + 1 --> 5
3  5    -1   --> 2*5 - 1 --> 9
4  9     0   --> 2*9 + 0 --> 18
... 

因此,产生序列的更简单的循环可能是:

n = 1
for i in range(100):
    print(n)
    n = 2*n + i % 3 - 1

使用 functools 中的 reduce 函数可以使这更加简洁:

from functools import reduce

sequence = reduce(lambda s,i: s + [s[-1]*2 + i%3 - 1],range(20),[1])
print(sequence)

>>> [1, 1, 2, 5, 9, 18, 37, 73, 146, 293, 585, 1170, 2341, 4681, 9362, 18725, 37449, 74898, 149797, 299593, 599186]

使用您的多渠道方法和我建议的公式,这将给出:

sequences   = [ 1,  1,  2,   5,   9,   18   ]
multipliers = [ 36, 72, 144, 288, 576, 1152 ]

allSequences = reduce(lambda ss,x: ss + [[ s + m*64**x for s,m in zip(ss[-1],multipliers) ]],range(100),[sequences])
for seq in allSequences: print(*seq) # print 6 by 6

[EDIT2] 如果您的所有序列都将具有相似的模式(即起始通道、乘数和计算公式),您可以在函数中推广此类序列的打印,因此每个序列只需要一行:

def printSeq(calcNext,sequence,multipliers,count):
    for x in range(count):
        print(*sequence)
        sequence = [ calcNext(x,s,m) for s,m in zip(sequence,multipliers) ]

printSeq(lambda x,s,m:s*2+m*64**x,[1,1,2,5,9,18],multipliers=[36,72,144,288,576,1152],count=100)

[EDIT3] 改进 printSeq 函数。

我相信您并不总是需要一个乘数数组来计算每个通道中的下一个值。该函数的改进是为 lambda 函数提供通道索引而不是乘数。如果需要,这将允许您使用乘数数组,但也可以让您使用更通用的计算。

def printSeq(name,count,calcNext,sequence):
    p = len(sequence)
    for x in range(count):
        print(name, x,":","\t".join(str(s) for s in sequence))
        sequence = [ calcNext(x,s,c,p) for c,s in enumerate(sequence) ]

lambda 函数有 4 个参数,预计会返回指定通道的下一个序列值:

s : current sequence value for the channel
x : iteration number
c : channel index (zero based)
p : number of channels

因此,在公式中使用数组将表示如下:

printSeq("A077947",100,lambda x,s,c,p: s + [36,72,144,288,576,1152][c] * 64**x, [1,1,2,5,9,18])

但是您也可以使用基于通道索引(和通道数)的更通用的公式:

printSeq("A077947",100,lambda x,s,c,p: s + 9 * 2**(p*x+c+2), [1,1,2,5,9,18])

或(基于 2*S + i%3 - 1 的 6 个通道):

printSeq("A077947",100,lambda x,s,c,p: 64*s + 9*(c%3*2 - (c+2)%3 - 1) ,[1,1,2,5,9,18])
printSeq("A077947",100,lambda x,s,c,p: 64*s + 9*[-3,1,2][c%3],[1,1,2,5,9,18])

我的理由是,如果您有一个可以根据当前索引和序列中的值计算下一个值的函数,您应该能够定义一个跨步函数,该函数将计算 N 个索引更远的值。

给定 F(i,S[i]) --> i+1,S[i+1]

F2(i,S[i]) --> i+2,S[i+2] = F(F(i,S[i]))
F3(i,S[i]) --> i+3,S[i+3] = F(F(F(i,S[i])))
...
F6(i,S[i]) --> i+6,S[i+6] = F(F(F(F(F(F(i,S[i]))))))
...
Fn(i,S[i]) --> i+n,S[i+n] = ...

这将始终有效,并且不需要乘法器数组。大多数时候,应该可以仅使用代数来简化 Fn。

例如 A001045 : F(i,S) = i+1, 2*S + (-1)**i

printSeq("A001045",20,lambda x,s,c,p: 64*s + 21*(-1)**(x*p+c),[0,1,1,3,5,11])

请注意,从第 3 个值开始,可以在不知道索引的情况下计算该序列中的下一个值:

A001045: F(S) = 2*S + 1 - 2*0**((S+1)%4)

于 2019-02-18T18:43:17.940 回答
0

这将与您的代码相同,并且可以说更漂亮。您可能会看到使魔术常数不那么随意的方法。

factors = [ 1, 1, 2, 5, 9, 18 ]
cofactors = [ 36*(2**n) for n in range(6) ]

for x in range(10):
    print(*factors)
    for i in range(6):
        factors[i] = factors[i] + cofactors[i] * 64**x

i要仅计算其中一个子序列,在迭代时保持固定就足够了。

于 2019-02-18T17:56:12.543 回答
0

从 OEIS 注释中可以看出,您只需要 3 个初始值和 3 个先前序列元素 a(n-1)、a(n-2) 和 a(n-3) 的 1 次递归。然后,您可以轻松获得该系列。

# a(n-1)+a(n-2)+2*a(n-3)
# start values: 1, 1, 2

a1, a2, a3 = 1,1,2 #initial vales
m3, m2, m1 = 1,1,2 #multipliers for a(n-1):m3 a(n-2):m2 and a(n-3):m1

print a1, a2, a3,
for i in range(16):
    a1,a2,a3=a2,a3,a3*m3+a2*m2+a1*m1
    print a3,

这给你 1 1 2 5 9 18 37 73 146 293 585 1170 2341 4681 9362 18725 ...

于 2020-08-20T00:41:55.460 回答
0

这是使用生成器的替代版本:

def Jacobsthal():
    roots = [1, 1, 2, 5, 9, 18]
    x = 0
    while True:
        yield roots
        for i in range(6):
            roots[i] += 36 * 2**i * 64**x
        x += 1

这是一种安全的使用方法:

j = Jacobsthal()
for _ in range(10):
    print(j.send(None))
于 2019-02-18T18:51:05.797 回答