"""
Description: A Python script to read .mps files which contain MILP problems and convert them to numpy format.
"""
import pulp # library used to read .mps files
from pulp import *
import numpy as np
import time
from pulp.constants import LpConstraintEQ, LpConstraintLE, LpConstraintGE
from branch_and_bound import BnB
write_flag = False # change to True if you want to write .json and .lp
# read .mps file
info = pulp.LpProblem.fromMPS("./B&B/22433.mps") # read .mps file
# The variable 'info' is a tuple of size 2.
# - The first entry, info[0] holds a dict of variable names
# - The second entry, info[1] holds a pulp.LpProblem
lp_problem = info[1]
# Returns a list of pulp.LpVariables
lp_variables = lp_problem.variables()
# Returns the objective of the LP as a pulp.LpAffineExpression
lp_objective = lp_problem.objective
# Maximize or Minimization problem
type_lookup = {1: 'minimize', -1: 'maximize'}
print(f"Type: {type_lookup[lp_problem.sense]}")
# Print the name of the LP
print(f"Problem name: {lp_problem.name}")
if write_flag:
# Convert to .json format (messy and hard to read)
lp_problem.toJson("./B&B/example_info.json")
# Write the LP in .lp format (This is easy for humans to read)
lp_problem.writeLP("./B&B/example_info.lp")
# If you want you can enumerate all the constraints (I wouln't suggest doing this for large LPs)
# for name, constraint in problem.constraints.items():
# print(f"{name}: {constraint}")
# Convert the pulp.LpProblem to numpy format
print("Converting .mps to numpy format...")
start = time.time()
# Obtain the coefficients of the objective, i.e. c'x
c = np.array([lp_problem.objective.get(var, 0) for var in lp_problem.variables()])
# Hold constraints
A_lt = [] #Ax <= b
b_lt = []
A_eq = [] # Ax = b
b_eq = []
for constraint in lp_problem.constraints.values():
row = [constraint.get(var, 0) for var in lp_problem.variables()] # Coefficients of the constraint
if constraint.sense == LpConstraintEQ: # a'x = b constraint
A_eq.append(row)
b_eq.append(-constraint.constant)
# b_eq.append(constraint.constant)
# print(f"{constraint.constant}")
elif constraint.sense == LpConstraintLE: # a'x <= constraint
A_lt.append(row)
b_lt.append(-constraint.constant)
# b_lt.append(constraint.constant)
elif constraint.sense == LpConstraintGE:
negative_row = [-element for element in row] # a'x >= constraint
A_lt.append(negative_row)
b_lt.append(constraint.constant)
# b_lt.append(-constraint.constant)
# convert to numpy
A_lt = np.array(A_lt)
b_lt = np.array(b_lt)
A_eq = np.array(A_eq)
b_eq = np.array(b_eq)
# Extract the integer and binary constraints
binary_variables = []
integer_variables = []
continuous_variables = []
bounds = []
integrality_args = [0]*len(c) # Passes to the linprog if the variable is interger (1) or continuous (0)
for idx, var in enumerate(lp_problem.variables()):
bounds.append((var.lowBound, var.upBound))
if var.cat == 'Integer': # integer constraint
# bounds.append((0.0, None))
integer_variables.append(idx)
# integrality_args[idx] = 1
elif var.cat == 'Binary': # binary constraint
# bounds.append((0.0, None))
binary_variables.append(idx)
else:
# bounds.append((var.lowBound, var.upBound))
# bounds.append((0.0, None))
continuous_variables.append(idx) # continuous constraint
binary_variables = np.array(binary_variables)
integer_variables = np.array(integer_variables)
continuous_variables = np.array(continuous_variables)
integrality_args = integrality_args if sum(integrality_args) != 0 else 0
end = time.time()
print(f"Finished conversion, took {round(end-start, 5)} sec")
from scipy.optimize import linprog
print("Now starting to solve relaxed MILP...")
if A_lt.shape[0] != 0:
start = time.time()
# sol_init = linprog(c=c, A_ub=A_lt, b_ub=b_lt, A_eq=A_eq, b_eq=b_eq, integrality=integrality_args, bounds=bounds)
sol_init, _ = BnB(c=c, A_ub=A_lt, b_ub=b_lt, A_eq=A_eq, b_eq=b_eq, bounds=bounds, int_indices=integer_variables)
end = time.time()
else:
start = time.time()
# sol_init = linprog(c=c, A_eq=A_eq, b_eq=b_eq, integrality=integrality_args, bounds=bounds)
# sol_init = linprog(c=c, A_eq=A_eq, b_eq=b_eq, bounds=bounds)
sol_init, _ = BnB(c=c, A_eq=A_eq, b_eq=b_eq, bounds=bounds, int_indices=integer_variables)
end = time.time()
print(f"Finished solving, took {round(end-start, 5)} sec")
print(f"solution: f(x*) = {sol_init.obj_val}")
# print(f"Pass: {sol_init.success}")
# print(f"Solution: {sol_init.x}")
# if not sol_init.success:
# print(f"Solver message: {sol_init.message}")