跳转到内容

GLPK/故障排除

来自维基教科书,开放的书籍,开放的世界

此页面讨论使用 GLPK 时偶尔会遇到的问题。并且,在可能的情况下,提供典型的 GLPK 警告消息以帮助诊断。


混合整数问题的连续解

[编辑 | 编辑源代码]

您成功地使用对glp_intopt的调用解决了您的 MIP 问题,然后发现最佳解决方案不是预期中的整数值。

检查您是否使用正确的例程查找信息。您应该使用glp_mip_col_val, glp_mip_row_val,以及glp_mip_obj_val来恢复 MIP 解决方案。相反,例程glp_get_col_primglp_get_row_prim返回 LP 松弛的解决方案。

MPS 格式和 OBJSENSE

[编辑 | 编辑源代码]

看起来很奇怪,MPS 线性程序问题格式的规范包含目标方向的说明符。也没有标准的默认值 - 无论是最小化还是最大化。但 GLPK 假设目标是 MPS 文件中的最小化。一些求解器接受非标准的OBJSENSE说明符作为对 MPS 规范的扩展,但 GLPK 会静默地忽略此关键字。

如果使用 GLPSOL,可以通过命令行设置目标方向--min--max。严格来说,使用--min是多余的。如果您不想使用--max,则可以将目标函数系数乘以 -1。解决方案将被正确报告,但目标值将保留错误的符号。

如果您的目标值为,而您期望的是其他值,那么您可能无意中部署了错误的目标方向。

导出时忽略目标偏移项

[编辑 | 编辑源代码]

目标函数中的常数项在 GLPK 中被称为“偏移”项。如果您在 GLPK 下运行模型,此项将被考虑在内。但如果您将模型导出到 CPLEX LP 和 MPS 格式,则此项不会被传输。这将导致变量值正确,但目标值将与“偏移”项不同。

在以下模型中,目标的常数项为 5。

var x, >=0; 
minimize obj : x + 5;

此文件可以使用以下命令导出到 CPLEX 格式

glpsol -m test.mod --wlp test.lp --check

控制台输出包含一个警告

glp_mpl_build_prob: row obj; constant term 5 ignored

导出的文件包含一个带有常数项的注释。

\* Problem: test *\

Minimize
 obj: + x
\* constant term = 5 *\

Subject To

End

为了规避这个问题,可以引入一个额外的变量和约束 [1]

var x, >=0; 
var v_dummy;
s.t. c_dummy : v_dummy = x + 5;
minimize obj : v_dummy;

内存不足

[编辑 | 编辑源代码]

对于某些优化问题,内存,而不是处理能力,可能是系统约束。如果 GLPK 无法通过操作系统获得对 RAM 内存的请求,它应该报告(然后失败)

umalloc: size = 166550392; no memory available

此消息意味着 GLPK 例程尝试从系统中获得一个 166.6 Mb 的内存块,但尝试失败 - 也就是说,对malloc的系统调用返回NULL。这意味着您的问题没有足够的 RAM(或者内存正在从某个进程泄漏,但不太可能是从 GLPK 泄漏)。

此外,如果 GLPK 由于内存不足而异常终止,它始终会向标准输出打印一条消息。如果未显示任何消息,则异常终止不是由 GLPK 引起的(尽管存在 GLPK 错误)。

以下线程讨论了 GLPK 对内存的使用,可能为一些内存消耗计算提供一个有用的起点。

一些背景

[编辑 | 编辑源代码]

glp_prob问题对象,在 API 级别,需要额外的内存来存储各种 GLPK 例程使用的辅助信息。例如,存储在object中的一个约束矩阵元素(类型为glp_probdoubleglp_prob)需要 32 字节(在 32 位平台上),而不是 8 字节。因此,存储在

object

中的 LP 实例比用一组普通数组表示的要多消耗大约四倍的内存,当部署了 LP 预处理器时,要多消耗大约十倍的内存。

使用 GLPSOL 拆分作业

[编辑 | 编辑源代码]为了减少使用 GLPSOL 时的内存需求,您可以拆分作业,如下所示:

glpsol --model foo.mod --data foo.dat --check --wglp foo.glp

翻译模型并将其写入foo.glp:

glpsol --glp foo.glp --write foo.sol

解决已翻译的模型,并将它的解写入

glpsol --model foo.mod --data foo.dat --read foo.sol

foo.sol使用先前找到的解决方案处理模型另请注意,数据文件foo.dat使用先前找到的解决方案处理模型是可选的,而

foo.mod

(如果存在)在步骤一和步骤三之间必须保持不变。

使用 API 明智地使用内存[编辑 | 编辑源代码], LP 问题通常使用稀疏矩阵构建。最常用的问题构建 API 调用是,以及glp_set_mat_rowglp_set_mat_col

  • glp_load_matrix
  • 。为了最小化内存消耗

只复制非零值

