【问题标题】:Resource allocation algorithm资源分配算法
【发布时间】:2015-09-28 16:51:42
【问题描述】:

我知道该算法存在,但我在命名它和找到合适的解决方案时遇到了问题。

我的问题如下:

  • 我有一组 J 作业需要完成。

  • 完成所有作业需要不同的时间,但时间是已知的。

  • 我有一组 R 资源。

  • 每个资源 R 可以有 1 到 100 个实例。

  • 一个 Job 可能需要使用任意数量的资源 R.

  • 一个作业可能需要使用资源 R 的多个实例,但绝不会超过资源 R 拥有的实例。 (如果一个资源只有 2 个实例,则作业永远不需要超过 2 个实例)

  • 一旦作业完成,它会将其使用的所有资源的所有实例返回到池中以供其他作业使用。

  • 作业一旦开始就不能被抢占。

  • 只要资源允许,可以同时执行的作业数量没有限制。

  • 这不是有向图问题,作业 J 可以按任何顺序执行,只要它们可以声明其资源即可。

我的目标: 调度作业以最小化运行时间和/或最大化资源利用率的最佳方式。

【问题讨论】:

  • 您必须定义竞争所有工作的“最佳”方式是什么意思,但这对于 Stack Overflow 来说仍然是题外话。
  • google.com/… 资源受限项目调度问题的混合元启发式算法
  • 听起来像是 ICON 挑战的this resource optimization problem。元启发式在这方面效果很好。您在该视频中看到的开源实现获得了二等奖。
  • 刚刚回到工作岗位,在您发布的解决方案上取得进展,哈罗德希望在几个小时内有更多进展。
  • @Kaiser,你能分享一下这个问题的方程式吗?

标签: algorithm scheduling


【解决方案1】:

我不确定这个想法有多好,但您可以将其建模为整数线性程序,如下所示(未测试)

定义一些常量,

Use[j,i] = amount of resource i used by job j
Time[j] = length of job j
Capacity[i] = amount of resource i available

定义一些变量,

x[j,t] = job j starts at time t
r[i,t] = amount of resource of type i used at time t
slot[t] = is time slot t used

约束是,

// every job must start exactly once
(1). for every j, sum[t](x[j,t]) = 1
// a resource can only be used up to its capacity
(2). r[i,t] <= Capacity[i]
// if a job is running, it uses resources
(3). r[i,t] = sum[j | s <= t && s + Time[j] >= t] (x[j,s] * Use[j,i])
// if a job is running, then the time slot is used
(4). slot[t] >= x[j,s] iff s <= t && s + Time[j] >= t

第三个约束意味着如果一个作业最近开始的时间足够长并且它仍在运行,那么它的资源使用量将被添加到当前使用的资源中。第四个约束意味着如果一个作业最近开始的时间足够长以至于它仍在运行,那么就使用这个时间段。

目标函数是槽的加权和,后面的槽具有更高的权重,因此它更喜欢填充早期的槽。理论上,权重必须以指数方式增加,以确保使用较晚的时隙总是比仅使用较早的时隙的任何配置更差,但求解器不喜欢这样,在实践中,您可能可以避免使用增长较慢的权重。

您将需要足够的槽位才能存在解决方案,但最好不要比您最终需要的多太多,因此我建议您从一个贪婪的解决方案开始,以便为您提供一个有希望的不平凡的时间上限插槽(显然还有所有任务的长度之和)。

有很多方法可以获得贪婪的解决方案,例如,只需在最早的时间段内逐一安排作业。通过某种“硬度”来排序它们可能会更好,然后将硬的放在第一位,例如,您可以根据他们使用资源的严重程度给他们打分(例如,Use[j,i] / Capacity[i] 的总和,或也许是最大值?谁知道呢,尝试一些东西)然后按该分数降序排列。

作为奖励,如果您只解决线性松弛问题(允许变量取小数值,不只是 0 或 1)你会得到一个下界,而近似的贪心解决方案会给出上界。如果它们足够接近,您可以跳过代价高昂的整数阶段并采用贪婪解决方案。在某些情况下,如果线性松弛的四舍五入目标与贪心解的目标相同,这甚至可以证明贪婪解是最优的。

【讨论】:

  • 有趣,这似乎有很大的潜力,我会尝试做一个实现,看看它会带我去哪里。
  • 我得到了 ILP 实现的工作版本,它很准确,但在较大的数据集上速度慢得令人望而却步。我正在尝试线性松弛,但我无法看到如何将线性松弛应用于问题。
  • @Kaiser 好吧,现在想想,放松可能很糟糕。也许我可以改进模型,对此有一些想法
  • 感谢您的帮助,看来这个问题比我最初预期的要困难一些。
  • @alanextar 我用竖线表示不是所有可能的j被使用,只有那些满足竖线后条件的。 Use[j,i] 在那里乘以 x[j,s],因为 r[i,t] 仅用于计算在那一刻使用了多少资源,因此它必须考虑到那一刻哪些任务处于活动状态(这也是为什么在竖线之后出现复杂条件的原因)以及每个活动任务使用多少资源。
【解决方案2】:

这可能是Dykstra's Algorithm 的工作。对于您的情况,如果您想最大化资源利用率,那么搜索空间中的每个节点都是将作业添加到您将立即执行的作业列表的结果。然后,边缘将是您将作业添加到您将要执行的作业列表时留下的资源。

然后,目标是找到具有最小值的传入边的节点的路径。

另一种更直接的方法是将其视为knapsack problem

要将这个问题构建为背包问题的一个实例,我会执行以下操作:

假设我有 J 工作、j_1, j_2, ..., j_nR 资源,我想找到 J 的子集,以便在安排该子集时,将 R 最小化(我将其称为 @ 987654328@).

在伪代码中:

def knapsack(J, R, J`):
  potential_solutions = []
  for j in J:
    if R > resources_used_by(j):
      potential_solutions.push( knapsack(J - j, R - resources_used_by(j), J' + j) )
    else:
      return J', R
  return best_solution_of(potential_solutions)

【讨论】:

  • 您能否详细说明如何将其视为背包?
  • @Davidann ,有趣的答案,但鉴于工作可能需要不同的时间,我无法看到这是如何给出最佳答案的。似乎背包代码没有考虑可能需要多个资源并运行很长时间的作业,并且可能会将它们与可能不会花费很长时间的作业组合在一起。您对此有何看法?
  • @Kaiser:您的目标是“最小化运行时间和/或最大化资源利用率”。我选择了资源利用。
  • @Davidann,对不起,我不清楚我想知道这如何考虑到作业的运行时间不同。即使您正在优化资源利用率,这种背包变体似乎也假设运行时间均匀。如果我错了,请纠正我。
  • @Kaiser:我认为这个算法没有考虑到每个作业运行需要多长时间。它只关注最大化资源利用率。
猜你喜欢
  • 2012-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多