【问题标题】:Precise solutions for Boolean Delay Equations布尔延迟方程的精确解
【发布时间】:2022-01-09 23:25:00
【问题描述】:

我正在尝试编写一种算法来计算布尔延迟方程的连续时间解。类似于 x(t) = x(t-tau1) ^ x(t-tau2),其中 x(t) 是时间的布尔值函数,^ 表示 XOR 运算符,tau1tau2 是连续时间的常数延迟(float)。

我设法编写代码来计算离散时间的解,以相等的时间间隔进行采样,例如 dt

这是一个 Python 脚本,用于计算和绘制其中一种解决方案:

from numpy import *
import matplotlib.pyplot as plt

n = 100000
t = linspace(0.0, 40.0, n)
dt = t[1] - t[0]

# atrasos nas duas linhas (números "reais" float)
tau1 = 1.0
tau2 = 1.3 #2/3 #6/7
# versão em int dos atrasos
itau1 = int(tau1/dt)
itau2 = int(tau2/dt)
# o maior dos atrasos
itaumax = max(itau1, itau2)
# o menor dos atrasos
itaumin = min(itau1, itau2)


# arrays para armazenar as variáveis dinâmicas
# saída do XOR
XO = zeros(n, dtype = int)
# saída da linha 1
XA = zeros(n, dtype = int)
# saída da linha 2
XB = zeros(n, dtype = int)

# estado inicial
XA[0] = 0
XB[0] = 0
XO[0:itaumin] = 1

# inicia cálculo no tempo
for i in range(itaumin,itaumax):
  #  t[i] = i*dt , dt = (tf-t0)/n = 0.01 para tf = 20, n = 1000
  if i-itau1 >= 0:
    XA[i] = XO[i-itau1] # a saída da linha 1 é XO atrasado de tau1
  if i-itau2 >= 0:
    XB[i] = XO[i-itau2] # a saída da linha 2 é XO atrasado de tau2
  XO[i] = XA[i] ^ XB[i] #  ^ corresponde a XOR de inteiros

for i in range(itaumax,n):
  #  t[i] = i*dt , dt = (tf-t0)/n = 0.01 para tf = 20, n = 1000
  XA[i] = XO[i-itau1] # a saída da linha 1 é XO atrasado de tau1
  XB[i] = XO[i-itau2] # a saída da linha 2 é XO atrasado de tau2
  XO[i] = XA[i] ^ XB[i] #  ^ corresponde a XOR de inteiros

plt.figure('Série temporal', figsize=(15,8))
ax1 = plt.subplot(3,1,1)

plt.plot(t-itaumax*dt, XA,color = "blue", label = "A")
plt.xlabel(r'Tempo')
plt.ylabel(r'A')


ax2 = plt.subplot(3,1,2, sharex = ax1)

plt.plot(t-itaumax*dt, XB,color = "red", label = "B")
plt.xlabel(r'Tempo')
plt.ylabel(r'B')

ax3 = plt.subplot(3,1,3, sharex = ax1)

plt.xlabel(r'Tempo')
#plt.plot(t-itaumax*dt, XA,color = "blue", label = "A")
#plt.plot(t, XB,color = "red", label = "B")
plt.plot(t, XO,color = "black", label = "A^B")
plt.ylabel(r'A ^ B')

plt.tight_layout()
plt.show()

但我发现很难编写和算法来表达发生转换(即从 0 到 1 或从 1 到 0)发生的确切时间。困难来自过渡时间相互碰撞和湮灭。在等式中,发生在时间 t 的任何转换都可能在时间 t+tau1t+tau2 产生两个转换,除非有是两个可能的时间 t 导致相同的未来转换,在这种情况下,新的转换“碰撞”并相互湮灭。

如果只是重复的转换,我可以生成所有可能的转换并丢弃重复的转换,但是一旦一对转换发生冲突,它们就不应该生成新的转换,因此我还需要丢弃所有其他转换源自丢弃的对。

这是一个“精确”解决方案的示例:假设我们在时间 t = 0.0 时从一个单一的转换 t[0] 开始,这一次将在时间 @ 产生两个新的转换987654323@ 和t[2] = tau2。新的将产生t[3] = tau1+tau1 == 2*tau1t[4] = tau1+tau2t[5] = tau2+tau1t[6] = tau2+tau2,除了t[4]t[5] 是相同的并且都应该被删除。然后我们应该继续用存储在t[6] 中的值替换t[4] 的值,并从t[3] 和新的t[4] 计算新的转换集。