ind = GLPK.new_intArray(3);
GLPK.intArray_setitem(ind, 1, 1);
GLPK.intArray_setitem(ind, 2, 2);
val = GLPK.new_doubleArray(3);
GLPK.doubleArray_setitem(val, 1, 1.);
GLPK.doubleArray_setitem(val, 2, -1.);
GLPK.glp_set_mat_row(lp, 1, 2, ind, val);
GLPK.delete_doubleArray(val);
GLPK.delete_intArray(ind);

在使用后删除临时数组和向量

以下示例使用 GLPK 的Java 包装器 - 而不是本机的C 语言接口

当然,另一种策略是增加系统内存。添加 DRAM 显然是最佳选择。另一种选择是检查您的 交换分区 并将其增加到 DRAM 容量的 8 倍,或迁移到 固态硬盘

数值不稳定性

[编辑 | 编辑源代码]

一位用户报告说,在使用 GLPK API 求解数百万个微小的自动生成的 LP 时,偶尔会遇到以下控制台消息

Warning: numerical instability (primal simplex, phase II)

这意味着单纯形求解器检测到当前基本解由于过大的舍入误差而变得不可行。在这种情况下,求解器会自动切换到阶段 I 以恢复可行性,然后继续搜索。如果求解器例程返回 0,则可以认为该解在当前工作精度内是准确的。GLPK 例程lpx_check_kkt随后可用于检查解是否满足可行性和最优性的各种条件,如 此处此处 所述。有关更多信息,请参见此 线程

从 GLPK 4.46 开始,计划采用更稳健的策略来处理数值不稳定性。此新版本将意味着这些不稳定性警告将不再出现。有关一些详细信息,请参见 2011 年 4 月的此 帖子

内点求解器

[编辑 | 编辑源代码]

用户应注意,内点求解器在求解牛顿系统时,有时会由于数值不稳定性而过早地终止其对解的搜索。在这种情况下,应使用更稳健的单纯形求解器。此 2011 年的 帖子 包含更多详细信息。

缓慢的模型

[编辑 | 编辑源代码]

有时,建模者会创建一个难以解决的问题。对于纯(IP)和混合整数(MIP)模型,这种情况比严格的线性(LP)模型更常见。另一方面,GLPK 使用的分支定界方法可以以不同的方式运行,切换到另一种变体可能会成功。

大多数这些变体可以通过 GLPSOL 使用其 **命令行选项** 进行访问。API 自然提供了更大的灵活性。例如,从默认的 GLPSOL 选项切换到--gomory—pcost对于一个玻璃制造模型,它在 2 分钟内产生了解,而对于另一个原本很慢的模型,它却很痛苦。

或者,模型可以 **重新表述** 以提高其易处理性或减小其大小。

最后一个选项是尝试 **另一个求解器**。您的问题类别可能更适合专门的求解器。最后,众所周知,高调的商业求解器比其免费软件对应产品更快、更健壮。

约束编程问题

[编辑 | 编辑源代码]

MIP 求解器通常在 约束编程 问题上表现不佳。GLPK 也不例外。

如果您的实例是纯 0-1 且约束系数是整数,请尝试使用 **MiniSat** 求解器。此专业求解器受 GLPSOL 支持,也可以通过 GLPK API 获得。MiniSat 本身在 此处 有介绍。

调用--minisat选项(如果使用 GLPSOL),在这种情况下,GLPK 会将您的实例转换为可满足性问题,并使用minisat求解器进行求解。详细信息在 GLPK 参考手册中给出。示例模型(“按数字绘画”拼图)可以在以下子目录中找到:glpk/examples/pbn。您可以使用--objbnd选项除了识别更好的整数可行解。此选项上的bound参数在目标函数上引入了额外的不等式约束。检查--help消息以获取使用详细信息。

一位用户 报告说,一个传统上需要 15 小时才能解决的问题,使用 MiniSat 求解器“几乎可以立即”解决。

超线程硬件

[编辑 | 编辑源代码]

有点矛盾的是,强大的多核 超线程 硬件可能会导致 GLPK 的性能下降。可以通过更改您的 BIOS 设置来禁用超线程。事实上,这可能会使您的速度提高一倍。有关更多信息,请参见 2013 年初的此 帖子

解排序

[编辑 | 编辑源代码]

如果您需要快速列出行和列,并按 GLPSOL 处理它们的顺序进行排列,请使用以下命令

glpsol --output quick.out --tmlim 1

系统时间同步错误

[编辑 | 编辑源代码]

在 4.47 版本之前,每当系统时钟被读取两次且新读取的时间戳小于先前读取的时间戳时,GLPK 断言就会失败——这种情况会在 GLPK 运行期间操作系统与 NTP 服务器同步时发生。有关原始错误报告,请参见 此处,有关该主题的一些更多流量,请参见 此处。此错误现在从 4.47 版本开始修复。

数据库和电子表格问题

[编辑 | 编辑源代码]

请参见 ODBC 页面

编译时问题

[编辑 | 编辑源代码]

一些故障排除提示在 此处 给出。

预编译二进制文件

[编辑 | 编辑源代码]

确保在 64 位系统上使用 64 位二进制文件,在 32 位系统上使用 32 位二进制文件。这似乎更多是 Windows 用户的问题。

华夏公益教科书