首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否有更多的Pythonic方法来编码这个递归关系re: OEIS A077947?

是否有更多的Pythonic方法来编码这个递归关系re: OEIS A077947?
EN

Stack Overflow用户
提问于 2019-02-18 17:41:53
回答 4查看 168关注 0票数 0

我正在写一篇关于雅各布序列(A001045)的论文,以及它们如何被认为是由一些不同的子序列组成的。我已经对A077947做了评论,指出了这一点,并包含了一个python程序。不幸的是,编写的程序还有很多不完善之处,因此,我当然想求助于Stack,看看这里是否有人知道如何改进代码!

这里是代码:

代码语言:javascript
复制
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个数字根保持序列拼接在一起生成的;根据这些序列的代码,这些序列在种子值a处启动。计算给定的A077947 a(n)所需的迭代次数是~n/6。执行时,代码将A077947的所有值返回到范围(X)或A077947的~x*6项。我发现重复的数字根很有趣,因为我寻找在序列中周期性的数字根保存作为识别数据中模式的一种方法。例如,在进行维护的大型IT生态系统(mod7环境)中,当估计警报的真假状态时,数字根保持序列能够对大型数据集进行时间序列分析;这种分析还与预测消费者需求/行为模式有关。利用这些分析方法,将A077947分割成6个数字根保持序列是为了降低复杂性;Python代码通过6个“通道”复制A077947,其中种子值为a。这个很长的段落可以归结为这样的说法:“序列的数字词根在模式中重复(1,1,2,5,9,9)。”更大的说法是,所有数字根与模式重复的序列都可以被分割/分离成相同数量的不同序列,并且这些序列可以独立计算。有个赏金和这个序列有关。

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

我还没有想出如何将它写成一个函数,因为我似乎无法使递归值正确地存储在一个函数中。

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

这里有一个指向序列的链接: https://oeis.org/A077947

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-02-18 18:43:17

下面是一种不用第二个for循环就可以完成此操作的替代方法:

代码语言:javascript
复制
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) ]

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

Ni+1 =2* Ni +(-1,1,1旋转)

Ni+1 =2* Ni +i mod 3-1(假设指数为零)

代码语言:javascript
复制
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
... 

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

代码语言:javascript
复制
n = 1
for i in range(100):
    print(n)
    n = 2*n + i % 3 - 1

使用函数工具中的还原函数可以使其更加简洁:

代码语言:javascript
复制
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]

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

代码语言:javascript
复制
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如果您的所有序列都有类似的模式(即启动通道、乘法器和计算公式),则可以将这些序列的打印概括为一个函数,因此每序列只需要一行:

代码语言:javascript
复制
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函数提供信道索引,而不是一个乘法器。这将允许您使用一个乘法器数组,如果您需要,但也将允许您使用更一般的计算。

代码语言:javascript
复制
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个参数,并期望返回指定通道的下一个序列值:

代码语言:javascript
复制
s : current sequence value for the channel
x : iteration number
c : channel index (zero based)
p : number of channels

因此,在公式中使用数组可以如下所示:

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

但是,您还可以使用一个更通用的公式,该公式基于通道索引(和频道数量):

代码语言:javascript
复制
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个信道):

代码语言:javascript
复制
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,Si) -> i+1,Si+1

代码语言:javascript
复制
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

代码语言:javascript
复制
printSeq("A001045",20,lambda x,s,c,p: 64*s + 21*(-1)**(x*p+c),[0,1,1,3,5,11])

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

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

票数 2
EN

Stack Overflow用户

发布于 2019-02-18 17:56:12

这将与您的代码行为相同,而且可以说更漂亮。您可能会看到使神奇常量不那么武断的方法。

代码语言:javascript
复制
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不变。

票数 0
EN

Stack Overflow用户

发布于 2019-02-18 18:51:05

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

代码语言:javascript
复制
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

下面是一种安全的使用方法:

代码语言:javascript
复制
j = Jacobsthal()
for _ in range(10):
    print(j.send(None))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54752681

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档