## Friday, 24 April 2015

### AMPL reporting solver statistics

This a simple script that I have been working on, which provides some Solver statistics to AMPL. At this moment, the script can handle the MINOS solver output and generate cool charts to summarize the process till the solver reaches a solution.
As usual, I have written a python script that is called by the shell command in AMPL.

option solver minos;
option minos_options "Superbasics_limit=100 summary_file=1 1=summary.txt summary_level = 1 summary_frequency=1";

printf "MINOS_report: generating AMPL results...\n";
shell 'C:\Python27\python.exe "MINOS_report.py" summary.txt';

As said, this script was written to work with MINOS, so after choosing MINOS as solver, we must provide to MINOS the output file which will contain the solver's statistics. The python script just parse the output file, clean it and generate the chart shown below. This code is just an example and does not aim to be very fast or optimum in terms of computational efficiency since is just a first test.
import pandas as pd
import matplotlib.pyplot as plt
import sys
import os

class Generate(object):
def __init__(self, i_file):
self.f_input = i_file
self.f_output = "results_clean.csv"
self.data = []
self.output = []

def clean_file(self):
with open(self.f_input, "r") as f:
it = 0
for line in f:
if "EXIT" in line:
break
elif line[:7].strip().isdigit() and int(line[:7].strip()) > it \
and not "T" in line:
if len(line) > 10:
#print line
it += 1
self.output.append(line)
f.close()
w = open(self.f_output, "w")
w.writelines(self.output)
w.close()
print "MINOS_report: new file > {0}".format(self.f_output)

def get_data(self):
cols = [(1, 7), (8, 16), (17, 22), (23, 32), (33, 48), (49, 54), (55, 60), (61, 65)]

def plots(self):

itn = len(self.data)
ninf = self.data[2]
sinf = self.data[3]
objective = self.data[4]
nobj = self.data[5]
ncon = self.data[6]
nsb = self.data[7]

it = list(range(1, itn + 1))

_min_obj = objective[itn - 1]
_max_nsb = nsb[itn - 1]
_max_nobj = nobj[itn - 1]
_sinf = sinf[itn - 1]
_ninf = ninf[itn - 1]
_ncon = ncon[itn - 1]

plt.figure("AMPL results")

# plot 1
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ax1 = plt.subplot(211)
ax1.set_title('Iterations={0}. Objective (optimal solution)={1}'
.format(itn, _min_obj), size=10)

ax1.set_xlabel('iterations')
ax1.set_ylabel('objective function')
l_obj = ax1.plot(it, objective, '.-', color="#0E3EEB", label="obj")
ax2 = ax1.twinx()
l_rg = ax2.plot(it, rgradient, '.-', color="#EB710E", label="rg")

lns = l_obj + l_rg
labs = [l.get_label() for l in lns]

ax1.grid()
ax1.legend(lns, labs, loc=0)

# plot 2
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ax3 = plt.subplot(223)
ax3.set_title('number of superbasics={0}\n # objective and gradient calculations={1}'
.format(_max_nsb, _max_nobj), size=10)

l_sb = ax3.plot(it, nsb, '.-', color="#0E3EEB", label="nsb")
ax3.set_xlabel('iterations')
ax3.set_ylabel('no.superbasics')
ax4 = ax3.twinx()
l_nobj = ax4.plot(it, nobj, '.-', color="#EB710E", label="nobj")

lns = l_sb + l_nobj
labs = [l.get_label() for l in lns]

ax3.grid()
ax3.legend(lns, labs, loc=4)

# plot 3
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
plt.subplot(224)
plt.title('no. of infeasibilities={0}\n sum of infeasibilities={1}\n '
'# nonlinear constraints evaluations={2}'.format(_ninf, _sinf, _ncon), size=10)
plt.plot(it, ncon, 'g-', label="ncon")
plt.plot(it, ninf, 'y-', label="ninf")
plt.plot(it, sinf, 'm-', label="sinf")
plt.xlabel('iterations')
plt.grid()
plt.legend()

plt.tight_layout()
plt.show()

if __name__ == "__main__":
summary_file = sys.argv[1]
#summary_file = "C:/Users/Guillermo Navas/Desktop/MSc Statistics and Operations research/Continuous optimization/" \
#                   "Modelling and solving optimization problems/Lab assignment 2 _ Network flow problems/solver_summary.txt"
report = Generate(summary_file)
report.clean_file()
report.get_data()
report.plots()