Commit f93a6986 authored by Bowen Wu's avatar Bowen Wu
Browse files

Support more bound types, enable generate integer variables, run MIP

parent 9d9fc1fa
......@@ -5,4 +5,5 @@ diff/
mutated/
*.log
*.sol
.DS_Store
\ No newline at end of file
.DS_Store
benchmark/
\ No newline at end of file
......@@ -54,33 +54,47 @@ class MPSProgram:
for i,row in enumerate(self.row_names):
out+=" {} {} \n".format(self.types[i], row)
out+="COLUMNS\n"
# Aprime is of dimension (#constraints+1) * #var
Aprime = np.concatenate(([self.c],self.A),axis=0)
E = np.sum(Aprime, axis=0)
row_names_prime = [self.objective_name]+self.row_names
x_dim, y_dim = Aprime.shape[0],Aprime.shape[1]
int_marker = 0
new_int = True
for j in range(y_dim):
if self.col_types[j] == "integral" and new_int:
out += f" MARK{str(int_marker).zfill(4)} 'MARKER' 'INTORG'\n"
new_int = False
for i in range(x_dim):
if Aprime[i][j] == 0.0: continue
if Aprime[i][j] == 0.0: continue # ignore variables that have all 0 coeff
out +=" {}\t\t{}\t\t{}\n".format(self.col_names[j],row_names_prime[i],Aprime[i][j])
if self.col_types[j] == "integral" and (j == y_dim - 1 or self.col_types[j+1] != "integral"):
out += f" MARK{str(int_marker).zfill(4)} 'MARKER' 'INTEND'\n"
int_marker += 1
new_int = True
out+="RHS\n"
for rhs_name, rhs_bounds in self.rhs.items():
for i in range(len(rhs_bounds)):
out += " {}\t\t{}\t\t{}\n".format(rhs_name, self.row_names[i], rhs_bounds[i])
out+="BOUNDS\n"
# TODO : output bounds
# we only care about the first bound name
bnd_lo = self.bnd[self.bnd_names[0]]['LO']
bnd_up = self.bnd[self.bnd_names[0]]['UP']
for col, lo, up in zip(self.col_names, bnd_lo, bnd_up):
for i, col, lo, up in zip(range(len(self.col_names)), self.col_names, bnd_lo, bnd_up):
if E[i] == 0.0: continue # ignore variables that have all 0 coeff
if lo != 0:
if lo != -np.inf:
out += f" LO {self.bnd_names[0]}\t\t{col}\t\t{lo}\n"
lo = int(lo) if self.col_types[i] == "integral" else lo
sense = "LI" if self.col_types[i] == "integral" else "LO"
out += f" {sense} {self.bnd_names[0]}\t\t{col}\t\t{lo}\n"
else:
# we only allow FR to set lower bound to -inf
assert up == np.inf
out += f" FR {self.bnd_names[0]}\t\t{col}\n"
out += f" MI {self.bnd_names[0]}\t\t{col}\n"
continue
if up != np.inf:
out += f" UP {self.bnd_names[0]}\t\t{col}\t\t{up}\n"
up = int(up) if self.col_types[i] == "integral" else up
sense = "UI" if self.col_types[i] == "integral" else "UP"
out += f" {sense} {self.bnd_names[0]}\t\t{col}\t\t{up}\n"
out+="ENDATA"
return out
......
import os
import sys
import pysmps.pysmps.smps_loader
from pysmps.pysmps.smps_loader import load_mps, MPSParseError
from generator import MPSProgram
import glob
import pandas as pd
# A simple wrapper to suppress talkative APIs from printing
# Inspired from https://stackoverflow.com/a/45669280
......@@ -31,7 +33,7 @@ class bcolors:
UNDERLINE = '\033[4m'
def load_mps_dict(path):
name, objsense, objective_name, row_names, col_names, col_types, types, c, A, rhs_names, rhs, bnd_names, bnd = pysmps.pysmps.smps_loader.load_mps(path)
name, objsense, objective_name, row_names, col_names, col_types, types, c, A, rhs_names, rhs, bnd_names, bnd = load_mps(path)
ret = dict()
ret["name"] = name
ret["objsense"] = objsense
......@@ -52,8 +54,44 @@ def print_mps_dict(mps: dict):
for k in mps:
print(f"{bcolors.OKBLUE}{k}\n{bcolors.ENDC}", mps[k])
def read_benchmark_mps(max_size):
"""
Check if the current parser can handle all possible cases in the seed pool
Parameter:
maxsize: maximum size of the file interested in bytes
"""
tests = glob.glob("benchmark/*.mps")
for test in tests:
if os.stat(test).st_size > max_size: continue
print("Reading ", test)
try:
load_mps_dict(test)
print(test, "succeeds.\n")
except MPSParseError as e:
print(test, " fails.\n", e)
def prepare_seed_pool():
"""
Prepare the seeds obtained from https://miplib.zib.de/tag_benchmark.html
Requirement:
1. Questions labeled as easy (hard problems take a long time to solve)
2. Questions that contain binary or integer variables (MIP is more prone to bugs)
3. Reasonable problem size
"""
bm_file = "benchmark/benchmark.csv"
max_var_num = 150
df = pd.read_csv(bm_file)
print(df.head)
df = df[df['Status Sta.'] == "easy"]
df = df[df['Binaries Bin.'] + df['Integers Int.'] > 0]
df = df[df['Variables Var.'] <= max_var_num]
print(df.head)
def print_load_mps_ret(path):
name, objsense, objective_name, row_names, col_names, col_types, types, c, A, rhs_names, rhs, bnd_names, bnd = pysmps.pysmps.smps_loader.load_mps(path)
name, objsense, objective_name, row_names, col_names, col_types, types, c, A, rhs_names, rhs, bnd_names, bnd = load_mps(path)
print(f"{bcolors.OKBLUE}Program Name: {bcolors.ENDC}", name)
print(f"{bcolors.OKBLUE}Objective Sense: {bcolors.ENDC}", objsense)
print(f"{bcolors.OKBLUE}Objective Name: {bcolors.ENDC}", objective_name)
......
......@@ -10,7 +10,7 @@ from queue import Queue
from numpy import diff
from generator import MPSProgram
from mps_mut import DenseMatMut
from mps_mut import DenseMatMut, SparseMatMut, FlipSignMut
from mps_util import load_mps_dict
from optimizer import OPTIMAL, CplexSolver, GurobiSolver
......@@ -158,11 +158,15 @@ class OptFuzzer(object):
self.checkpoint()
nround += 1
self.print_stats()
self.cplex.print_solver_stats()
self.gurobi.print_solver_stats()
self.save_states()
def main():
dmm = DenseMatMut(0.5)
seed = ["mps/testprob.mps"]
smm = SparseMatMut(0.5)
fsm = FlipSignMut(0.5)
seed = ["benchmark/markshare_4_0.mps"]
mut_method = [dmm]
cpx = CplexSolver()
grb = GurobiSolver()
......@@ -174,9 +178,6 @@ def main():
mut_choice = "fixed"
fuzzer = OptFuzzer(seed, mut_method, cpx, grb, save_path, checkpoint_freq, checkpoint_path, diff_path)
fuzzer.fuzz(max_time, mut_choice)
fuzzer.print_stats()
cpx.print_solver_stats()
grb.print_solver_stats()
if __name__ == "__main__":
main()
Subproject commit 5cd2c221a191085ca5379024cc8594629f9c2972
Subproject commit 457e7a3488ecd752e2359ebba796944d24248180
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment