diff --git a/include/IO/Statistics/SolverRuntimeCollection.hpp b/include/IO/Statistics/SolverRuntimeCollection.hpp new file mode 100644 index 00000000..f3bbc5d4 --- /dev/null +++ b/include/IO/Statistics/SolverRuntimeCollection.hpp @@ -0,0 +1,242 @@ +/* + * SolverRuntimeCollection.hpp + * + * Created on: Jan 29, 2019 + * Author: Franziska Wegner + */ + +#ifndef EGOA__IO__STATISTICS__GUROBI_INFO_COLLECTION_HPP +#define EGOA__IO__STATISTICS__GUROBI_INFO_COLLECTION_HPP + +#include "IO/Statistics/SolverRuntimeRow.hpp" +#include "IO/Statistics/SolverRuntimeCollection.hpp" + +#include +#include +#include +#include +#include + +using namespace std; + +namespace egoa::IO { + +class SolverRuntimeCollection { + public: + using TRow = SolverRuntimeRow; + + + ///@name Constructor and destructor + ///@{ +#pragma mark CONSTRUCTORS_AND_DESTRUCTOR + SolverRuntimeCollection() + : information() + , min(), max(), avg() + , filename_("SolverRuntimeCollectionFilename") + , verbose_(false) + , name_("SolverRuntimeCollectionName") + , numberOfVertices_(0) + , numberOfEdges_(0) + {} + + SolverRuntimeCollection ( Types::string filename + , bool verbose + , Types::string name + ) + : information() + , min(), max(), avg() + , filename_(filename) + , verbose_(verbose) + , name_(name) + , numberOfVertices_(0) + , numberOfEdges_(0) + { } + ///@} + + ///@name Operators + ///@{ +#pragma mark OPERATORS + inline SolverRuntimeCollection & operator+= ( TRow & rhs ) + { + if (verbose_) + { + rhs.Name = name_; + rhs.NumberOfEdges = numberOfEdges_; + DumpLine ( filename_, rhs, false ); + } + else information.push_back(rhs); + return *this; + } + + inline void AddMeta ( Types::name name + , Types::count nrVertices + , Types::count nrEdges + ) + { + for ( auto & info : information ) + { + info.Name = name; + info.NumberOfVertices = nrVertices; + info.NumberOfEdges = nrEdges; + } + } + + // Compute statistics. + inline void ComputeStatistics() + { + if ( information.empty() ) return; + + // Compute average, minimum, and maximum. + avg = information[0]; + min = information[0]; + max = information[0]; + + for ( size_t i = 1; i < information.size(); ++i ) + { + avg += information[i]; + min.Min(information[i]); + max.Max(information[i]); + } + avg /= information.size(); + } + ///@} + + + ///@name Output + ///@{ +#pragma mark OUTPUT + + inline void Dump ( ostream & os ) + { + if ( information.empty() ) return; + // ComputeStatistics(); + os << "\n" + << "Statistics:" << std::endl + << "-----------" << std::endl + + << std::setprecision(2) + << std::fixed + + << setw(30) << "Problem: " << setw(8) << information[0].NameOfProblem << ", " << std::endl + << setw(30) << "Name: " << setw(8) << information[0].Name << ", " << std::endl + + << setw(30) << "Number of vertices: " << setw(8) << information[0].NumberOfVertices << ", " << std::endl + << setw(30) << "Number of edges: " << setw(8) << information[0].NumberOfEdges << ", " << std::endl + + << setw(30) << "Total time: " << setw(8) << avg.OptimizationRuntimeSeconds << setw(11) << " sec (avg), " + << setw(8) << min.OptimizationRuntimeSeconds << setw(11) << " sec (min), " + << setw(8) << max.OptimizationRuntimeSeconds << setw(11) << " sec (max)" << std::endl + + << setw(30) << "Solutions: " << setw(8) << avg.Solution << setw(11) << " (avg), " + << setw(8) << min.Solution << setw(11) << " (min), " + << setw(8) << max.Solution << setw(11) << " (max)" << std::endl + + << setw(30) << "MipGap: " << setw(8) << avg.MipGap << setw(11) << " (avg), " + << setw(8) << min.MipGap << setw(11) << " (min), " + << setw(8) << max.MipGap << setw(11) << " (max)" << std::endl + + << setw(30) << "Upper bound: " << setw(8) << avg.UpperBound << setw(11) << " (avg), " + << setw(8) << min.UpperBound << setw(11) << " (min), " + << setw(8) << max.UpperBound << setw(11) << " (max)" << std::endl + + << setw(30) << "Lower bound: " << setw(8) << avg.LowerBound << setw(11) << " (avg), " + << setw(8) << min.LowerBound << setw(11) << " (min), " + << setw(8) << max.LowerBound << setw(11) << " (max)" << std::endl + + << setw(30) << "NumberOfVariables: " << setw(8) << avg.NumberOfVariables << setw(11) << " (avg), " + << setw(8) << min.NumberOfVariables << setw(11) << " (min), " + << setw(8) << max.NumberOfVariables << setw(11) << " (max)" << std::endl + << setw(30) << "NumberOfConstraints: " << setw(8) << avg.NumberOfConstraints << setw(11) << " (avg), " + << setw(8) << min.NumberOfConstraints << setw(11) << " (min), " + << setw(8) << max.NumberOfConstraints << setw(11) << " (max)" << std::endl + << setw(30) << "NumberOfConstraints: " << setw(8) << avg.NumberOfSoS << setw(11) << " (avg), " + << setw(8) << min.NumberOfSoS << setw(11) << " (min), " + << setw(8) << max.NumberOfSoS << setw(11) << " (max)" << std::endl + << setw(30) << "NumberOfQConstrains: " << setw(8) << avg.NumberOfQConstrains << setw(11) << " (avg), " + << setw(8) << min.NumberOfQConstrains << setw(11) << " (min), " + << setw(8) << max.NumberOfQConstrains << setw(11) << " (max)" << std::endl + << setw(30) << "NumberOfQConstrains: " << setw(8) << avg.NumberOfGenConstrains << setw(11) << " (avg), " + << setw(8) << min.NumberOfGenConstrains << setw(11) << " (min), " + << setw(8) << max.NumberOfGenConstrains << setw(11) << " (max)" << std::endl + << setw(30) << "NumberOfNZs: " << setw(8) << avg.NumberOfNZs << setw(11) << " (avg), " + << setw(8) << min.NumberOfNZs << setw(11) << " (min), " + << setw(8) << max.NumberOfNZs << setw(11) << " (max)" << std::endl + << setw(30) << "NumberOfIntVars: " << setw(8) << avg.NumberOfIntVars << setw(11) << " (avg), " + << setw(8) << min.NumberOfIntVars << setw(11) << " (min), " + << setw(8) << max.NumberOfIntVars << setw(11) << " (max)" << std::endl + << setw(30) << "NumberOfBinaryVars: " << setw(8) << avg.NumberOfBinaryVars << setw(11) << " (avg), " + << setw(8) << min.NumberOfBinaryVars << setw(11) << " (min), " + << setw(8) << max.NumberOfBinaryVars << setw(11) << " (max)" << std::endl + << std::endl; + } + + inline void DumpLine ( Types::string const filename + , TRow const & info + , bool const overwrite = false ) const + { +#ifndef NDEBUG + qDebug() << "Dumping debug data to: " << QString::fromStdString(filename); +#endif + // Open output stream. + // ofstream f(filename); + std::ofstream f; + overwrite?f.open(filename, std::ofstream::trunc):f.open(filename, std::ofstream::app); + if (!f.is_open()) return; + + // GurobiInfo::Header(f); + // file is empty + f.seekp(0, ios::end); + if ( f.tellp() == 0 ) { TRow::Header(f); } + + info.Content(f); + } + + inline void Dump ( std::string const filename + , bool const overwrite = true ) const + { +#ifdef NDEBUG + qDebug() << "Dumping debug data to: " << QString::fromStdString(filename); +#endif + // Open output stream. + // ofstream f(filename); + std::ofstream f; + overwrite?f.open(filename, std::ofstream::trunc):f.open(filename, std::ofstream::app); + if (!f.is_open()) return; + + // GurobiInfo::Header(f); + // file is empty + f.seekp(0, ios::end); + if ( f.tellp() == 0 ) { TRow::Header(f); } + + for ( const auto & info : information ) { info.Content(f); } + } + ///@} + + + inline Types::count NumberOfVertices () const { return numberOfVertices_; } + inline Types::count & NumberOfVertices () { return numberOfVertices_; } + + inline Types::count NumberOfEdges () const { return numberOfEdges_; } + inline Types::count & NumberOfEdges () { return numberOfEdges_; } + + private: + ///@name Member + ///@{ +#pragma mark MEMBER + vector information; + TRow min, max, avg; + + Types::name filename_; + bool verbose_; + + Types::name problemName_; + Types::name name_; + + Types::count numberOfVertices_; + Types::count numberOfEdges_; + ///@} +}; + +} // namespace egoa::IO + +#endif // EGOA__IO__STATISTICS__GUROBI_INFO_COLLECTION_HPP diff --git a/include/IO/Statistics/SolverRuntimeRow.hpp b/include/IO/Statistics/SolverRuntimeRow.hpp new file mode 100644 index 00000000..89b50e5d --- /dev/null +++ b/include/IO/Statistics/SolverRuntimeRow.hpp @@ -0,0 +1,207 @@ +/* + * SolverRuntimeRow.hpp + * + * Created on: Jan 29, 2019 + * Author: Franziska Wegner + */ + +#ifndef EGOA__IO__STATISTICS__GUROBI_INFO_HPP +#define EGOA__IO__STATISTICS__GUROBI_INFO_HPP + +#include "Auxiliary/Types.hpp" + +#include +#include + +namespace egoa::IO { + + /** + * @brief A struct representing one row of the statistics for mathematical models. + * + * @see GurobiRuntimeCollection A collection of @c SolverRuntimeRow objects + */ + struct SolverRuntimeRow { + + Types::name NameOfProblem; /**< Problem solved */ + Types::name Name; /**< Name of the instance */ + + Types::count NumberOfVertices; /**< Number of vertices */ + Types::count NumberOfEdges; /**< Number of edges */ + + Types::real Solution; /**< Current solution's cost */ + Types::real OptimizationRuntimeSeconds; /**< Current time in the whole gurobi program */ + Types::real BuildingRuntimeSeconds; /**< Current time in the whole gurobi program */ + + Types::string Status; /**< Gurobi solution status; see https://www.gurobi.com/documentation/8.0/refman/optimization_status_codes.html#sec:StatusCodes */ + Types::real MipGap; /**< MIP gap in % */ + Types::real UpperBound; /**< Upper bound */ + Types::real LowerBound; /**< Lower bound */ + Types::count NumberOfVariables; /**< Number of variables */ + Types::count NumberOfConstraints; /**< Number of variables */ + Types::count NumberOfSoS; /**< Number of variables */ + Types::count NumberOfQConstrains; /**< Number of variables */ + Types::count NumberOfGenConstrains; /**< Number of variables */ + Types::count NumberOfNZs; /**< Number of variables */ + Types::count NumberOfIntVars; /**< Number of variables */ + Types::count NumberOfBinaryVars; /**< Number of variables */ + + SolverRuntimeRow() : + NameOfProblem(""), + Name(""), + + NumberOfVertices(0), + NumberOfEdges(0), + + Solution(0.0), + OptimizationRuntimeSeconds(0.0), + BuildingRuntimeSeconds(0.0), + + Status("unknown"), + + MipGap(0.0), + UpperBound(0.0), + LowerBound(0.0), + NumberOfVariables(0), + NumberOfConstraints(0), + NumberOfSoS(0), + NumberOfQConstrains(0), + NumberOfGenConstrains(0), + NumberOfNZs(0), + NumberOfIntVars(0), + NumberOfBinaryVars(0) + {} + + inline static void Header ( std::ostream & os ) { + os + << "NameOfProblem" << ",\t" + << "Name" << ",\t" + + << "NumberOfVertices" << ",\t" + << "NumberOfEdges" << ",\t" + + << "Solution" << ",\t" + << "OptimizationRuntimeSeconds" << ",\t" + << "BuildingRuntimeSeconds" << ",\t" + + << "Status" << ",\t" + << "MipGap" << ",\t" + << "UpperBound" << ",\t" + << "LowerBound" << ",\t" + << "NumberOfVariables" << ",\t" + << "NumberOfConstraints" << ",\t" + << "NumberOfSoS" << ",\t" + << "NumberOfQConstrains" << ",\t" + << "NumberOfGenConstrains" << ",\t" + << "NumberOfNZs" << ",\t" + << "NumberOfIntVars" << ",\t" + << "NumberOfBinaryVars" << "" + + << std::endl; + } + + inline void Content ( std::ostream & os ) const { + os + << NameOfProblem << ",\t" + << Name << ",\t" + + << NumberOfVertices << ",\t" + << NumberOfEdges << ",\t" + + << Solution << ",\t" + << OptimizationRuntimeSeconds << ",\t" + << BuildingRuntimeSeconds << ",\t" + + << Status << ",\t" + << MipGap << ",\t" + << UpperBound << ",\t" + << LowerBound << ",\t" + << NumberOfVariables << ",\t" + << NumberOfConstraints << ",\t" + << NumberOfSoS << ",\t" + << NumberOfQConstrains << ",\t" + << NumberOfGenConstrains << ",\t" + << NumberOfNZs << ",\t" + << NumberOfIntVars << ",\t" + << NumberOfBinaryVars << "" + + << std::endl; + } + + inline SolverRuntimeRow& operator+= ( const SolverRuntimeRow &rhs ) { + Solution += rhs.Solution; + OptimizationRuntimeSeconds += rhs.OptimizationRuntimeSeconds; + BuildingRuntimeSeconds += rhs.BuildingRuntimeSeconds; + + MipGap += rhs.MipGap; + UpperBound += rhs.UpperBound; + LowerBound += rhs.LowerBound; + NumberOfVariables += rhs.NumberOfVariables; + NumberOfConstraints += rhs.NumberOfConstraints; + NumberOfSoS += rhs.NumberOfSoS; + NumberOfQConstrains += rhs.NumberOfQConstrains; + NumberOfGenConstrains += rhs.NumberOfGenConstrains; + NumberOfNZs += rhs.NumberOfNZs; + NumberOfIntVars += rhs.NumberOfIntVars; + NumberOfBinaryVars += rhs.NumberOfBinaryVars; + + return *this; + } + + inline SolverRuntimeRow& operator/= ( int rhs ) { + Solution /= rhs; + OptimizationRuntimeSeconds /= rhs; + BuildingRuntimeSeconds /= rhs; + + MipGap /= rhs; + UpperBound /= rhs; + LowerBound /= rhs; + NumberOfVariables /= rhs; + NumberOfConstraints /= rhs; + NumberOfSoS /= rhs; + NumberOfQConstrains /= rhs; + NumberOfGenConstrains /= rhs; + NumberOfNZs /= rhs; + NumberOfIntVars /= rhs; + NumberOfBinaryVars /= rhs; + + return *this; + } + + inline void Min(const SolverRuntimeRow &rhs) { + Solution = std::min( Solution, rhs.Solution ); + OptimizationRuntimeSeconds= std::min( OptimizationRuntimeSeconds, rhs.OptimizationRuntimeSeconds); + + MipGap = std::min( MipGap, rhs.MipGap ); + UpperBound = std::min( UpperBound, rhs.UpperBound ); + LowerBound = std::min( LowerBound, rhs.LowerBound ); + NumberOfVariables = std::min( NumberOfVariables, rhs.NumberOfVariables ); + NumberOfConstraints = std::min( NumberOfConstraints, rhs.NumberOfConstraints ); + NumberOfSoS = std::min( NumberOfSoS, rhs.NumberOfSoS ); + NumberOfQConstrains = std::min( NumberOfQConstrains, rhs.NumberOfQConstrains ); + NumberOfGenConstrains = std::min( NumberOfGenConstrains, rhs.NumberOfGenConstrains); + NumberOfNZs = std::min( NumberOfNZs, rhs.NumberOfNZs ); + NumberOfIntVars = std::min( NumberOfIntVars, rhs.NumberOfIntVars ); + NumberOfBinaryVars = std::min( NumberOfBinaryVars, rhs.NumberOfBinaryVars ); + } + + inline void Max(const SolverRuntimeRow &rhs) { + Solution = std::max( Solution, rhs.Solution ); + OptimizationRuntimeSeconds= std::max( OptimizationRuntimeSeconds, rhs.OptimizationRuntimeSeconds); + + MipGap = std::max( MipGap, rhs.MipGap ); + UpperBound = std::max( UpperBound, rhs.UpperBound ); + LowerBound = std::max( LowerBound, rhs.LowerBound ); + NumberOfVariables = std::max( NumberOfVariables, rhs.NumberOfVariables ); + NumberOfConstraints = std::max( NumberOfConstraints, rhs.NumberOfConstraints ); + NumberOfSoS = std::max( NumberOfSoS, rhs.NumberOfSoS ); + NumberOfQConstrains = std::max( NumberOfQConstrains, rhs.NumberOfQConstrains ); + NumberOfGenConstrains = std::max( NumberOfGenConstrains, rhs.NumberOfGenConstrains); + NumberOfNZs = std::max( NumberOfNZs, rhs.NumberOfNZs ); + NumberOfIntVars = std::max( NumberOfIntVars, rhs.NumberOfIntVars ); + NumberOfBinaryVars = std::max( NumberOfBinaryVars, rhs.NumberOfBinaryVars ); + } +}; + +} // namespace egoa::IO + +#endif // EGOA__IO__STATISTICS__GUROBI_INFO_HPP