我想创建一个简单的多重分形(二项式测量)。它可以按如下方式完成:
二项式度量是一种概率度量,通过递归构造方便地定义。首先将$ 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
我试图以递归的方式实现它,但出现了问题:它使用了左子和右子中先前更改的间隔
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)。
答案 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]
我认为我们拥有它。