如何将定期事件随时间均匀地分布在各个业务部门中?

时间:2018-12-18 08:57:54

标签: algorithm

让我们说我们有N个垃圾箱,并且想要在给定时间段P内在每个垃圾箱上触发#[n]事件(n

  • 事件以固定的时间间隔全局触发:每P / sum(#[n]),都会触发一个事件。
  • 在每个bin上,事件通常以固定的时间间隔大致触发:即,每个P / #[n]

目标是计算一个周期,该周期将反复重复(在过程的整个生命周期中)。事件应在此周期的重复过程中平均分配。

作为一个例子,假设我们有3个bin A,B和C,使得#[A] = 5#[B] = 10#[C] = 15,那么一个好的周期可能是:

[C, B, C, B, C, A,
 C, B, C, B, C, A,
 C, B, C, B, C, A,
 C, B, C, B, C, A,
 C, B, C, B, C, A]

目前尚不清楚这是否是最佳选择,因为B分布不均。

当然,我们无法保证事件的数量是如此精确地分配;实际上,事件的数量可能是同质的。

注意:一个同样好的循环将使Bs的任一列与As的列切换。


数量级:

  • 最多12个垃圾箱。
  • 每个bin多达数十万个事件。

一个务实的解决方案是依靠随机算法:对于上述情况,将5 As,10 Bs和15 Cs放在一个序列中,然后随机洗牌。它不是最佳的,但是具有良好的复杂性和相对分散的可能性。


我有一个暂定的Python解决方案:

def select_minimum(weights):
    n, w = 0, weights[0][1]

    for i in range(len(weights)):
        if weights[i][1] < w:
            n, w = i, weights[i][1]

    return n


def spread_bins(bins):
    total = sum(bins)
    pace = [total * 1.0 / b for b in bins]

    c = [(i, pace[i]) for i in range(len(bins))]

    result = []

    for _ in range(total):
        n = select_minimum(c)

        bin, w = c[n]
        c = c[:n] + c[n+1:] + [(bin, w + pace[bin])]
        c = [(i, w - 1) for i, w in c]

        result.append(bin)

    return result

哪个似乎在这个特定示例上起作用,产生:

[2, 1, 2, 0, 1, 2,
 2, 1, 2, 0, 1, 2,
 2, 1, 2, 0, 1, 2,
 2, 1, 2, 0, 1, 2,
 2, 1, 2, 0, 1, 2]

但是我不相信(1)正确,(2)最佳。


如何将定期事件随时间均匀地分布在各个业务部门中?

2 个答案:

答案 0 :(得分:2)

请注意,您的问题在本质上等同于Bresenham line drawing algorithm

虽然Bresehham算法将两个位移值dxdy尽可能均匀地分布在dx+dy步骤上,但是您的任务需要“更多尺寸”-N = 3..12

Bresenham算法可能会在3D情况下进行扩展,以此类推(example of 3d and 6d),但是我没有看到简洁的概括(例如,使用优先级队列来累积错误等)-也许确实存在这种概括。 (some words towards common case

答案 1 :(得分:0)

说我们每个仓库都有一个数据结构,其中包含以下内容:

  • 装箱尺寸
  • 要达到的值:用于计算,并初始化为所有容器尺寸的总和
  • 当前值:初始化为0
  • 一个成长的步骤:初始化容器大小<​​/ li>

给定的bin需要(达到的值-当前值)/生长步长(四舍五入为整数)步长作为下一个元素出现。

考虑所有垃圾箱,将使用 M =步骤值的最小值触发下一个元素。

所以我们可以:

  • 更新所有垃圾箱,以便*当前值+ = M *增长步骤*
  • 保留所有具有当前值> =值的垃圾箱
  • 更新我们保持在当前值-=值以上的垃圾箱
  • 并返回这些垃圾箱作为结果

这样,我们以离散的方式推进结果,而不会丢失频率。 此外,由于初始列表的顺序,因此仅保留顺序。

bad Python中,可能是:

def create_bins( sizes ):
    s = sum(sizes)
    return [[size, s, 0, size] for size in sizes]

def div_rem( x, y ):
    d = (int)(x / y)
    r = x % y
    if r == 0:
        return d
    else:
        return d+1

def next_bins( bins ):
    min_steps = min([div_rem(b[1]-b[2], b[3]) for b in bins])
    for b in bins: b[2] = b[2] + min_steps * b[3]
    result = [b for b in bins if b[2] >= b[1]]
    for b in result: b[2] = b[2] - b[1]
    return result

sizes = [15, 10, 5]

bins = create_bins( sizes )

result = next_bins( bins )