/** Separation function. * This function is invoked whenever CPLEX finds an integer feasible * solution. It then separates either feasibility or optimality cuts * on this solution. */ void BendersOpt::LazyConstraintCallback::main() { std::cout << "Callback invoked. Separate Benders cuts." << std::endl; IloNumArray x(getEnv()); IloNumArray rayVals(getEnv()); IloNumVarArray rayVars(getEnv()); IloNumArray cutVal(getEnv()); IloNumVarArray cutVar(getEnv()); getValues(x, master->vars); bool error = false; // Iterate over blocks and trigger a separation on each of them. // The separation is triggered asynchronously so that it can happen // on different remote objects simultaneously. for (BlockVector::size_type b = 0; b < blocks.size(); ++b) { Block *const block = blocks[b]; // Remove current objective from the block's model. IloModel model = block->cplex.getModel(); IloObjective obj = block->obj; model.remove(obj); IloExpr newObj = obj.getExpr(); // Iterate over the fixed master variables in this block to update // the block's objective function. // Each fixed variable goes to the right-hand side and therefore // into the objective function. for (std::vector<Block::FixData>::const_iterator it = block->fixed.begin(); it != block->fixed.end(); ++it) newObj -= block->vars[it->row] * (it->val * x[it->col]); obj.setExpr(newObj); model.add(obj); newObj.end(); // If the problem is unbounded we need to get an infinite ray in // order to be able to generate the respective Benders cut. If // CPLEX proves unboundedness in presolve then it will return // CPX_STAT_INForUNBD and no ray will be available. So we need to // disable presolve. block->cplex.setParam(IloCplex::Param::Preprocessing::Presolve, false); block->cplex.setParam(IloCplex::Param::Preprocessing::Reduce, 0); // Solve the updated problem to optimality. block->cplex.setParam(IloCplex::Param::RootAlgorithm, IloCplex::Primal); try { handles[b] = block->cplex.solve(true); } catch (...) { // If there is an exception then we need to kill and join // all remaining solves. Otherwise we may leak handles. while (--b > 0) { handles[b].kill(); handles[b].join(); } throw; } } // Wait for the various LP solves to complete. for (BlockVector::size_type b = 0; b < blocks.size(); ++b) handles[b].join(); // See if we need to generate cuts. for (BlockVector::size_type b = 0; b < blocks.size(); ++b) { Block *const block = blocks[b]; cutVal.clear(); cutVar.clear(); double cutlb = -IloInfinity; double cutub = IloInfinity; // We ust STL types here since they are exception safe. std::vector<double> tmp(master->vars.getSize(), 0); std::map<IloNumVar,double,ExtractableLess<IloNumVar> > rayMap; // Depending on the status either seperate a feasibility or an // optimality cut. switch (block->cplex.getStatus()) { case IloAlgorithm::Unbounded: { // The subproblem is unbounded. We need to extract a feasibility // cut from an unbounded ray of the problem (see also the comments // at the top of this file). std::cout << "unbounded "; block->cplex.getRay(rayVals, rayVars); cutub = 0.0; for (IloInt j = 0; j < rayVars.getSize(); ++j) { cutub -= rayVals[j] * block->objMap[rayVars[j]]; rayMap[rayVars[j]] = rayVals[j]; } for (std::vector<Block::FixData>::const_iterator it = block->fixed.begin(); it != block->fixed.end(); ++it) tmp[it->col] -= it->val * rayMap[block->vars[it->row]]; for (IloInt j = 0; j < master->vars.getSize(); ++j) { if ( fabs (tmp[j]) > 1e-6 ) { cutVar.add(master->vars[j]); cutVal.add(tmp[j]); } } } break; case IloAlgorithm::Optimal: { // The subproblem has a finite optimal solution. // We need to check if this gives rise to an optimality cut (see // also the comments at the top of this file). std::cout << "optimal "; double const objval = block->cplex.getObjValue(); double const eta = x[etaind + b]; block->cplex.getValues(block->vars, rayVals); if ( objval > eta + 1e-6 ) { cutub = 0.0; for (IloInt j = 0; j < block->vars.getSize(); ++j) cutub -= rayVals[j] * block->objMap[block->vars[j]]; for (std::vector<Block::FixData>::const_iterator it = block->fixed.begin(); it != block->fixed.end(); ++it) tmp[it->col] -= it->val * rayVals[it->row]; for (IloInt j = 0; j < master->vars.getSize(); ++j) { if ( fabs (tmp[j]) > 1e-6 ) { cutVal.add(tmp[j]); cutVar.add(master->vars[j]); } } cutVal.add(-1.0); cutVar.add(master->vars[etaind + b]); } } break; default: std::cerr << "Unexpected status " << block->cplex.getStatus() << std::endl; error = true; break; } // If a cut was found then add that. if ( cutVar.getSize() > 0 ) { IloExpr expr(master->env); for (IloInt i = 0; i < cutVar.getSize(); ++i) expr += cutVar[i] * cutVal[i]; IloRange cut(getEnv(), cutlb, expr, cutub); expr.end(); std::cout << "cut found: " << cut << std::endl; add(cut).end(); } else std::cout << "no cuts." << std::endl; } cutVar.end(); cutVal.end(); rayVars.end(); rayVals.end(); x.end(); if ( error ) throw -1; }
// This routine separates Benders' cuts violated by the current x solution. // Violated cuts are found by solving the worker LP // IloBool separate(const Arcs x, const IloNumArray2 xSol, IloCplex cplex, const IloNumVarArray v, const IloNumVarArray u, IloObjective obj, IloExpr cutLhs, IloNum& cutRhs) { IloBool violatedCutFound = IloFalse; IloEnv env = cplex.getEnv(); IloModel mod = cplex.getModel(); IloInt numNodes = xSol.getSize(); IloInt numArcs = numNodes * numNodes; IloInt i, j, k, h; // Update the objective function in the worker LP: // minimize sum(k in V0) sum((i,j) in A) x(i,j) * v(k,i,j) // - sum(k in V0) u(k,0) + sum(k in V0) u(k,k) mod.remove(obj); IloExpr objExpr = obj.getExpr(); objExpr.clear(); for (k = 1; k < numNodes; ++k) { for (i = 0; i < numNodes; ++i) { for (j = 0; j < numNodes; ++j) { objExpr += xSol[i][j] * v[(k-1)*numArcs + i*numNodes + j]; } } } for (k = 1; k < numNodes; ++k) { objExpr += u[(k-1)*numNodes + k]; objExpr -= u[(k-1)*numNodes]; } obj.setExpr(objExpr); mod.add(obj); objExpr.end(); // Solve the worker LP cplex.solve(); // A violated cut is available iff the solution status is Unbounded if ( cplex.getStatus() == IloAlgorithm::Unbounded ) { IloInt vNumVars = (numNodes-1) * numArcs; IloNumVarArray var(env); IloNumArray val(env); // Get the violated cut as an unbounded ray of the worker LP cplex.getRay(val, var); // Compute the cut from the unbounded ray. The cut is: // sum((i,j) in A) (sum(k in V0) v(k,i,j)) * x(i,j) >= // sum(k in V0) u(k,0) - u(k,k) cutLhs.clear(); cutRhs = 0.; for (h = 0; h < val.getSize(); ++h) { IloInt *index_p = (IloInt*) var[h].getObject(); IloInt index = *index_p; if ( index >= vNumVars ) { index -= vNumVars; k = index / numNodes + 1; i = index - (k-1)*numNodes; if ( i == 0 ) cutRhs += val[h]; else if ( i == k ) cutRhs -= val[h]; } else { k = index / numArcs + 1; i = (index - (k-1)*numArcs) / numNodes; j = index - (k-1)*numArcs - i*numNodes; cutLhs += val[h] * x[i][j]; } } var.end(); val.end(); violatedCutFound = IloTrue; } return violatedCutFound; } // END separate
/**************************************************程序入口****************************************************/ int main() { clock_t start,finish; double totaltime; start=clock(); time_t nowTime=time(0); struct tm* nowTimeStruct=localtime(&nowTime);//打印系统时间 // output<<"系统当前时间:"<<1900+nowTimeStruct->tm_year<<"."<<nowTimeStruct->tm_mon+1<<"."<< // nowTimeStruct->tm_mday<<" "<<nowTimeStruct->tm_hour<<":"<<nowTimeStruct->tm_min<<":"<<nowTimeStruct->tm_sec<<endl; try { // output<<">>>>>>>>>>>>>>>>>>>>>>>>>数据区<<<<<<<<<<<<<<<<<<<<"<<endl; define_data(env);//首先初始化全局变量 // output<<">>>>>>>>>>>>>>>>>>>>>>>>>/数据区<<<<<<<<<<<<<<<<<<<"<<endl<<endl; IloInvert(env,B0,B0l,Node-1);//求逆矩阵 //在此创建两种形式的目标函数 IloNumExpr Cost(env);//目标函数 for(IloInt w=0;w<NW;++w) { Cost+=detaPw[w]; } IloObjective min(env,Cost,IloObjective::Sense::Minimize,"min"); IloObjective max(env,Cost,IloObjective::Sense::Maximize,"max"); Master_Model.add(min); // Master_Model.add(IloMaximize(env,Cost));//目标函数二选一 Cost.end(); IloNumExpr expr1(env),expr2(env);//功率平衡约束 for(IloInt i=0;i<NG;++i) { expr1+=detaP[i]; } for(IloInt w=0;w<NW;++w) { expr2+=detaPw[w]; } Master_Model.add(expr1+expr2==0); expr1.end(); expr2.end(); for(IloInt i=0;i<NG;++i)//机组可调节范围 { Master_Model.add(detaP[i]>=Unit[i][1]*u[i]-P1[i]); Master_Model.add(detaP[i]<=Unit[i][2]*u[i]-P1[i]); Master_Model.add(detaP[i]>=-detaa[i]); Master_Model.add(detaP[i]<=detaa[i]); } IloNumExprArray detaP_node(env,Node-1),detaPw_node(env,Node-1);//安全约束,实际上安全约束影响不大 IloNumExprArray Theta(env,Node); for(IloInt b=0;b<Node-1;++b) { detaP_node[b]=IloNumExpr(env); detaPw_node[b]=IloNumExpr(env); IloInt i=0; for(;i<NG;++i) { if(Unit[i][0]==b-1)break; } if(i<NG) { detaP_node[b]+=detaP[i]; } if(Sw[b]>=0) { detaPw_node[b]+=detaPw[ Sw[b] ]; } } for(IloInt b=0;b<Node-1;++b) { Theta[b]=IloNumExpr(env); for(IloInt k=0;k<Node-1;++k) { Theta[b]+=B0l[b][k]*(detaP_node[k]+detaPw_node[k]); } } Theta[Node-1]=IloNumExpr(env); for(IloInt h=0;h<Branch;++h) { IloNumExpr exprTheta(env);//莫明其妙的错误 exprTheta+=(Theta[(IloInt)Info_Branch[h][0]-1]-Theta[(IloInt)Info_Branch[h][1]-1]); Master_Model.add(exprTheta<=Info_Branch[h][3]*(Info_Branch[h][4]-PL[h])); Master_Model.add(exprTheta>=Info_Branch[h][3]*(-Info_Branch[h][4]-PL[h])); exprTheta.end(); //两个相减的节点顺序没有影响么? } Theta.end(); detaP_node.end(); detaPw_node.end(); Master_Cplex.extract(Master_Model); Master_Cplex.solve(); if (Master_Cplex.getStatus() == IloAlgorithm::Infeasible)//输出结果 { output<<"Master Problem Have No Solution"<<endl; goto lable2; } /************************************************************输出显示过程**************************************************/ // output/*<<endl<<"Min:"*/<<Master_Cplex.getObjValue()<<endl; Master_Model.remove(min); Master_Model.add(max); Master_Cplex.extract(Master_Model); Master_Cplex.solve(); if (Master_Cplex.getStatus() == IloAlgorithm::Infeasible)//输出结果 { output<<"Master Problem Have No Solution"<<endl; goto lable2; } output/*<<endl<<"Max:"*/<<Master_Cplex.getObjValue()<<endl<<endl;; // output<<endl<<"常规机组出力调整量:"<<endl; // for(IloInt i=0;i<NG;++i) // { // output<<Master_Cplex.getValue(detaP[i])<<" "; // } // output<<endl<<"风电机组出力调整量:"<<endl; // for(IloInt i=0;i<NW;++i) // { // output<<Master_Cplex.getValue(detaPw[i])<<" "; // } // output<<endl; lable2: Master_Model.end(); Master_Cplex.end(); env.end(); } catch(IloException& ex)//异常捕获 { output<<"Error: "<<ex<<endl; } catch(...) { output<<"Error: Unknown exception caught!" << endl; } finish=clock(); totaltime=(double)(finish-start)/CLOCKS_PER_SEC; output<<"totaltime: "<<totaltime<<"s"<<endl<<endl; output.close(); return 0; }