【问题标题】:Generating Markov number sequence with python用python生成马尔可夫数列
【发布时间】:2021-11-26 03:32:00
【问题描述】:

我想做一些事情来更好地了解产量和产量。目标是按顺序生成马尔可夫序列,第一个元素为索引 0。 https://en.wikipedia.org/wiki/Markov_number

我想出了以下代码。

def chain(iter1, iter2):
    while True:
        yield next(iter1)
        yield next(iter2)

def isMarkov(x,y,z):
    if x**2 + y**2 + z**2 == 3 * x * y * z:
        return True
    else:
        return False

def gen_markov(seed):
    x1 = seed[0]
    y1 = seed[2]
    z1 = y1 + 1
    while not isMarkov(x1,y1,z1):
        z1 += 1
    yield (x1,y1,z1)
    
    x2 = seed[1]
    y2 = seed[2]
    z2 = y2 + 1
    while not isMarkov(x2,y2,z2):
        z2 += 1
    yield (x2,y2,z2)
    
    yield from chain(gen_markov((x1,y1,z1)), gen_markov((x2,y2,z2)))
    
def markov(n):
    g = gen_markov((1,2,5))
    markov_nums = set([1,2,5])
    while len(markov_nums) <= n:
        triple = next(g)
        for x in triple:
            markov_nums.add(x)
    markov_nums = list(markov_nums)
    markov_nums.sort()
    print(markov_nums[n])

n = int(input('Enter n: '))
markov(n)

这可以在树状结构中生成马尔可夫三元组。

这是 gen_markov 函数生成的前 35 个马尔科夫三元组。

(1, 5, 13)
(2, 5, 29)
(1, 13, 34)
(2, 29, 169)
(5, 13, 194)
(5, 29, 433)
(1, 34, 89)
(2, 169, 985)
(5, 194, 2897)
(5, 433, 6466)
(13, 34, 1325)
(29, 169, 14701)
(13, 194, 7561)
(29, 433, 37666)
(1, 89, 233)
(2, 985, 5741)
(5, 2897, 43261)
(5, 6466, 96557)
(13, 1325, 51641)
(29, 14701, 1278818)
(13, 7561, 294685)
(29, 37666, 3276509)
(34, 89, 9077)
(169, 985, 499393)
(194, 2897, 1686049)
(433, 6466, 8399329)
(34, 1325, 135137)
(169, 14701, 7453378)
(194, 7561, 4400489)
(433, 37666, 48928105)
(1, 233, 610)
(2, 5741, 33461)
(5, 43261, 646018)
(5, 96557, 1441889)
(13, 51641, 2012674)

我的问题是我希望能够按顺序生成序列。数字 610 是序列中的第 11 个元素,但远大于 610 的数字会更早生成。例如,如果您运行 n=11,则函数返回 2897。关于如何按顺序生成序列的任何建议?

【问题讨论】:

  • 与链接中的顺序相同?
  • 如果您想要与链接中相同的顺序,那么您对gen_markov 的实现就是问题所在。您的尝试确实是一种蛮力方法。我对此类数字没有经验,但在链接中提到了构造此类数字的明确方法。看看德语翻译,你会发现一些更有用的技巧(它更完整!)来生成它们

标签: python math generator sequence yield


【解决方案1】:

更新。我能够使用队列找到一个相当好的解决方案(虽然并不完美)。

# Markov Numbers

seed = (1,2,5)
markov = set()
markov.add(1)
queue = []
queue.append(seed)

n = int(input('Enter n: '))

while len(markov) <= n**3:
    curr = queue.pop()
    p,q,r = (curr)
    markov.add(p)
    markov.add(q)
    markov.add(r)
    left = (p,r,3*p*r-q)
    right = (q,r,3*q*r-p)
    queue.insert(0,left)
    queue.insert(0,right)
markov = list(markov)
markov.sort()
print(markov[n])

我测试到 n=39,(从索引 0 开始)。这与 OEIS 中的前 40 个元素相匹配。 https://oeis.org/A002559/list

0th element: 1
1th element: 2
2th element: 5
3th element: 13
4th element: 29
5th element: 34
6th element: 89
7th element: 169
8th element: 194
9th element: 233
10th element: 433
11th element: 610
12th element: 985
13th element: 1325
14th element: 1597
15th element: 2897
16th element: 4181
17th element: 5741
18th element: 6466
19th element: 7561
20th element: 9077
21th element: 10946
22th element: 14701
23th element: 28657
24th element: 33461
25th element: 37666
26th element: 43261
27th element: 51641
28th element: 62210
29th element: 75025
30th element: 96557
31th element: 135137
32th element: 195025
33th element: 196418
34th element: 294685
35th element: 426389
36th element: 499393
37th element: 514229
38th element: 646018
39th element: 925765

这并不完美,因为仍然需要搜索比 n 更远的距离才能获得 n>10 左右的准确结果。这就是为什么有 n**3 项。如果有人能解释一个更好的方法,将不胜感激。

