Cplex / OPL本地搜索

时间:2013-08-21 17:03:04

标签: optimization cplex ilog

我在OPL中实现了一个模型。我想使用这个模型在java中实现本地搜索。我想用一些启发式方法初始化解决方案,并为cplex提供这些初始解决方案,根据模型找到更好的解决方案,但我也想将搜索限制在特定的邻域。有关如何做到这一点的想法吗?

另外,我如何限制所有变量的范围?什么是最好的:在自己的opl或java甚至C ++中实现这些启发式和本地搜索?

提前致谢!

2 个答案:

答案 0 :(得分:1)

这是几个问题。所以这里有一些指示和建议:

  1. 在Cplex中,您使用IloOplCplexVectors()为模型提供初始解决方案 这是关于如何更改CPLEX解决方案的good example in IBM's文档。

  2. 在OPL中,您也可以这样做。您基本上为变量设置了一系列值,并将这些值交给CPLEX。 (See this example)。

  3. 将搜索限制在特定的社区:在不知道详细信息的情况下,没有简单的方法可以回复。但人们有两种方式可以做到这一点:

    一个。改变目标以支持“邻里”并使其他领域缺乏吸引力。

    湾添加从搜索空间中清除其他邻域的约束。

  4. 关于限制OPL中的变量范围,您可以直接执行:

    dvar int supply in minQty..maxQty;
    
  5. 或者对于一系列决策变量,您可以执行以下操作:

    range CreditsAllowed = 3..12;
    dvar int credits[student] in CreditsAllowed;
    

    希望这有助于你前进。

答案 1 :(得分:1)

只是添加一些相关的观察结果:

Re Ram的观点3:我们在方法b上取得了很大的成功。特别是,添加约束以将某些变量修复为已知解决方案中的值,然后重新求解问题中的其余变量很简单。更一般地,您可以添加约束以将值限制为与先前的解决方案类似,例如:

var >= previousValue - 1
var <= previousValue + 2

当然这对二进制变量没用,但对于一般整数或连续变量都可以正常工作。这种方法可以推广用于变量集合:

sum(i in indexSet) var[i] >= (sum(i in indexSet) value[i])) - 2
sum(i in indexSet) var[i] <= (sum(i in indexSet) value[i])) + 2

这个可以适用于二进制变量集。对于100个二进制变量的数组,其中10个值为1,我们将寻找一个解决方案,其中至少8个值为1但不超过12.另一个变体是限制汉明距离(假设为汉明距离)这里的vars都是二进制的):

dvar int changed[indexSet] in 0..1;
forall(i in indexSet)
  if (previousValue[i] <= 0.5)
    changed[i] == (var[i] >= 0.5) // was zero before
  else
    changed[i] == (var[i] <= 0.5) // was one before

sum(i in indexSet) changed[i] <= 2;

这里我们要说的是例如100个二进制变量,只允许最多两个二进制变量与前一个解决方案具有不同的值。

当然,你可以结合这些想法。例如,添加简单约束以将问题的大部分修复为先前的值,同时保留一些其他变量以重新求解,然后在一些剩余的自由变量上添加约束以限制新解决方案接近于前一个。您会注意到,当我们试图变得更聪明时,这些方案的实施和维护会变得更加复杂。

为了使本地搜索能够很好地运作,您需要仔细考虑如何构建您当地的社区 - 太小而且您寻求改进的机会太少,而如果它们太大则需要花费太长时间要解决,所以你不能做出这么多改进步骤。

一个相关的观点是每个邻域需要合理地内部连接。我们做了一些实验,我们在模型中修复了99%的变量值,并解决了剩余的1%。当1%在模型中聚集在一起时(例如,资源子集的所有分配变量),我们得到了很好的结果,而相比之下,我们从模型中的任何地方随机选择1%的变量就无处可去。 / p>

一个经常被忽视的想法是在模型上反转这些相同的限制,作为对解决方案进行一些改变以实现一定程度的多样化的一种方式。因此,您可以添加约束以强制特定值与先前的解决方案不同,或者确保100个二进制变量数组中的至少两个具有<来自先前解决方案的强>不同值。我们已经使用这种方法来获得一种混合数学模型的禁忌搜索。

最后,我们主要在C ++和C#中完成此操作,但它可以很好地从Java中完成。没有从OPL尝试过多,但也应该没问题。我们的关键是能够遍历问题结构并使用问题知识来选择我们冻结或放松的变量集 - 我们发现使用C#这样的语言编写代码更容易,更快,但是建模的东西更难写作和维护。我们可能有点“老派”,喜欢对我们正在做的事情进行详细的细粒度控制,并发现我们需要在OPL中创建更多的数组和索引集以实现我们想要的目标,同时我们可以实现在没有像C#这样的语言中创建如此多的数据结构的情况下,使用更智能的循环等效果相同。