与太多工人一起使用IloCP的问题

时间:2018-07-13 21:14:14

标签: constraint-programming ilog cp-optimizer

我建立了一个简单的约束,强制变量的值必须与模运算一致。有两种一致性级别:边界一致性和域一致性。在此示例中,使用1个或2个工作程序可以很好地解决边界一致性问题,但是对于3个或更多工作程序,propagate()函数将无限循环,因为它似乎无法删除域的最大值。我的计算机有2个物理核心,所以我的猜测是问题所在:使用比物理核心更多的工人。我正在使用最新版本的Cplex Optimization Studio。这是代码:

文件main.cc

#include <ilcp/cp.h>
#include "IloModulo.h"


int main() {
  IloEnv env;
  IloModel model(env);

  IloIntVar x(env, 1, 100000);
  model.add(IloModulo(env, x, 3, BOUNDS_CONSISTENCY));
  model.add(IloMinimize(env, x));

  IloCP solver(model);
  solver.setParameter(IloCP::Workers, 1); // Infinite loop with 3 or more workers
  solver.solve();

  return 0;
}

文件IloModulo.h

#ifndef ILOMODULO_H_
#define ILOMODULO_H_


#include <ilcp/cpext.h>


#define BOUNDS_CONSISTENCY 1
#define DOMAIN_CONSISTENCY 2


class IlcModuloI : public IlcConstraintI {
private:
  IlcIntVar x_;
  IlcInt modulo_;
  IlcInt consistency_;

public:
  IlcModuloI(IloCPEngine cp,
         IlcIntVar x,
         IlcInt modulo,
         IlcInt consistency);
  ~IlcModuloI();

  virtual void propagate();
  virtual void post();
};

// The IloModulo constraint is used with the following function
IloConstraint IloModulo(IloEnv env,
            IloIntVar x,
            IloInt modulo,
            IloInt consistency);


#endif // ILOMODULO_H_

文件IloModulo.cc

#include "IloModulo.h"


IlcModuloI::IlcModuloI(IloCPEngine solver,
               IlcIntVar x,
               IlcInt modulo,
               IlcInt consistency) :
  IlcConstraintI(solver),
  modulo_(modulo),
  x_(x),
  consistency_(consistency) {
  ;
}


IlcModuloI::~IlcModuloI() {
  ;
}


void IlcModuloI::propagate() {
  switch (consistency_) {
  case BOUNDS_CONSISTENCY: {
    while ((x_.getMin() % modulo_ != 0) ||
       (x_.getMax() % modulo_ != 0)) {
      if (x_.getMin() % modulo_ != 0) {
    x_.setMin(x_.getMin()+1);
    continue;
      }
      if (x_.getMax() % modulo_ != 0) {
    std::cout << "Min/max values: " << x_.getMin() << "/" << x_.getMax() << std::endl;
    std::cout << "Decreasing maximum value by 1." << std::endl;
    x_.setMax(x_.getMax()-1);
    std::cout << "Min/max values: " << x_.getMin() << "/" << x_.getMax() << std::endl;
    std::cout << "------------------------------" << std::endl;
    continue;
      }
    }
    break;
  }

  case DOMAIN_CONSISTENCY: {
    IlcInt threshold = x_.getMin();
    while (threshold <= x_.getMax()) {
      if (threshold % modulo_ != 0) {
    x_.removeValue(threshold);
      }
      if (threshold == x_.getMax()) {
    break;
      }
      threshold = x_.getNextHigher(threshold);
    }
    break;
  }
  }
}


void IlcModuloI::post() {
  switch (consistency_) {
  case BOUNDS_CONSISTENCY: {
    x_.whenRange(this);
    break;
  }

  case DOMAIN_CONSISTENCY: {
    x_.whenDomain(this);
    break;
  }
  }
}


ILOCPCONSTRAINTWRAPPER3(IloModuloWrapper, solver,
            IloIntVar, x_,
            IloInt, modulo_,
            IloInt, consistency_) {
  use(solver, x_);
  return new (solver.getHeap()) IlcModuloI(solver,
                       solver.getIntVar(x_),
                       modulo_,
                       consistency_);
}


IloConstraint IloModulo(IloEnv env,
            IloIntVar x,
            IloInt modulo,
            IloInt consistency) {
  return IloModuloWrapper(env, x, modulo, consistency);
}

2 个答案:

答案 0 :(得分:1)

实际上,在某些非常特定的条件下,用户定义的约束的传播似乎确实是一个问题。我不确定是否与工人人数有直接联系。 CP Optimizer的开发团队将调查此问题,我们将通知您。

答案 1 :(得分:1)

实际上,CP Optimizer没问题,问题出在传播中的“ while”循环。在传播期间,当您更改变量的最小值/最大值时,更改不必立即应用,因此,如果执行x.setMax(x.getMax()-1),则不会立即应用新的最大值broadcast(),x.getMax()仍返回“旧”最大值。这就是循环的原因。因此,如果您真的想像当前算法一样一一删除这些值,则应该存储当前范围:

case BOUNDS_CONSISTENCY: {
  IloInt min = x_.getMin();
  IloInt max = x_.getMax();
  while ((min % modulo_ != 0) || (max % modulo_ != 0)) {
    if (min % modulo_ != 0) {
      min += 1;
      x_.setMin(min);
      continue;
    }
    if (max % modulo_ != 0) {
      max -=1;
      x_.setMax(max);
      continue;
    }
  }

但是,当然,您不需要按增量工作,并且可以使用整数除法直接设置正确的最小/最大范围:

IloInt min = x_.getMin();
IloInt max = x_.getMax();
min = ( (min+_modulo-1) / _modulo) * _modulo;
max = ( (max) / _modulo) * _modulo;
x_.setRange(min, max);

当然(但是我不知道您的问题的背景是什么),您不需要定义新的约束,您可以在模型中使用预定义的模表达式,即发布: / p>

model.add( (x % _modulo)==0 );

在音乐会上。