buq’s blog

覚えておきたいけど覚えておけなさそうなことを書きます?

pulp のバグ:目的関数が零のとき valid() の返り値が正しくない

python の LP/MIP ソルバー(のラッパー)である pulp のバグをみつけたのでメモ. GitHub - coin-or/pulp: A python Linear Programming API

具体的には,目的関数がゼロの場合,ダミー変数が現れて solve() 後の valid() (現在の解が実行可能かどうか)の挙動が正しくなくなる.

サンプル

import pulp

mip1 = pulp.LpProblem('****** MIP1 ******')
x = pulp.LpVariable('x')
mip1 += (0 * x)
mip1 += (x >= 1)

mip1.solve()
print mip1
print 'x', x.value()
print mip1.valid()
print

mip2 = pulp.LpProblem('****** MIP2 ******')
y = pulp.LpVariable('y')
mip2 += (1 * y)
mip2 += (y >= 1)

mip2.solve()
print mip2
print 'y', y.value()
print mip2.valid()

出力(# 以降は注釈)

****** MIP1 ******:
MINIMIZE
0*__dummy + 0
SUBJECT TO
_C1: x >= 1

VARIABLES
__dummy = 0 Continuous # 自分で定義していないダミー変数が現れている
x free Continuous

x 1.0
False # validでないと判定される.しかし,x = 1.0 は明らかに実行可能.

****** MIP2 ******:
MINIMIZE
1*y + 0
SUBJECT TO
_C1: y >= 1

VARIABLES
y free Continuous

y 1.0
True

理由はダミー変数 __dummy の値が零でなく None になるから.

for v in mip1.variables():
    print v, v.value()

出力:

__dummy None
x 1.0

LpProblem.valid() は問題に現れるすべての変数,制約が valid であれば True を返すが, 変数の値が None のとき,変数は valid ではないという実装になっているのが問題. おそらく正しい解決は,ダミー変数の値のデフォルトを 0 にすること? ダミー変数のポリシーとかよく分かっていないのでプルリクを送るには至っていない.

4月8日追記 issueたてた