我正在尝试运行一个大规模的线性程序,并将我以前的一些代码从MATLAB翻译成Python。然而,问题是MATLAB和Python给了我极其矛盾的答案:MATLAB代码找到了最佳解决方案,但Python代码说这个问题是不可行的。这是ell_infinity回归或minimax回归的LP建模。我对这两个功能的设置非常有信心。
MATLAB代码:
function [ x_opt, f_opt, exitflag, output] = ell_infinity_reg_solver( A, b )
% Solves the ell_infinity regression problem ||Ax - b||_inf. That is finds
% the least t for which Ax - b < t.ones and Ax - b > -t.ones.
[n,d] = size(A) ;
if n == 0
f_opt = 0 ;
x_opt = zeros(d,1) ;
return
end
% infinity norm
f = [ zeros(d,1); 1 ];
A = sparse([ A, -ones(n,1) ; -A, -ones(n,1) ]);
b = [ b; -b ];
[xt, f_opt, exitflag, output] = linprog(f,A,b);
x_opt = xt(1:d,:);
end
Python代码
from scipy.optimize import linprog
import numpy as np
def ell_infinity_regression_solver(A, b):
"""Compute the solution to the ell_infinity regression problem.
x_hat = arg min_x ||Ax - b||_infty by a reformulating as LP:
min t :
Ax - b <= t * ones
b - Ax >= - t*ones
i.e. finds minimal radius ball enclosing distance between all data points
and target values b.
Input:
A - array or datafram of dimension n by d
b - target vector of size n by 1.
Output:
x_opt which solves the optimisation.
f_opt the radius of the enclosing ball
"""
n,d = A.shape
# include a check on n and d to ensure dimensionality makes sense
if n > 0:
f = np.vstack((np.zeros((d,1)), [1])).ravel()
print("shape of f {}".format(f.shape)) # should be d+1 length
big_A = np.hstack((np.vstack((A,-A)), np.ones((2*n,1))))
print("shape of big_A {}".format(big_A.shape)) # should be 2n*(d+1)
#big_b = np.vstack((b,-b)) # should be length 2n
big_b = b.append(-b) # only works for data frames -- switch to np array?
print("Type of b {}".format(type(b)))
print("Shape of b {}".format(b.shape))
print("shape of big_b {}".format(big_b.shape))
output = linprog(f, A_ub=big_A, b_ub=big_b)
#print(output)
else:
f_opt = 0
x_opt = np.zeros_like(b)
return output
由于scipy
方法不起作用,我还尝试使用添加的行CVXOPT
c = cvxopt.matrix(f)
G = cvxopt.matrix(X)
h = cvxopt.matrix(Y)
output = cvxopt.solvers.lp(c, G, h, solver='glpk')
但是这又返回了dual-infeasible
的标志,该标志与使用的MATLAB exitflag=1
(成功)和dual-simplex
算法形成对比。
我测试的数据是一个500乘11的数据矩阵,带有一组相关的响应变量。
我对产生如此显着差异的原因感兴趣,哪些是正确的。确实增加混淆的一件事是将输入的大小减小到小于全等级的那个似乎不会影响MATLAB输出标志但是Python代码没有找到最佳解决方案(如我想是的。)
数据位于https://www.dropbox.com/s/g4qcj1q0ncljawq/dataset.csv?dl=0,矩阵A是前11列,目标向量是最后一列。
答案 0 :(得分:1)
(1)默认变量边界几乎总是零和无穷大。即,除非另有说明,否则大多数求解器假设非负变量。 Matlab使用不同的默认值。默认变量是免费的。
对于您的模型,这意味着您需要明确告诉linprog
x
变量是免费的。 t
变量可以是免费的也可以是非负的。
因此
output = linprog(f, A_ub=big_A, b_ub=big_b, bounds=(None,None),method='interior-point' )
对于单纯形法,该模型有点大(Simplex实现有点像玩具算法)。新的内点法没有问题。
(2)该行
big_A = np.hstack((np.vstack((A,-A)), np.ones((2*n,1))))
应该阅读
big_A = np.hstack((np.vstack((A,-A)), -np.ones((2*n,1))))
(3)另请注意您的模型
min t :
Ax - b <= t * ones
b - Ax >= - t*ones
不正确。它应该是:
min t :
Ax - b <= t * ones
Ax - b >= - t*ones
这给出了LP输入:
min t :
Ax - t <= b
-Ax - t <= -b
(还有其他针对此问题的表述,有些不会存储A两次。请参阅[link])