1. 上手
1.1 快速使用
首先是简单的调用测试,在mac上首先安装clp的库:brew install coin-or-tools/coinor/cbc
,然后新建项目进行调用,各项配置如下,注意要添加的library和directory比较多:
1.2 命令行方式
安装完cbc后,可以直接输入cbc调出命令行:
或者直接一行调用:
cbc air03.lp solve solu sol.txt
求解的几个配置:
Sec :默认Infinity,最多允许的执行时间
MaxN: 默认Infinity : 最多允许搜索的节点数。防止内存溢出
MaxS : 默认Infinity : 做多允许存储的可行解数量。如果只想要一个可行解,可以把这个数值设置为1.
2. 基本调用方法
标识 | 类名 | 说明 |
---|---|---|
A | CbcBranch… | MIP的非连续类,比如说整数变量、0-1变量 |
B | CbcNode | 接下来进行branch的节点 |
C | CbcTree | CbcNode的集合 |
D | CbcCompare… | 在CbcTree上决定下一步探索那个Node的函数,可以修改 |
E | CglCutGenerators | CGL中的cut generator,很少有人自己写 |
F | CbcHeuristics | 启发式算法 |
2.1 model和solver
需要首先定义一个线性规划的solver,传入model中。
model的方法和solver的方法很多是一致的,比如model.getNumCols() 以及model.solver()->getNumCols(),但是同步性有时会有差别,比如getColSolution() ,CbcModel可能不是最新的结果,这时可以用CbcModel::bestSolution()来获取结果。
当然两者还是有差别的,比如用来减少输出显示的代码:
model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry);
在model中就没有。
2.2 获取结果信息
2.3 预处理和cut选项
-
Prep : 预处理,默认sos
sos: creates Special Ordered Sets [CITE] to improve branching
off: turns of pre-processing
equal : turns ≤ clique constraints into equality clique constraints -
PassP : 默认5
-
Cuts : 默认On
-
Clique : 默认IfMove
Off : never try this cut;
Root : cuts applied only at root node;
IfMove : cuts will be used of they succeed on improving the dual bound;
ForceOn : forces the use of the cut generator at every node. -
Lift(liftAndProjectCuts) : 默认Off
-
Mixed(MixedIntegerRounding) : 默认IfMove
-
Two(TwoMirCuts) : 默认Root : Determines the application Two phase Mixed Integer Rounding cuts.
-
Knapsack : 默认IfMove
-
Flow : 默认IfMove
-
Probing(ResidualCapacityCuts) : 默认forceOnStrong
除了上述选项外,还包含:forceOn, forceOnGlobal, forceOnStrong, forceOnButStrong and strongRoot. -
Residual(ResidualCapacityCuts) : 默认Off
-
CutD(CutDepth): 默认-1
当深度为CutD的倍数时进行cut。CutD=-1时,由cbc来自动判断。 -
CutL(CutLength): 默认-1
gomory cuts允许的最大cut数目。默认情况由cbc决定:
0 ≤ CutL < 10, 000, 000 : maximum length of CutL for cuts generated at root node and in the tree;
CutL ≥ 10, 000, 000 : allows cuts with unlimited length at root node, with a limit inside the tree. for example: CutL =10,000,130 indicate that in the tree only cuts with at most 130 variables will be accepted. -
PassC(PassCuts) : 默认-1
根节点cut passes最大数目。如果是 -1, 使用以下策略,其中n是变量数(column number):
n ≤ 500 : 100 passes;
500 < n ≤ 5000 : 100 passes, stopping when bound improvements are small;
n ≥ 5000 : 20 passes for larger problems.
2.4 启发式算法
- Round:在每次搜索时启用rounding heuristic
- Feas : 在根节点启动feasibility pump heuristic。使用一系列LPs,尝试获取integer feasible solution.
- PassF(PassFeasibilityPump): 默认30。Feasibility Pump heuristic的最大允许pass数目。若没有获得初始可行解,可以尝试将数值提升。
- Local(LocalTreeSearch):默认off
- PivotAndC( PivotAndComplement):默认Off
- PivotAndF(PivotAndFix):默认Off
- Combine : 默认On
在多次求解之后,仅尝试对出现过多次的变量进行b&c - Combine2 : 默认Off
比上面的要求更严格,要求出现多次且数值相同。 - Rins : 默认On
控制Relaxation Induced Neighborhood Search heuristic. - Rens : 默认Off
控制Relaxation Enforced Neighborhood Search heuristic. - Vnd(VndVariableNeighborhoodSearch):默认Off
控制Variable Neighborhood Search heuristic. - DivingG(DivingGuided) : 默认Off.
切换为Guided Dives heuristic - DivingP(DivingPseudoCost): 默认Off.
切换为使用pseudo costs的Diving heuristic . - DivingF(DivingFractional): 默认Off.
切换为Diving Fractional heuristic. - DivingS(DivingSome): 默认Off.
切换为random diving heuristic at various times.
此外,cbc只有一个rounding heuristic,可以自定义启发式算法。
3. 选择下一个搜索节点
使用CbcCompare来控制如何选择搜索节点。已经定义好的实现如下
类型 | 描述 |
---|---|
CbcCompareDepth | 一直探索最深的树节点 |
CbcCompareObjective | 一直探索当前目标函数最佳的树节点 |
CbcCompareDefault | 在可行解找到前使用depth-first。当一定数量的nodes被探索过、或者一定数量的解被发现后,改用breadth-first搜索;然后当树到达一定的尺寸后,再改为depth-first |
CbcCompareEstimate | 当pseudo cost启用时,可以用来猜测解 |
要自己实现的话,参考使用下面的函数:
修改CbcCompareUser.hpp和CbcCompareUser.cpp中CbcCompare的bool test(CbcNode* x, CbcNode* y)) 函数:当node y优先于node x,返回true。
CbcCompareUser::test()方法代码如下:
// Returns true if y better than x
bool
CbcCompareUser::test (CbcNode * x, CbcNode * y)
{
if (weight_==-1.0) {
// before solution
if (x->numberUnsatisfied() > y->numberUnsatisfied())
return true;
else if (x->numberUnsatisfied() < y->numberUnsatisfied())
return false;
else
return x->depth() < y->depth();
} else {
// after solution.
// note: if weight_=0, comparison is based
// solely on objective value
double weight = CoinMax(weight_,0.0);
return x->objectiveValue()+ weight*x->numberUnsatisfied() >
y->objectiveValue() + weight*y->numberUnsatisfied();
}
}
tree是无状态的。newSolution()方法在每次新的解发现时调用,另外每1000次探索后调用every1000Nodes(),此时可以修改test()中的变量(e.g., weight_).同时由于CbcNode有model指针,因此同时可以修改诸如最大允许时间等变量 (e.g., CbcModel::setMaximumSeconds(double value))