我正在尝试使用C ++和Concert Technology在CPLEX中解决LP模型。
我想实现需要在当前解决方案中查询我的两个变量的值的约束(更具体的地图消除约束): 变量数组xvar表示边缘,yvar表示节点。
我通过在修改的图上求解n(=节点数)Min-Cut-Problems来实现这些约束,这是通过添加人工源和人工接收器并将它们连接到原始图的每个节点来构造的。
从我到目前为止所读到的内容,我是否需要一个懒惰的约束或回调或者没有这个?
这是我创建模型并解决它,访问解决方案中的变量值等的地方:
// Step 2: Construct the necessary CPLEX objects and the LP model
IloCplex solver(env);
std::cout<< "Original Graph g: " <<std::endl;
std::cout<< net.g() <<std::endl;
MCFModel model(env, net);
// Step 3: Load the model into cplex and solve
solver.extract(model);
solver.solve();
// Step 4: Extract the solution from the solver
if(solver.getStatus() != IloAlgorithm::Optimal) throw "Could not solve to optimality!";
IloNumArray xsol ( env, net.g().nEdges() );
IloNumArray ysol ( env, net.g().nNodes() );
IloNumArray rsol ( env, net.g().nGroups() );
IloNumArray wisol ( env, net.g().nGroups() );
IloNum ksol;
NumMatrix wsol ( env, net.g().nGroups());
for(IloInt i = 0; i < net.g().nGroups(); i++){
wsol[i] = IloNumArray( env, net.g().nGroups() );
}
solver.getValues(xsol, model.xvar());
solver.getValues(ysol, model.yvar());
solver.getValues(rsol, model.rvar());
solver.getValues(wisol, model.wivar());
ksol=solver.getValue(model.kvar());
for (IloInt i = 0; i < net.g().nGroups(); i++){
wsol[i] = wisol;
}
// Step 5: Print the solution.
约束,我需要变量xvar和yvar的当前值,在这里创建:
//build subset constraint y(S) -x(E(S))>= y_i
void MCFModel::buildSubsetCons(){
IloExpr lhs(m_env);
IloCplex cplex(m_env);
IloNumArray xtemp ( m_env, m_net.g().nEdges() );
IloNumArray ytemp ( m_env, m_net.g().nNodes() );
std::vector<Edge> mg_twin;
std::vector<int> mg_weights;
int mg_s;
int mg_t;
SGraph mgraph;
std::vector<int> f;
int nOrigEdges = m_net.g().nEdges();
int nOrigNodes = m_net.g().nNodes();
cplex.getValues(xtemp, m_xvar);
cplex.getValues(ytemp, m_yvar);
mgraph = m_net.g().mod_graph();
mg_s = mgraph.nNodes()-1;
mg_t = mgraph.nNodes();
std::cout<<"modified graph:"<<std::endl;
std::cout<<mgraph<<std::endl;
// fill the weight of original edges with 1/2*x_e
foreach_edge(e, m_net.g()){
mg_weights.push_back((xtemp[e->idx()])/2);
}
// fill the weight of the edges from artificial source with zero
for(int i=0; i<m_net.g().nNodes(); i++){
mg_weights.push_back(0);
}
// fill the weight of the edges to artificial sink with f(i)
// first step: calculate f(i):
//f.resize(m_net.g().nNodes());
foreach_node(i, m_net.g()){
foreach_adj_edge(e, i, m_net.g()){
f[i] = f[i] + xtemp[e->idx()];
}
f[i] = (-1)*f[i]/2;
f[i] = f[i] + ytemp[i];
}
// second step: fill the weights vector with it
for(int i=0; i<m_net.g().nNodes(); i++){
mg_weights.push_back(f[i]);
}
// calculate the big M = abs(sum_(i in N) f(i))
int M;
foreach_node(i, m_net.g()){
M = M + abs(f[i]);
}
// Build the twin vector of the not artificial edges for mgraph
mg_twin.resize(2*nOrigEdges + 2*nOrigNodes);
for(int i=0; i < nOrigEdges ; ++i){
mg_twin[i] = mgraph.edges()[nOrigEdges + i];
mg_twin[nOrigEdges + i] = mgraph.edges()[i];
}
//Start the PreflowPush for every node in the original graph
foreach_node(v, m_net.g()){
// "contract" the edge between s and v
// this equals to higher the weights of the edge (s,v) to a big value M
// weight of the edge from v to s lies in mg_weights[edges of original graph + index of node v]
mg_weights[m_net.g().nEdges() + v] = M;
//Start PreflowPush for v
PreflowPush<int> pp(mgraph, mg_twin, mg_weights, mg_s, mg_t);
std::cout << "Flowvalue modified graph: " << pp.minCut() << std::endl;
}
}
Object pp是用人工源和接收器解决修改后的图形mgraph上的Min-Cut-Problem。原始图表位于m_net.g()。
当我编译并运行它时,我收到以下错误:
terminate called after throwing an instance of 'IloCplex::Exception'
Aborted
在我看来,不可能像这样访问xvar和yvar的值? 我很感激任何帮助,因为我很失落如何做到这一点。 非常感谢!!
答案 0 :(得分:0)
两件事......
予。我强烈建议您使用try-catch来更好地理解CPLEX Exceptions。您也许可以像这样理解异常的本质。事实上,我建议你尝试一下catch-catch设置:
try {
//... YOUR CODE ...//
}
catch(IloException& e) {
cerr << "CPLEX found the following exception: " << e << endl;
e.end();
}
catch(...) {
cerr << "The following unknown exception was found: " << endl;
}
II。在优化过程中与CPLEX交互的唯一方法是通过回调,对于Subtour Elimination Constraints(SECs),您需要将整数和分数SEC分开。
II.1 INTEGER:第一个是最简单的例程,O(n)
例程可以帮助您识别节点解决方案的所有连接组件,然后您可以添加后续剪切防止此特定SEC出现在其他节点中。您可以使用addLocal()
函数在本地强制执行切割,即仅在当前子树上强制执行切割,或使用add()
函数全局执行切割,即在整个Branch-and-Cut树上执行切割。在任何情况下,总是记得添加.end()
来终止剪切容器。否则你会有严重的内存泄漏问题,请相信我,哈哈。此回调需要通过Lazy Constraint Callback(ILOLAZYCONSTRAINTCALLBACK
)
II.2 分数:第二个是更复杂的。最简单的方法是使用Lysgaard教授的CVRPSEP库。现在,它是计算容量削减,Multistar,广义多级,框架容量,强化梳子和低压切割的最有效方式。此外,很容易链接任何现有的代码。链接也需要嵌入到解决方案流程中,因此也需要回调。在这种情况下,它将是User Cut Callback(ILOUSERCUTCALLBACK
)。
很高兴能为您服务 ÿ