如何为Scipy milp功能读取MPS格式文件?
解决Scipy MILP读取MPS文件的问题
方法1:使用第三方库mps-reader
这是专门用于读取MPS格式文件的轻量Python库,能直接将MPS数据转换成适配Scipy MILP的结构:
- 安装库:
pip install mps-reader
- 读取并转换为Scipy MILP参数:
from mps_reader import read_mps from scipy.optimize import milp, LinearConstraint # 读取MPS文件 mps_data = read_mps("your_problem.mps") # 提取目标函数系数 c = mps_data["obj"] # 构建约束矩阵与上下界 A = mps_data["A"] lb = mps_data["lb"] ub = mps_data["ub"] constraints = LinearConstraint(A, lb, ub) # 提取整数变量标记(0表示连续,1表示整数) integrality = mps_data["int_vars"] # 调用Scipy MILP求解 result = milp(c=c, constraints=constraints, integrality=integrality) print(result.x)
方法2:手动解析MPS文件(无需额外依赖)
如果不想安装第三方库,可以基于MPS文件的标准格式手动解析核心内容。MPS文件主要包含NAME、ROWS、COLUMNS、RHS、BOUNDS、ENDATA等段,核心是提取目标系数、约束矩阵、变量上下界和整数标记:
from scipy.optimize import milp, LinearConstraint import numpy as np def read_mps_manual(file_path): c = [] A_rows = [] A_cols = [] A_data = [] rhs = {} bounds = {} int_vars = [] row_types = {} var_names = [] with open(file_path, 'r') as f: section = None for line in f: line = line.strip() if not line: continue # 识别段落 if line.startswith('NAME'): section = 'NAME' elif line.startswith('ROWS'): section = 'ROWS' elif line.startswith('COLUMNS'): section = 'COLUMNS' elif line.startswith('RHS'): section = 'RHS' elif line.startswith('BOUNDS'): section = 'BOUNDS' elif line.startswith('ENDATA'): break # 处理ROWS段:记录约束类型(目标是N,约束是L/G/E) if section == 'ROWS': parts = line.split() row_type, row_name = parts[0], parts[1] row_types[row_name] = row_type # 处理COLUMNS段:提取目标系数和约束矩阵元素 elif section == 'COLUMNS': parts = line.split() var_name = parts[0] if var_name not in var_names: var_names.append(var_name) int_vars.append(0) # 默认连续变量,后续BOUNDS段标记整数 # 处理第一个行和系数 row1, val1 = parts[1], float(parts[2]) if row1 == 'OBJ': c.append(val1) else: A_rows.append(list(row_types.keys()).index(row1)) A_cols.append(var_names.index(var_name)) A_data.append(val1) # 处理第二个行和系数(如果有) if len(parts) > 3: row2, val2 = parts[3], float(parts[4]) if row2 == 'OBJ': c.append(val2) else: A_rows.append(list(row_types.keys()).index(row2)) A_cols.append(var_names.index(var_name)) A_data.append(val2) # 处理RHS段:提取约束右侧值 elif section == 'RHS': parts = line.split() rhs_name = parts[1] val = float(parts[2]) rhs[rhs_name] = val if len(parts) >3: rhs_name2 = parts[3] val2 = float(parts[4]) rhs[rhs_name2] = val2 # 处理BOUNDS段:提取变量上下界和整数标记 elif section == 'BOUNDS': parts = line.split() bound_type = parts[0] var_name = parts[2] var_idx = var_names.index(var_name) if bound_type == 'LO': bounds[var_idx] = {'lb': float(parts[3]), 'ub': bounds.get(var_idx, {}).get('ub', np.inf)} elif bound_type == 'UP': bounds[var_idx] = {'lb': bounds.get(var_idx, {}).get('lb', -np.inf), 'ub': float(parts[3])} elif bound_type == 'FX': bounds[var_idx] = {'lb': float(parts[3]), 'ub': float(parts[3])} elif bound_type == 'INT': int_vars[var_idx] = 1 # 构建约束矩阵 A = np.zeros((len(row_types)-1, len(var_names))) # 减去OBJ行 for r, c_idx, val in zip(A_rows, A_cols, A_data): A[r, c_idx] = val # 构建约束上下界 lb = [] ub = [] for row_name in row_types: if row_name == 'OBJ': continue rt = row_types[row_name] rh = rhs.get(row_name, 0) if rt == 'L': lb.append(-np.inf) ub.append(rh) elif rt == 'G': lb.append(rh) ub.append(np.inf) elif rt == 'E': lb.append(rh) ub.append(rh) # 构建变量上下界(默认-∞到∞) var_lb = [-np.inf]*len(var_names) var_ub = [np.inf]*len(var_names) for idx, b in bounds.items(): var_lb[idx] = b['lb'] var_ub[idx] = b['ub'] return { 'c': np.array(c), 'A': A, 'constraint_lb': np.array(lb), 'constraint_ub': np.array(ub), 'var_lb': np.array(var_lb), 'var_ub': np.array(var_ub), 'integrality': np.array(int_vars) } # 使用示例 mps_data = read_mps_manual("your_problem.mps") constraints = LinearConstraint(mps_data['A'], mps_data['constraint_lb'], mps_data['constraint_ub']) result = milp( c=mps_data['c'], constraints=constraints, integrality=mps_data['integrality'], bounds=(mps_data['var_lb'], mps_data['var_ub']) ) print(result.x)
注:手动解析代码仅适配MPS基础格式,复杂扩展格式(如分段约束、特殊变量类型)需额外调整。
内容的提问来源于stack exchange,提问作者Simd
相关产品推荐
相关产品推荐