带数字:对于tau1 = 2.0/3.0tau2 = 1.0,预期的解决方案是

t[1] = 0.66667
t[2] = 1.0
t[3] = 1.33333 
t[4] = 2.33333  ## Note that 1.6667 was removed because t[1]+tau2 == t[2]+tau1
t[5] = 3.0      ## 2.0 was also removed because t[3]+tau1 == t[2]+tau2
t[6] = 3.33333
t[7] = 3.66667  ## etc.

【问题讨论】:

  • 你能举个例子吗?很难理解你在说什么。或许可以向我们展示一个示例,在您的离散时间中 t 有 10 或 20 个连续值,以及相应的 x(t),并解释您的算法应该输出什么以及为什么。
  • 我也不知道“碰撞”和“歼灭”可能是什么意思
  • 也不明白你说某些转换“产生新的转换”是什么意思。
  • 我改进了问题的解释,添加了一个示例,以及离散时间案例的代码。我希望这次我已经让问题变得可以理解了。我还意识到我的离散时间解决方案有时(对于某些延迟值)会产生短脉冲,如果它是精确的,则不应该出现。这可能是由于离散化或舍入错误。这就是为什么我想要一个“精确”的解决方案。感谢您对@Stef 的关注。
  • 关注问题的最后一段,以及 t[1] 到 t[7] 给出的示例,我认为一个简单的解决方案是使用优先级队列来存储生成的时间,以便您仅从队列中最早的时间生成新时间;出队时,如果队列顶部有重复项,则将其丢弃。

标签: python math boolean delay


【解决方案1】:

关注您问题的最后一段,以及从 t[1] 到 t[7] 给出的示例,我认为一个简单的解决方案是使用优先级队列来存储生成的时间,这样您只需从队列中最早的时间生成新的时间;出队时,如果队列前面有重复项,则将其丢弃。

import heapq

def fequal(x, y):            # never compare floats with == directly
    return abs(x-y) < 0.0001

def gen_times(t0, tau):
    queue = [t0]
    while queue:
        head = heapq.heappop(queue)
        if not queue or not fequal(queue[0], head):  # element is unique
            yield head
            for t in tau:
                heapq.heappush(queue, head+t)
        else:                              # element is duplicate
            while queue and fequal(queue[0], head):
                heapq.heappop(queue)


# TESTING
from itertools import islice
print(list(islice(gen_times(0.0, [0.2, 1.0]), 12)))
# [0.0, 0.2, 0.4, 0.6000000000000001, 0.8, 1.2, 1.6, 2.2, 2.4000000000000004, 3.2, 4.2, 4.4]

请注意,1.2没有被删除,因为 1.0 被删除了,所以 1.2 从未生成为 1.0+0.2,仅生成为 0.2+1.0。

【讨论】:

  • 抱歉,@Stef,您的解决方案在 tau1 = 2/3 和 tau2 = 1.0 的第 14 次迭代之后无法工作。它开始产生重复的过渡,这些过渡也应该发生碰撞。请注意,任何先前的转换都可能发生冲突,而不仅仅是最后一个。但我认为堆队列的使用绝对是正确的方向。
  • 这是print(list(islice(gen_times(0.0, [tau1, tau2]), 20)))的部分输出:... 6.0, 6.666666666666666, 6.666666666666667, 7.0, 7.333333333333333, 7.333333333333334, 7.666666666666666, 8.333333333333334, 8.666666666666666]。也许它是由舍入误差引起的? (重复值的最后一位数字似乎不同)。
  • @HugoCavalcante Ooooops,当然,我在编写代码时脑子里有整数。浮点数几乎不应该使用==!= 进行比较。在上面的代码中,您应该将queue[0] != head 替换为abs(queue[0] - head) &gt; 0.0001,将queue[0] == head 替换为abs(queue[0] - head) &lt; 0.0001
  • 是的!它工作得非常漂亮而且非常快。我更改了 decimal 模块中的浮点数,以提高精度。非常感谢!
猜你喜欢
  • 2013-04-28
  • 2011-04-19
  • 1970-01-01
  • 2013-09-13
  • 2021-08-03
  • 1970-01-01
  • 1970-01-01
  • 2012-08-23
  • 2018-10-21
相关资源
最近更新 更多