/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* */ /* This file is part of the HiGHS linear optimization suite */ /* */ /* Written and engineered 2008-2024 by Julian Hall, Ivet Galabova, */ /* Leona Gottwald and Michael Feldmeier */ /* */ /* Available as open-source under the MIT License */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /**@file ../app/RunHighs.cpp * @brief HiGHS main */ #include "Highs.h" // #include "io/HighsIO.h" #include "lp_data/HighsRuntimeOptions.h" // uncomment if we will be shutting down task executor from exe // #include "parallel/HighsParallel.h" void reportModelStatsOrError(const HighsLogOptions& log_options, const HighsStatus read_status, const HighsModel& model); int main(int argc, char** argv) { // Create the Highs instance Highs highs; const HighsOptions& options = highs.getOptions(); const HighsLogOptions& log_options = options.log_options; // Load user options std::string model_file; std::string read_solution_file; HighsOptions loaded_options; // Set "HiGHS.log" as the default log_file for the app so that // log_file has this value if it isn't set in the file loaded_options.log_file = "HiGHS.log"; // When loading the options file, any messages are reported using // the default HighsLogOptions if (!loadOptions(log_options, argc, argv, loaded_options, model_file, read_solution_file)) return (int)HighsStatus::kError; // Open the app log file - unless output_flag is false, to avoid // creating an empty file. It does nothing if its name is "". if (loaded_options.output_flag) highs.openLogFile(loaded_options.log_file); // Pass the option settings to HiGHS. Only error-checking produces // output, but values are checked in loadOptions, so it's safe to // call this first so that printHighsVersionCopyright uses reporting // settings defined in any options file. highs.passOptions(loaded_options); // highs.writeOptions("Options.md"); // Load the model from model_file HighsStatus read_status = highs.readModel(model_file); reportModelStatsOrError(log_options, read_status, highs.getModel()); if (read_status == HighsStatus::kError) return (int)read_status; // Possible read a solution file if (read_solution_file != "") { HighsStatus read_solution_status = highs.readSolution(read_solution_file); if (read_solution_status == HighsStatus::kError) { highsLogUser(log_options, HighsLogType::kInfo, "Error loading solution file\n"); return (int)read_solution_status; } } if (options.write_presolved_model_to_file) { // Run presolve and write the presolved model to a file HighsStatus status = highs.presolve(); if (status == HighsStatus::kError) return int(status); HighsPresolveStatus model_presolve_status = highs.getModelPresolveStatus(); const bool ok_to_write = model_presolve_status == HighsPresolveStatus::kNotReduced || model_presolve_status == HighsPresolveStatus::kReduced || model_presolve_status == HighsPresolveStatus::kReducedToEmpty || model_presolve_status == HighsPresolveStatus::kTimeout; if (!ok_to_write) { highsLogUser(log_options, HighsLogType::kInfo, "No presolved model to write to file\n"); return int(status); } status = highs.writePresolvedModel(options.write_presolved_model_file); return int(status); } // Solve the model HighsStatus run_status = highs.run(); if (run_status == HighsStatus::kError) return int(run_status); // highs.writeInfo("Info.md"); // Possibly write the solution to a file if (options.write_solution_to_file || options.solution_file != "") highs.writeSolution(options.solution_file, options.write_solution_style); // Possibly write the model to a file if (options.write_model_to_file) { HighsStatus write_model_status = highs.writeModel(options.write_model_file); if (write_model_status == HighsStatus::kError) return (int)write_model_status; // todo: change to write model error } // Shut down task executor: optional and wip // HighsTaskExecutor::shutdown(true); return (int)run_status; } void reportModelStatsOrError(const HighsLogOptions& log_options, const HighsStatus read_status, const HighsModel& model) { const HighsLp& lp = model.lp_; const HighsHessian& hessian = model.hessian_; if (read_status == HighsStatus::kError) { highsLogUser(log_options, HighsLogType::kInfo, "Error loading file\n"); } else { HighsInt num_integer = 0; HighsInt num_semi_continuous = 0; HighsInt num_semi_integer = 0; for (HighsUInt i = 0; i < lp.integrality_.size(); i++) { switch (lp.integrality_[i]) { case HighsVarType::kInteger: num_integer++; break; case HighsVarType::kSemiContinuous: num_semi_continuous++; break; case HighsVarType::kSemiInteger: num_semi_integer++; break; default: break; } } std::string problem_type; const bool non_continuous = num_integer + num_semi_continuous + num_semi_integer; if (hessian.dim_) { if (non_continuous) { problem_type = "MIQP"; } else { problem_type = "QP "; } } else { if (non_continuous) { problem_type = "MIP "; } else { problem_type = "LP "; } } const HighsInt a_num_nz = lp.a_matrix_.numNz(); HighsInt q_num_nz = hessian.numNz(); if (*log_options.log_dev_level) { highsLogDev(log_options, HighsLogType::kInfo, "%4s : %s\n", problem_type.c_str(), lp.model_name_.c_str()); highsLogDev(log_options, HighsLogType::kInfo, "Rows : %" HIGHSINT_FORMAT "\n", lp.num_row_); highsLogDev(log_options, HighsLogType::kInfo, "Cols : %" HIGHSINT_FORMAT "\n", lp.num_col_); if (q_num_nz) { highsLogDev(log_options, HighsLogType::kInfo, "Matrix Nz : %" HIGHSINT_FORMAT "\n", a_num_nz); highsLogDev(log_options, HighsLogType::kInfo, "Hessian Nz: %" HIGHSINT_FORMAT "\n", q_num_nz); } else { highsLogDev(log_options, HighsLogType::kInfo, "Nonzeros : %" HIGHSINT_FORMAT "\n", a_num_nz); } if (num_integer) highsLogDev(log_options, HighsLogType::kInfo, "Integer : %" HIGHSINT_FORMAT "\n", num_integer); if (num_semi_continuous) highsLogDev(log_options, HighsLogType::kInfo, "SemiConts : %" HIGHSINT_FORMAT "\n", num_semi_continuous); if (num_semi_integer) highsLogDev(log_options, HighsLogType::kInfo, "SemiInt : %" HIGHSINT_FORMAT "\n", num_semi_integer); } else { highsLogUser(log_options, HighsLogType::kInfo, "%s", problem_type.c_str()); if (lp.model_name_.length()) highsLogUser(log_options, HighsLogType::kInfo, " %s", lp.model_name_.c_str()); highsLogUser(log_options, HighsLogType::kInfo, " has %" HIGHSINT_FORMAT " rows; %" HIGHSINT_FORMAT " cols", lp.num_row_, lp.num_col_); if (q_num_nz) { highsLogUser(log_options, HighsLogType::kInfo, "; %" HIGHSINT_FORMAT " matrix nonzeros", a_num_nz); highsLogUser(log_options, HighsLogType::kInfo, "; %" HIGHSINT_FORMAT " Hessian nonzeros", q_num_nz); } else { highsLogUser(log_options, HighsLogType::kInfo, "; %" HIGHSINT_FORMAT " nonzeros", a_num_nz); } if (num_integer) highsLogUser(log_options, HighsLogType::kInfo, "; %" HIGHSINT_FORMAT " integer variables", num_integer); if (num_semi_continuous) highsLogUser(log_options, HighsLogType::kInfo, "; %" HIGHSINT_FORMAT " semi-continuous variables", num_semi_continuous); if (num_semi_integer) highsLogUser(log_options, HighsLogType::kInfo, "; %" HIGHSINT_FORMAT " semi-integer variables", num_semi_integer); highsLogUser(log_options, HighsLogType::kInfo, "\n"); } } }