function [objective,solution,solutionStatus] = gurobiSolveMIP(localfilename,tolerance,parameterfilename)
%gurobiSolveMIP Executes the Gurobi MIP solver and returns the status of the optimization
%procedure and potentially the achieved optimal objective function value
%and the optimal solution vector.
%
% [objective,solution,solutionStatus] = gurobiSolveMIP(mpsfilename,tolerance,parameter-filename)
%
% Inputs:
% mpsfilename: the fully qualified path of the file where the input problem is stored (usually in .mps format)
% and that will be solved by Gurobi
%
% tolerance: [0,1] float value specifying the tolerance w.r.t the optimal
% solution that the Gurobi Solver should use to arrive to an efficient
% solution. If not specified, the default value 0 is used (optimal
% solution).
%
% parameterfilename: filename of the ".par" parameter file containing
% modifications to default values of Gurobi parameters. The file must
% be in the same directory as the caller script or else the fully
% qualified name of the file must be specified. NOTE THAT THIS ARGUMENT
% IS OPTIONAL. USE [] IF YOU DO NOT WISH TO MODIFY VALUES OF DEFAULT
% PARAMETERS OF GUROBI.
%
% Outputs:
% solutionStatus : integer value that corresponds to the status numbers returned by the Gurobi solver.
% Additionally, specific status numbers may be reported for failure codes corresponding to failures not related
% to Gurobi, like inability to read from specified file etc.
%
% NOTE: it is the responsibility of the caller of this function to check
% the status of the function call and then decided whether to read
% the objective value and the solution vector.
%
% Gurobi solution status codes:
%
% solutionStatus = 1: Model is loaded, but no solution information is
% available.
% solutionStatus = 2: Model was solved to optimality (subject to
% tolerances), and an optimal solution is available.
% solutionStatus = 3: Model was proven to be infeasible.
% solutionStatus = 4: Model was proven to be either infeasible or
% unbounded.
% solutionStatus = 5: Model was proven to be unbounded.
% solutionStatus = 6: Optimal objective for model was proven to be
% worse than the value specified in the Cutoff parameter. No solution
% information is available.
% solutionStatus = 7: Optimization terminated because the total
% number of simplex iterations performed exceeded the value specified
% in the IterationLimit parameter.
% solutionStatus = 8: Optimization terminated because the total
% number of branch-and-cut nodes explored exceeded the value specified
% in the NodeLimit parameter.
% solutionStatus = 9: Optimization terminated because the time
% expended exceeded the value specified in the TimeLimit parameter.
% solutionStatus = 10: Optimization terminated because the number of
% solutions found reached the value specified in the SolutionLimit
% parameter.
% solutionStatus = 11: Optimization was terminated by the user.
% solutionStatus = 12: Optimization was terminated due to
% unrecoverable numerical difficulties.
%
% Gurobi error codes (means optimization never completed):
%
% solutionStatus = 10001: out of memory
% solutionStatus = 10002: NULL input value provided for a required argument
% solutionStatus = 10003: An invalid value was provided for a routine argument
% solutionStatus = 10004: Tried to query or set an unknown attribute
% solutionStatus = 10005: Attempted to query or set an attribute that
% could not be accessed at that time
% solutionStatus = 10006: Tried to query or set an attribute, but one
% or more of the provided indices (e.g., constraint index, variable index)
% was outside the range of valid values
% solutionStatus = 10007: Tried to query or set an unknown parameter
% solutionStatus = 10008: Tried to set a parameter to a value that is
% outside the parameter's valid range
% solutionStatus = 10009: Failed to obtain a valid license
% solutionStatus = 10010: Attempted to solve a model that is larger
% than the limit for a demo license
% solutionStatus = 10011: Problem in callback
% solutionStatus = 10012: Failed to read the requested file
% solutionStatus = 10013: Failed to write the requested file
% solutionStatus = 10014: Numerical error during requested operation
% solutionStatus = 10015: Attempted to perform infeasibility analysis
% on a feasible model
% solutionStatus = 10016: Requested operation not valid for a MIP
% model
% solutionStatus = 10017: Tried to query or modify a model while
% optimization was in progress
% solutionStatus = 10018: Constraint, variable, or SOS contained
% duplicated indices
% solutionStatus = 10019: Error in reading or writing a node file
% during MIP optimization
%
% Matlab-Gurobi interface specific status codes:
% solutionStatus = 20000: error in executing the Gurobi-Matlab
% native executable
% solutionStatus = 20001: unable to read from specified input file
% solutionStatus = 20002: file I/O error when processing MIP status file locally
% solutionStatus = 20003: file I/O error when processing MIP objective file locally
% solutionStatus = 20004: file I/O error when processing MIP solution vector file locally
%
% OBJECTIVE: real-valued number corresponding to the optimal solution
% achieved by Gurobi for the input problem. If no optimal solution is
% found, the value is null.
%
% SOLUTION: vector of the optimal solution. If no optimal solution is
% found, the vector is empty.
%
%(c) 2010
% Kostas Katrinis (kostas.katrinis@gmail.com)
% Version 2.0
%
%%%%%%%%%%%%%%%%%%%%
%% INITIALIZATION
%%%%%%%%%%%%%%%%%%%%
solutionStatus=0;
objective=[];
solution=[];
%load mat file containing parameter values
load('guroboMATic_vars.mat');
x=clock;
%the file that will store the solution vector will be given a random,
%with high probability unique, filename
tmpfilename=sprintf('%d_%d_%d_%d_%d_%d',x(1),x(2),x(3),x(4),x(5),floor(x(6)))
localobjfilename = sprintf('%s.objective',tmpfilename);
localstatusfilename = sprintf('%s.status',tmpfilename);
exitCodefilename = sprintf('%s.error',tmpfilename);
%% NOTE: the suffix of the solution file must be ".sol" for Gurobi to
%% operate as expected
localsolfilename = sprintf('%s.sol',tmpfilename);
gurobiSolver_execfilename = sprintf('%s\\%s',GurobiSolverIFpath, GurobiSolverIFexec);
%%%%%%%%%%%%%%%%%%%%%%%
%% CORE FUNCTIONALITY
%%%%%%%%%%%%%%%%%%%%%%%
interfaceCommand = sprintf('%s %s %s %s %s %s %f %s',gurobiSolver_execfilename,localfilename,...
localstatusfilename,localobjfilename,localsolfilename, ...
exitCodefilename, tolerance,parameterfilename);
%%%%%%
%%%%%% Fire the Gurobi Solver
%%%%%%
try
system(interfaceCommand);
catch
error('Error: gurobiSolveMIP could not execute the Gurobi-Matlab interface command');
solutionStatus = 20000;
return;
end
%%% read the status code returned by the execution of Matlab-Gurobi
%%% interface
ifstatus=0;
try
ifstatus=textread(exitCodefilename,'%d');
catch
error('Error: gurobiSolveMIP could not read the exit code file of the Gurobi-Matlab interface program');
solutionStatus = 20000;
return;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%
%%%%%% Process the status code of the MIP optimization
%%%%%%
if ifstatus==0
delete(exitCodefilename);
MIPstatus=-1;
try
MIPstatus=textread(localstatusfilename,'%d');
catch
error(['Error: gurobiSolveMIP could not read from the MIP status file'...
' %s ...'],localstatusfilename);
delete(localstatusfilename);
solutionStatus=20002;
return;
end
delete(localstatusfilename);
solutionStatus = MIPstatus;
%%%%% in case feasible solution found, retrieve objective and solution
%%%%% files from remote host
if MIPstatus==2 || MIPstatus==7 || MIPstatus==8 || MIPstatus==9 ...
|| MIPstatus==10 || MIPstatus==11
try
objective=textread(localobjfilename,'%f');
catch
error(['Error: gurobiSolveMIP could not read from the MIP objective file'...
' %s ...'],localobjfilename);
delete(localobjfilename);
solutionStatus=20003;
return;
end
delete(localobjfilename);
%%% NOTE: Reading the solution file with limited arithmetic precision
%%% may truncate the value of a real-valued variable (i.e. non-integer)
%%% to an integer value. If large precision is a requirement, reading
%%% the solution file with higher precision should be implemented.
try
fid = fopen(localsolfilename);
%read and ignore the first comment line
textscan(fid, '%s %s %s %s %s', 1);
tmpcell = textscan(fid,'%s %f',1);
while (~isempty(tmpcell{1}))
solution = [solution tmpcell{2}];
tmpcell = textscan(fid,'%s %f',1);
end
fclose(fid);
%textread(localsolfilename,'%s',1);
%solution = textread(localsolfilename, '%f', 'delimiter', '\n');
catch
error(['Error: gurobiSolveMIP could not read from the MIP solution vector file'...
' %s ...'],localsolfilename);
delete(localsolfilename);
solutionStatus=20004;
return;
end
delete(localsolfilename);
return;
else
return;
end
else
error('Error: execution of the C interface program to Gurobi');
display('Reason:');
% TODO: return here the text reason depending on the error code
solutionStatus = 20000;
return;
end