【讨论】:

    【解决方案2】:

    这是我对这个问题的贡献(不是答案),我完全重新编辑了我的第一次尝试,我不会再继续下去了。为什么? 问题没有明确定义

    1. 您建议作为参考的维基百科文章很糟糕(另请参阅我的 cmets)
    2. 您没有指定排序规则和马尔可夫数的定义 [我自己记录了自己,也有技术/研究论文,但没有找到任何东西(甚至没有正确的马尔可夫定义号码!!)]

    所以,只要你不改进问题,让每个人都可以访问,我会认为它很接近。

    建议

    • math stackexchange 社区询问如何生成有序马尔可夫序列
    • yield/yield from 实现之前,您应该有一个工作示例并理解它(?),即在这种情况下,选择另一个(更简单的)问题开始!
    • 提供有关问题的更多信息

    考虑

    • 马尔可夫数是二叉树的节点,所以实现二叉树

    • 树的每一层都有两个(相对的)最小值,即最外部的叶子,它们由斐波那契和佩尔序列描述。斐波那契是最小的。这些可以用作包含 n-Markov 数的列表的 size 的中断条件

    • 通过保持简单,使用贪心算法...例如,如果您想要一个 n 阶马尔可夫数列表,请考虑一棵完美的二叉树(它的计算量很大,大小由具有初始值的几何级数建模1 和共同比率 2) 并按升序对它们进行排序,并考虑此类列表的第一个 n 条目,smt like

      list(sorted(markov_triples, key=lambda p: p[1]))[:n]

    危险 如评论中所述,在维基百科文章中,对应于马尔可夫数 194 的节点未正确标记,请参阅我的评论以供参考。这里有一个比维基百科更详细的Markov tree

    关于计算树的叶子的示例代码。我使用一个完美的树作为参考,它的节点可以被唯一地描述为几何序列的术语来定位叶子,然后找到通向根的左右路径的序列,最后应用“马尔可夫规则”来找到三元组:

    from math import log
    
    def find_lv(n): # provided that the root as vertex 1, n: absolute node index
        return int(log(n, 2))
    
    def branch_path(n, k): # leaf to root
        # n: depth, k: 0 <= index <= 2**n - 1
        path = [k]
        for i in range(n-1):
            if path[-1] % 2 == 0:
                path += [path[-1] // 2]
            else:
                path += [path[-1] // 2]
        return path
    
    def branch_path_as_directions(path): # leaf to root
        return ['L' if p % 2 == 0 else 'R' for p in path[:-1]] # the root should be skiped!
    
    def new_sol(triple):
        x, y, z = triple
        return (x, y, 3*x*y - z)
    
    def left_triple(triple): 
        x, y, z = triple
        return (x, z, y)
    
    def right_triple(triple): 
        x, y, z = triple
        return (y, z, x)
    
    def markov_triples(n):
       # n: is the absolute position of a node in the tree, i.e. wrt to a geometric series
       # return the branch of triples corresponding to that node
        # initial values of the sequence
        triples = [(1, 1, 1), (1, 1, 2), (1, 2, 5)]
        if n == -2:
            return triples[0]
        if n == -1:
            return triples[1]
        if n == 0:
            return triples[2]
    
        depth = find_lv(n) + 1
    
        # get path the leaf with n
        path = branch_path(depth, n)
        path_l_r = branch_path_as_directions(path)
            
        # flow from root to leaf
        for direction in path_l_r[::-1]:
            if direction == 'L':
                triples += [new_sol(left_triple(triples[-1]))]
            else:
                triples += [new_sol(right_triple(triples[-1]))]
                
        return triples
    
    print(markov_triples(10))
    

    输出

    [(1, 2, 5), (1, 5, 13), (5, 13, 194), (5, 194, 2897)]
    

    【讨论】:

    • 如果您查看 wiki 链接,它将显示前几个马尔可夫数字。 1, 2, 5, 13, 29, 34, 89, 169, 194, 233, 433, 610, 985, 1325 这些都是方程解中三元组 (x,y,z) 的一部分给定的。您的解决方案与我的类似,因为它生成马尔可夫三元组。但问题是我们需要一种方法以正确的顺序生成序列。
    • 谢谢,现在我清楚了您对订单的含义。我很困惑,因为你展示了三元组。因此,要获得数字,应该完成树的每个“层”并查看每个三元组的 y。我会考虑的……
    • 是的,这很困难,因为较小的数字会出现在树的更下方。
    • 好消息!我发现wikipedia中的树的图像是错误的(在英语和其他语言中也是如此)!!,对应于Markoff数194的节点没有正确标记(左右切换)。参见图 2,第 4 页,pdf by Don Zagier
    猜你喜欢
    • 2018-03-21
    • 1970-01-01
    • 1970-01-01
    • 2016-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多