将单元段递归分成两部分

时间:2017-03-21 21:00:33

标签: python recursion

我想创建一个简单的多重分形(二项式测量)。它可以按如下方式完成:

  

二项式度量是一种概率度量,通过递归构造方便地定义。首先将$ I:= [0,1] $拆分为两个子区间$ I_0 $和$ I_1 $等长,并将质量$ m_0 $和$ m_1 = 1 - m_0 $分配给它们。使用两个子间隔,以相同的方式进行,依此类推:在第二阶段,例如,四个子区间$ I_ {00},I_ {01},I_ {10},I_ {11} $分别具有质量$ m_0m_0,m_0m_1 m_1m_0 ​​m_1m_1 $。

Rudolf H. Riedi. Introduction to Multifractals

它应该在13次迭代中看起来像这样: Figure 1

我试图以递归的方式实现它,但出现了问题:它使用了左子和右子中先前更改的间隔

def binom_measuare(iterations, val_dct=None, interval=[0, 1], p=0.4, temp=None):

    if val_dct is None:
        val_dct = {str(0.0): 0}

    if temp is None:
        temp = 0

    temp += 1

    x0 = interval[0] + (interval[1] - interval[0]) / 2
    x1 = interval[1]

    print(x0, x1)

    m0 = interval[1] * p
    m1 = interval[1] * (1 - p)

    val_dct[str(x0)] = m0
    val_dct[str(x1)] = m1

    print('DEBUG: iter before while', iterations)
    while iterations != 0:

        if temp % 2 == 0:
            iterations -= 1
            print('DEBUG: iter after while (left)', iterations)
            # left
            interval = [interval[0] + (interval[1] - interval[0]) / 2, interval[1] / 2]
            binom_measuare(iterations, val_dct, interval, p=0.4, temp=temp)

        elif temp % 2 == 1:
            print('DEBUG: iter after while (right)', iterations)
            # right
            interval = [interval[0] + (interval[1] - interval[0]) / 2, interval[1]]
            binom_measuare(iterations, val_dct, interval, p=0.4, temp=temp) 

    else:
        return val_dct

此外,我尝试使用for循环执行此操作,并且它在第二次迭代中表现良好:在第三次迭代中,它使用2 ^ 3乘数而不是3 $ m_0m_0m_0 $和2 ^ 4在第四次迭代而不是4等等:

iterations = 4
interval = [0, 1]
val_dct = {str(0.0): 0}
p = 0.4

for i in range(1, iterations):
    splits = 2 ** i
    step = interval[1] / splits
    print(splits)

    for k in range(1, splits + 1):
        deg0 = splits // 2 - k // 2
        deg1 = k // 2
        print(deg0, deg1)
        val_dct[str(k * step)] = p ** deg0 * (1 - p) ** deg1
    print(val_dct)

这个概念似乎很容易实现,可能有人已经完成了。我只是从另一个角度看?

UPD:请确保您的建议可以达到上图所示的结果(p=0.4, iteration=13)。

UPUPD:Bill Bell提供了一个很好的想法来实现Riedi在文章中提到的内容。我使用了Bill的方法并编写了一个函数来实现它所需的迭代次数和$ m_0 $(请参阅我的answer below)。

3 个答案:

答案 0 :(得分:1)

如果我正确理解了这个原则,你可以使用sympy符号代数库来进行这个计算。

>>> from sympy import *
>>> var('m0 m1')
(m0, m1)
>>> layer1 = [m0, m1]
>>> layer2 = [m0*m0, m0*m1, m0*m1, m1*m1]
>>> layer3 = []
>>> for item in layer2:
...     layer3.append(m0*item)
...     layer3.append(m1*item)
...     
>>> layer3
[m0**3, m0**2*m1, m0**2*m1, m0*m1**2, m0**2*m1, m0*m1**2, m0*m1**2, m1**3]

间隔总是相同的大小。

当您需要评估分发时,您可以使用以下类型的代码。

>>> [_.subs(m0,0.3).subs(m1,0.7) for _ in layer2]
[0.0900000000000000, 0.210000000000000, 0.210000000000000, 0.490000000000000]

答案 1 :(得分:0)

我认为问题出在你的while循环中:它没有正确处理递归的基本情况。它仅在迭代为0时停止,否则保持循环。如果你想调试为什么这会形成一个无限循环,我会留给你。相反,我尽力解决问题。

我将更改为简单的 if ,通过不更改例程中的迭代使递归变得更安全,并使< strong> interval 输入参数的本地副本。您正在使用可变对象作为默认值,这很危险。

def binom_measuare(iterations, val_dct=None, span=[0, 1], p=0.4, temp=None):
    interval = span[:]
    ...
    ...
print('DEBUG: iter before while', iterations)
if iterations > 0:

    if temp % 2 == 0:
        print('DEBUG: iter after while (left)', iterations)
        # left
        interval = [interval[0] + (interval[1] - interval[0]) / 2, interval[1] / 2]
        binom_measuare(iterations-1, val_dct, interval, 0.4, temp)

    else:
        print('DEBUG: iter after while (right)', iterations)
        # right
        interval = [interval[0] + (interval[1] - interval[0]) / 2, interval[1]]
        binom_measuare(iterations-1, val_dct, interval, 0.4, temp)

else:
    return val_dct

这终止并且似乎给出了一些明智的结果。但是,我想知道你的间隔计算,当右边界往往小于左边。考虑[0.5,1.0] ......左子递归将在区间[0.75,0.5];那是你想要的吗?

答案 2 :(得分:0)

这是我对@Bill Bell对我的问题的回答的改编。它概括了他提供的想法。

if (isset($_POST['submit']) {  // "submit" is the name of the submit button
    onSubmit();
}

function onSubmit() {
    /* your code here */
}

让我们绘制输出

import matplotlib.pyplot as plt
from sympy import var

def binom_measuare(iterations, p=0.4, current_layer=None):

    var('m0 m1')

    if current_layer is None:
        current_layer = [1]

    next_layer = []

    for item in current_layer:
        next_layer.append(m0*item)
        next_layer.append(m1*item)

    if iterations != 0:
        return binom_measuare(iterations - 1, current_layer=next_layer)

    else:
        return [i.subs(m0, p).subs(m1, 1 - p) for i in next_layer]

enter image description here

我认为我们拥有它。