我正在使用 AMPL 来优化一系列值,并且我想指定一个规则,该序列不能连续包含两个以上的负值。我通过在序列为负时声明一个二进制来标记来实现这一点:
var InventoriesDecrease{Years} binary;
param BigNumber := 1111112;
subject to EnforceInventoriesDecreaseFlag{y in Years}:
BalancedUse[y,"Change in Inventories"] >= (0 - BigNumber*InventoriesDecrease[y]);
意图是对于给定的年份,如果 InventoriesDecrease 标志为零,则库存变化必须 >= 0,如果 InventoriesDecrease 标志为 1,则必须 >=(大负数)。
然后,我使用另一个约束强制执行“不超过 2 个连续否定”规则:
param MaxConsecutiveDecreasesInInventory := 2;
param NumYearsInSeries := card(Years);
subject to EnforceMaxConsecutiveDecreases
{y in Years: ord(y,Years) <= NumYearsInSeries-MaxConsecutiveDecreasesInInventory}:
sum{y2 in Years: ord(y,Years)<=ord(y2,Years)<=ord(y,Years)+MaxConsecutiveDecreasesInInventory}
(InventoriesDecrease[y2])
<=
MaxConsecutiveDecreasesInInventory;
当我将 BigNumber 设置为 1111111 时,我得到了预期的结果——输出在库存变化中不超过两个连续的负数。(对于我正在研究的经济问题,这实际上不是一个好的解决方案,但没关系。)检查 InventoriesDecrease 的值会给我一个类似 1 1 0 1 0 1 1 ...
但是当我将 BigNumber 设置为 1111112 时,它每年都会对库存变化产生负面影响。查看 InventoriesDecrease,这些值要么是 1,要么是非常小的非整数正数,大约为 1E-5 左右。这使得库存的变化每年都是负数(因为现在的下限是 BigNumber * 1E-5 ~ 100 而不是 BigNumber * 0 = 0)。
如果我将 BigNumber 设置为 1111111 这不会发生;看起来好像然后精确地强制执行二元约束(或至少比〜 1E-5 更小的容差),因此“不超过 2 个连续否定”规则按预期工作。据推测,BigNumber 的大小会影响在 InventoriesDecrease 上设置的容差。(求解器 = Gurobi,但我在使用 CPLEX 时遇到了类似的问题。)
我希望使用一些相当大的数字,所以我想更好地了解触发这种行为的原因。我找到了http://www.ampl.com/NEW/tolerate.html但有几个“即将到来”,最后一次更新是在 1996 年,所以我没有屏住呼吸 :-)
(我也有点惊讶,十进制 1111111 是这种行为的阈值;我本来期望大约是 2 的幂!)