diff --git a/.github/workflows/test-fortran-macos.yml b/.github/workflows/test-fortran-macos.yml new file mode 100644 index 0000000000..e90da71869 --- /dev/null +++ b/.github/workflows/test-fortran-macos.yml @@ -0,0 +1,43 @@ +name: test-fortran-macos + +on: [push, pull_request] + +jobs: + fast_build_release: + runs-on: macos-12 + + + steps: + - uses: actions/checkout@v4 + + - uses: fortran-lang/setup-fortran@v1.6 + id: setup-fortran + with: + compiler: gcc + version: 11 + + # - name: Install GFortran + # run: brew install gfortran gcc + + - name: Create Build Environment + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Configure CMake + shell: bash + working-directory: ${{runner.workspace}}/build + run: | + cmake --version + gfortran-11 --version + cmake $GITHUB_WORKSPACE -DFORTRAN=ON + + - name: Build + shell: bash + working-directory: ${{runner.workspace}}/build + run: cmake --build . --parallel + + - name: Test + shell: bash + working-directory: ${{runner.workspace}}/build + run: | + ls + ./bin/fortrantest diff --git a/.github/workflows/test-fortran-ubuntu.yml b/.github/workflows/test-fortran-ubuntu.yml index 937f51b12c..7030087313 100644 --- a/.github/workflows/test-fortran-ubuntu.yml +++ b/.github/workflows/test-fortran-ubuntu.yml @@ -1,4 +1,4 @@ -name: test-fortran +name: test-fortran-ubuntu on: [push, pull_request] diff --git a/CMakeLists.txt b/CMakeLists.txt index 595da87831..aa59302874 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -209,7 +209,7 @@ if (BUILD_CXX) "but it is not supported by the compiler. The check failed with this output:\n" "${check_ipo_support_output}") endif() - elseif(NOT ipo_supported) + elseif(NOT ipo_supported OR (APPLE AND FORTRAN)) message(STATUS "IPO / LTO: disabled because it is not supported") elseif(NOT BUILD_SHARED_LIBS) # For a static library, we can't be sure whether the final linking will diff --git a/FEATURES.md b/FEATURES.md index 09784c9767..c587caf6ee 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -1,41 +1,22 @@ ## Build changes -### HiGHS on nixpkgs +The python wrapper highspy is now available for aarch64 on manylinux +This allows highs to be run through Python on AWS arm64 -HiGHS now has a `flake.nix` to build the binary, allowing `nix` users to try it out - -### Python build update - -Highspy with setuptools from v1.7.0 only worked on Python 3.12 -For v1.7.0 we have dropped setuptools and switched to scikit-build-core - -### Windows versions - -Fixed version info of shared library -Added version info to executable +Bug fix for fortran on macOS ## Code changes -Inserting `pdlp_iteration_count` into various structs (for v1.7.0) breaks the C API, so it has been moved to the end of those structs - -`setBasis` has been added to `highspy` - -`writePresolvedModel` has been added - -Saved MIP solution pool is populated when presolve reduces MIP to empty - -Compilation date has been removed improve build reproducibility. Methods to print compilation dates are deprecated - -Logging and error return when user-supplied solution or basis is rejected on vector dimensions - -Memory allocation errors in presolve are caught and `Highs::run()` returns `HighsStatus::kError` with `model_status_ = HighsModelStatus::kMemoryLimit` - -QP solver logging is now neater and quieter - -Any Hessian for the incumbent model is modified with zero entries when adding columns to the model, and rows/columns are removed when columns are deleted from the model. +The accessor function Highs_getCallbackDataOutItem in the C API means +that `pdlp_iteration_count` can be moved back to where it was inserted +into the `HighsCallbackDataOut` struct in v1.7.0, which broke the C +API. This fixes #1812 -Minor bug fix in MIP presolve +Some duplicate code has been eliminated from the MIP solver, and +modifications made to eliminate compiler warnings -QP solver will now hot start given a basis and solution +Declaration of the (deprecated) method `char* highsCompilationDate()` +has been corrected +Fixed bug when describing integrality status during the human-readable solution write diff --git a/check/CMakeLists.txt b/check/CMakeLists.txt index 0367e593be..366a4c5924 100644 --- a/check/CMakeLists.txt +++ b/check/CMakeLists.txt @@ -321,4 +321,4 @@ if (NOT FAST_BUILD OR ALL_TESTS) endforeach(setting) endforeach() -endif() \ No newline at end of file +endif() diff --git a/check/TestHighsVersion.cpp b/check/TestHighsVersion.cpp index 6a133d1a03..0d41016f5b 100644 --- a/check/TestHighsVersion.cpp +++ b/check/TestHighsVersion.cpp @@ -13,6 +13,8 @@ TEST_CASE("HighsVersion", "[highs_version]") { const HighsInt major = highsVersionMajor(); const HighsInt minor = highsVersionMinor(); const HighsInt patch = highsVersionPatch(); + const std::string compilation = highsCompilationDate(); + const std::string githash = std::string(highsGithash()); std::stringstream ss; ss << major << "." << minor << "." << patch; std::string local_version = ss.str(); @@ -21,15 +23,31 @@ TEST_CASE("HighsVersion", "[highs_version]") { printf("HiGHS major version %d\n", int(major)); printf("HiGHS minor version %d\n", int(minor)); printf("HiGHS patch version %d\n", int(patch)); - printf("HiGHS githash: %s\n", highsGithash()); - // Compilation date is deprecated. - // printf("HiGHS compilation date: %s\n", highsCompilationDate()); + printf("HiGHS githash: %s\n", githash.c_str()); + // Compilation date is deprecated, but make sure that the + // deprecated method is still tested. + printf("HiGHS compilation date: %s\n", compilation.c_str()); printf("HiGHS local version: %s\n", local_version.c_str()); } REQUIRE(major == HIGHS_VERSION_MAJOR); REQUIRE(minor == HIGHS_VERSION_MINOR); REQUIRE(patch == HIGHS_VERSION_PATCH); - REQUIRE(local_version == version); + REQUIRE(githash == std::string(HIGHS_GITHASH)); + REQUIRE(version == local_version); + // Check that the corresponding methods + Highs highs; + const std::string version0 = highs.version(); + REQUIRE(version0 == version); + const HighsInt major0 = highs.versionMajor(); + REQUIRE(major0 == major); + const HighsInt minor0 = highs.versionMinor(); + REQUIRE(minor0 == minor); + const HighsInt patch0 = highs.versionPatch(); + REQUIRE(patch0 == patch); + const std::string githash0 = highs.githash(); + REQUIRE(githash0 == githash); + const std::string compilation0 = highs.compilationDate(); + REQUIRE(compilation == compilation); } TEST_CASE("sizeof-highs-int", "[highs_version]") { diff --git a/cmake/README.md b/cmake/README.md index 4cb04ac682..5a24107a5a 100644 --- a/cmake/README.md +++ b/cmake/README.md @@ -3,7 +3,7 @@ | OS | C++ | Fortran | Python | CSharp Example | .NET | |:-------- | :---: | :------: | :----: | :----: | :----: | | Linux | [![Status][linux_cpp_svg]][linux_cpp_link] | [![Status][linux_fortran_svg]][linux_fortran_link] | [![Status][linux_python_svg]][linux_python_link] | *(1)* | [![Status][linux_dotnet_svg]][linux_dotnet_link] | -| MacOS | [![Status][macos_cpp_svg]][macos_cpp_link] | *(2)* | [![Status][macos_python_svg]][macos_python_link] | *(1)* |[![Status][macos_dotnet_svg]][macos_dotnet_link] | +| MacOS | [![Status][macos_cpp_svg]][macos_cpp_link] | [![Status][macos_fortran_svg]][macos_fortran_link] | [![Status][macos_python_svg]][macos_python_link] | *(1)* |[![Status][macos_dotnet_svg]][macos_dotnet_link] | | Windows | [![Status][windows_cpp_svg]][windows_cpp_link] | *(2)* | [![Status][windows_python_svg]][windows_python_link] | [![Status][windows_csharp_svg]][windows_csharp_link] | [![Status][windows_dotnet_svg]][windows_dotnet_link] | [linux_cpp_svg]: https://github.com/ERGO-Code/HiGHS/actions/workflows/cmake-linux-cpp.yml/badge.svg diff --git a/docs/src/guide/basic.md b/docs/src/guide/basic.md index 764b99ecd4..1b674a84a6 100644 --- a/docs/src/guide/basic.md +++ b/docs/src/guide/basic.md @@ -20,14 +20,17 @@ and [classes](@ref classes-overview), and are referred to below. #### [Enums](@id guide-basic-enums) -Enums are scalar identifier types that can take only a limited range of values.???? - -#### The -advantage using these classes is that many fewer parameters are -needed when passing data to and from HiGHS. However, the use of -classes is not necessary for the basic use of `highspy`. As with the -`C` and `Fortran` interfaces, there are equivalent methods that use -simple scalars and vectors of data. +Enums are scalar identifier types that can take only a limited range of values. + +#### [Classes](@id guide-basic-classes) + +The advantage of using the native `C++` classes in HiGHS is that many fewer parameters are needed +when passing data to and from HiGHS. The binding of the data members +of these classes to `highspy` structures allows them to be used when +calling HiGHS from Python, although they are not necessary for the +basic use of `highspy`. As with the `C` and `Fortran` interfaces, +there are equivalent methods that use simple scalars and vectors of +data. ## Defining a model diff --git a/docs/src/interfaces/python/example-py.md b/docs/src/interfaces/python/example-py.md index 9fe1989be8..d75c67dd9e 100644 --- a/docs/src/interfaces/python/example-py.md +++ b/docs/src/interfaces/python/example-py.md @@ -210,7 +210,7 @@ print('Basis validity = ', h.basisValidityToString(info.basis_validity)) * `changeColCost` * `changeColBounds` * `changeRowBounds` - * `changeColsCosts` + * `changeColsCost` * `changeColsBounds` * `changeRowsBounds` * `changeCoeff` diff --git a/docs/src/options/definitions.md b/docs/src/options/definitions.md index ba3988e850..2505c4d3c3 100644 --- a/docs/src/options/definitions.md +++ b/docs/src/options/definitions.md @@ -341,3 +341,15 @@ - Range: [1e-12, inf] - Default: 0.0001 +## qp\_iteration\_limit +- Iteration limit for QP solver +- Type: integer +- Range: {0, 2147483647} +- Default: 2147483647 + +## qp\_nullspace\_limit +- Nullspace limit for QP solver +- Type: integer +- Range: {0, 2147483647} +- Default: 4000 + diff --git a/docs/src/structures/enums.md b/docs/src/structures/enums.md index af9601b7c2..7975e41fb0 100644 --- a/docs/src/structures/enums.md +++ b/docs/src/structures/enums.md @@ -73,6 +73,8 @@ This defines the status of the model after a call to `run` * `kTimeLimit`: The run time limit has been reached * `kIterationLimit`: The iteration limit has been reached * `kSolutionLimit`: The MIP solver has reached the limit on the number of LPs solved + * `kInterrupt`: The solver has been interrupted by the user + * `kMemoryLimit`: The solver has been unable to allocate sufficient memory * `kUnknown`: The model status is unknown ## HighsBasisStatus diff --git a/extern/zstr/strict_fstream.hpp b/extern/zstr/strict_fstream.hpp index 6c3ea85d90..953311a907 100644 --- a/extern/zstr/strict_fstream.hpp +++ b/extern/zstr/strict_fstream.hpp @@ -17,7 +17,7 @@ namespace strict_fstream { -// Help people out a bit, it seems like this is a common recommenation since +// Help people out a bit, it seems like this is a common recommendation since // musl breaks all over the place. #if defined(__NEED_size_t) && !defined(__MUSL__) #warning "It seems to be recommended to patch in a define for __MUSL__ if you use musl globally: https://www.openwall.com/lists/musl/2013/02/10/5" diff --git a/src/Highs.h b/src/Highs.h index 94d6193cf3..7b3c08ca26 100644 --- a/src/Highs.h +++ b/src/Highs.h @@ -1212,11 +1212,7 @@ class Highs { // Start of deprecated methods - /** - * @brief Return compilation date - */ std::string compilationDate() const { return "deprecated"; } - const char* highsCompilationDate(); HighsStatus setLogCallback(void (*user_log_callback)(HighsLogType, const char*, void*), @@ -1525,4 +1521,9 @@ class Highs { const double ill_conditioning_bound); bool infeasibleBoundsOk(); }; + +// Start of deprecated methods not in the Highs class + +const char* highsCompilationDate(); + #endif diff --git a/src/io/HMPSIO.cpp b/src/io/HMPSIO.cpp index 69e906b66e..b6037d3624 100644 --- a/src/io/HMPSIO.cpp +++ b/src/io/HMPSIO.cpp @@ -564,7 +564,7 @@ HighsStatus writeModelAsMps(const HighsOptions& options, HighsStatus row_name_status = normaliseNames(options.log_options, "row", lp.num_row_, local_row_names, max_row_name_length); - if (row_name_status == HighsStatus::kError) return col_name_status; + if (row_name_status == HighsStatus::kError) return row_name_status; warning_found = row_name_status == HighsStatus::kWarning || warning_found; HighsInt max_name_length = std::max(max_col_name_length, max_row_name_length); diff --git a/src/io/HMpsFF.cpp b/src/io/HMpsFF.cpp index cf18f204d5..14f0bf5dc0 100644 --- a/src/io/HMpsFF.cpp +++ b/src/io/HMpsFF.cpp @@ -2036,12 +2036,12 @@ double HMpsFF::getValue(const std::string& word, bool& is_nan, const HighsInt id) const { // Lambda to replace any d or D by E auto dD2e = [&](std::string& word) { - HighsInt ix = word.find("D"); - if (ix >= 0) { + size_t ix = word.find("D"); + if (ix != std::string::npos) { word.replace(ix, 1, "E"); } else { ix = word.find("d"); - if (ix >= 0) word.replace(ix, 1, "E"); + if (ix != std::string::npos) word.replace(ix, 1, "E"); } }; diff --git a/src/io/HighsIO.h b/src/io/HighsIO.h index 7dd398d86d..adead90c24 100644 --- a/src/io/HighsIO.h +++ b/src/io/HighsIO.h @@ -45,14 +45,23 @@ struct HighsLogOptions { bool* output_flag; bool* log_to_console; HighsInt* log_dev_level; - void (*user_log_callback)(HighsLogType, const char*, void*) = nullptr; - void* user_log_callback_data = nullptr; + void (*user_log_callback)(HighsLogType, const char*, void*); + void* user_log_callback_data; std::function user_callback; - void* user_callback_data = nullptr; - bool user_callback_active = false; + void* user_callback_data; + bool user_callback_active; void clear(); + HighsLogOptions() + : log_stream(nullptr), + output_flag(nullptr), + log_to_console(nullptr), + log_dev_level(nullptr), + user_log_callback(nullptr), + user_log_callback_data(nullptr), + user_callback_data(nullptr), + user_callback_active(false){}; }; /** diff --git a/src/ipm/ipx/crossover.h b/src/ipm/ipx/crossover.h index 3587014353..7e16b00eb1 100644 --- a/src/ipm/ipx/crossover.h +++ b/src/ipm/ipx/crossover.h @@ -44,7 +44,7 @@ class Crossover { // as long as the Crossover object is used. Crossover(const Control& control); - // First runs the dual push phase; if this was succesful, then runs the + // First runs the dual push phase; if this was successful, then runs the // primal push phase. // // weights: Must either be NULL or an array of size n+m. diff --git a/src/ipm/ipx/forrest_tomlin.h b/src/ipm/ipx/forrest_tomlin.h index 32c373080b..dc60bfd6ab 100644 --- a/src/ipm/ipx/forrest_tomlin.h +++ b/src/ipm/ipx/forrest_tomlin.h @@ -11,7 +11,7 @@ namespace ipx { // Generic implementation of the Forrest-Tomlin update [1] that can be used with // any LU factorization. The implementation does not exploit hypersparsity, -// which exludes its use for such problems. For non-hypersparse problems the +// which excludes its use for such problems. For non-hypersparse problems the // implementation is better suited than BASICLU, however, because it stores L // and U in compressed form with permuted indices; hence solving triangular // systems with a dense rhs/lhs accesses memory contiguously. BASICLU could not diff --git a/src/ipm/ipx/indexed_vector.h b/src/ipm/ipx/indexed_vector.h index 6ad46af292..07a0864be1 100644 --- a/src/ipm/ipx/indexed_vector.h +++ b/src/ipm/ipx/indexed_vector.h @@ -24,7 +24,7 @@ namespace ipx { // otherwise. // // When modifying the vector changes its pattern (e.g. by writing to v[i] for an -// arbitray index i), you have to invalidate the pattern or provide the new one. +// arbitrary index i), you have to invalidate the pattern or provide the new one. class IndexedVector { public: diff --git a/src/ipm/ipx/iterate.cc b/src/ipm/ipx/iterate.cc index 755e143f8f..c407eb3de4 100644 --- a/src/ipm/ipx/iterate.cc +++ b/src/ipm/ipx/iterate.cc @@ -279,7 +279,7 @@ void Iterate::Postprocess() { // For fixed variables compute xl[j] and xu[j] from x[j]. If the lower and // upper bound are equal, set zl[j] or zu[j] such that the variable is dual - // feasibile. Otherwise leave them zero. + // feasible. Otherwise leave them zero. for (Int j = 0; j < n+m; j++) { if (StateOf(j) == State::fixed) { xl_[j] = x_[j] - lb[j]; diff --git a/src/ipm/ipx/iterate.h b/src/ipm/ipx/iterate.h index 53b05cce37..0f1ce529d4 100644 --- a/src/ipm/ipx/iterate.h +++ b/src/ipm/ipx/iterate.h @@ -77,7 +77,7 @@ class Iterate { double zl(Int j) const { return zl_[j]; } double zu(Int j) const { return zu_[j]; } - // Returns const rerefences to the residual vectors + // Returns const references to the residual vectors // rb = b-AI*x, // rl = lb-x+xl, // ru = ub-x-xu, @@ -155,7 +155,7 @@ class Iterate { double presidual() const; double dresidual() const; - // copmlementarity() returns the sum of the pairwise complementarity + // complementarity() returns the sum of the pairwise complementarity // products xl[j]*zl[j] and xu[j]*zu[j] from all barrier terms. mu() // returns the average, mu_min() the minimum and mu_max() the maximum. double complementarity() const; diff --git a/src/ipm/ipx/lu_factorization.h b/src/ipm/ipx/lu_factorization.h index 6effb8b094..5bc4340678 100644 --- a/src/ipm/ipx/lu_factorization.h +++ b/src/ipm/ipx/lu_factorization.h @@ -38,7 +38,7 @@ class LuFactorization { // kLuDependencyTol as absolute pivot tolerance and to // remove columns from the active submatrix // immediately when all entries became smaller than - // the abolute pivot tolerance. Need not be supported + // the absolute pivot tolerance. Need not be supported // by the implementation. // @L, @U: return the matrix factors with sorted indices. The objects are // resized as necessary. diff --git a/src/ipm/ipx/lu_update.h b/src/ipm/ipx/lu_update.h index 2ef13e0228..299ec4d8c0 100644 --- a/src/ipm/ipx/lu_update.h +++ b/src/ipm/ipx/lu_update.h @@ -25,7 +25,7 @@ class LuUpdate { // kLuDependencyTol as absolute pivot tolerance and to // remove columns from the active submatrix // immediately when all entries became smaller than - // the abolute pivot tolerance. Need not be supported + // the absolute pivot tolerance. Need not be supported // by the implementation. // // Factorize() cannot fail other than for out of memory, in which case diff --git a/src/ipm/ipx/sparse_utils.h b/src/ipm/ipx/sparse_utils.h index 54bdbc782c..db45600ef7 100644 --- a/src/ipm/ipx/sparse_utils.h +++ b/src/ipm/ipx/sparse_utils.h @@ -16,7 +16,7 @@ namespace ipx { // have previously been unmarked; they are marked now and newtop // is returned. // @marked, @marker Node i is "marked" iff @marked[i] == @marker. -// @work worksapce of size # rows of A. +// @work workspace of size # rows of A. // // The code has been copied and adapted from cs_dfs.c, included in the CSPARSE // package [1]. diff --git a/src/lp_data/Highs.cpp b/src/lp_data/Highs.cpp index a2f6cd517d..fa600bba14 100644 --- a/src/lp_data/Highs.cpp +++ b/src/lp_data/Highs.cpp @@ -2320,12 +2320,12 @@ HighsStatus Highs::changeColsIntegrality(const HighsInt from_col, return returnFromHighs(return_status); } -HighsStatus analyseSetCreateError(HighsLogOptions log_options, - const std::string method, - const HighsInt create_error, - const bool ordered, - const HighsInt num_set_entries, - const HighsInt dimension) { +static HighsStatus analyseSetCreateError(HighsLogOptions log_options, + const std::string method, + const HighsInt create_error, + const bool ordered, + const HighsInt num_set_entries, + const HighsInt dimension) { if (create_error == kIndexCollectionCreateIllegalSetSize) { highsLogUser(log_options, HighsLogType::kError, "Set supplied to Highs::%s has illegal size of %d\n", diff --git a/src/lp_data/HighsCallbackStruct.h b/src/lp_data/HighsCallbackStruct.h index 4553707f61..b76716d3eb 100644 --- a/src/lp_data/HighsCallbackStruct.h +++ b/src/lp_data/HighsCallbackStruct.h @@ -1,3 +1,4 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* */ /* This file is part of the HiGHS linear optimization suite */ /* */ @@ -28,6 +29,7 @@ typedef struct { double running_time; HighsInt simplex_iteration_count; HighsInt ipm_iteration_count; + HighsInt pdlp_iteration_count; double objective_function_value; int64_t mip_node_count; double mip_primal_bound; @@ -42,7 +44,6 @@ typedef struct { double* cutpool_value; double* cutpool_lower; double* cutpool_upper; - HighsInt pdlp_iteration_count; } HighsCallbackDataOut; typedef struct { diff --git a/src/lp_data/HighsInterface.cpp b/src/lp_data/HighsInterface.cpp index 7f7a201f99..d5ffd342a0 100644 --- a/src/lp_data/HighsInterface.cpp +++ b/src/lp_data/HighsInterface.cpp @@ -2198,7 +2198,7 @@ void Highs::formIllConditioningLp0(HighsLp& ill_conditioning_lp, ill_conditioning_matrix.value_.push_back(1.0); ill_conditioning_matrix.start_.push_back( HighsInt(ill_conditioning_matrix.index_.size())); - // Subracting x_- with cost 1 + // Subtracting x_- with cost 1 ill_conditioning_lp.col_cost_.push_back(1); ill_conditioning_lp.col_lower_.push_back(0); ill_conditioning_lp.col_upper_.push_back(kHighsInf); @@ -2312,7 +2312,7 @@ void Highs::formIllConditioningLp1(HighsLp& ill_conditioning_lp, } assert(ill_conditioning_lp.num_col_ == incumbent_num_row); if (constraint) { - // Add the identiy matrix for constraint y - u + w = 0 + // Add the identity matrix for constraint y - u + w = 0 for (HighsInt iRow = 0; iRow < incumbent_num_row; iRow++) { ill_conditioning_matrix.index_.push_back(iRow); ill_conditioning_matrix.value_.push_back(1.0); diff --git a/src/lp_data/HighsModelUtils.cpp b/src/lp_data/HighsModelUtils.cpp index cc48527032..6a60010282 100644 --- a/src/lp_data/HighsModelUtils.cpp +++ b/src/lp_data/HighsModelUtils.cpp @@ -319,8 +319,8 @@ bool hasNamesWithSpaces(const HighsLogOptions& log_options, const std::vector& names) { HighsInt num_names_with_spaces = 0; for (HighsInt ix = 0; ix < num_name; ix++) { - HighsInt space_pos = names[ix].find(" "); - if (space_pos >= 0) { + size_t space_pos = names[ix].find(" "); + if (space_pos != std::string::npos) { if (num_names_with_spaces == 0) { highsLogDev( log_options, HighsLogType::kInfo, @@ -398,10 +398,12 @@ void writeSolutionFile(FILE* file, const HighsOptions& options, if (style == kSolutionStyleOldRaw) { writeOldRawSolution(file, lp, basis, solution); } else if (style == kSolutionStylePretty) { - writeModelBoundSolution( - file, true, lp.num_col_, lp.col_lower_, lp.col_upper_, lp.col_names_, - have_primal, solution.col_value, have_dual, solution.col_dual, - have_basis, basis.col_status, lp.integrality_.data()); + const HighsVarType* integrality = + lp.integrality_.size() > 0 ? lp.integrality_.data() : nullptr; + writeModelBoundSolution(file, true, lp.num_col_, lp.col_lower_, + lp.col_upper_, lp.col_names_, have_primal, + solution.col_value, have_dual, solution.col_dual, + have_basis, basis.col_status, integrality); writeModelBoundSolution(file, false, lp.num_row_, lp.row_lower_, lp.row_upper_, lp.row_names_, have_primal, solution.row_value, have_dual, solution.row_dual, diff --git a/src/lp_data/HighsOptions.h b/src/lp_data/HighsOptions.h index 38be9b59ae..9a9bb29aa6 100644 --- a/src/lp_data/HighsOptions.h +++ b/src/lp_data/HighsOptions.h @@ -424,6 +424,128 @@ struct HighsOptionsStruct { // Logging callback identifiers HighsLogOptions log_options; virtual ~HighsOptionsStruct() {} + + HighsOptionsStruct() + : presolve(""), + solver(""), + parallel(""), + run_crossover(""), + time_limit(0.0), + solution_file(""), + write_model_file(""), + random_seed(0), + ranging(""), + infinite_cost(0.0), + infinite_bound(0.0), + small_matrix_value(0.0), + large_matrix_value(0.0), + primal_feasibility_tolerance(0.0), + dual_feasibility_tolerance(0.0), + ipm_optimality_tolerance(0.0), + objective_bound(0.0), + objective_target(0.0), + threads(0), + user_bound_scale(0), + user_cost_scale(0), + highs_debug_level(0), + highs_analysis_level(0), + simplex_strategy(0), + simplex_scale_strategy(0), + simplex_crash_strategy(0), + simplex_dual_edge_weight_strategy(0), + simplex_primal_edge_weight_strategy(0), + simplex_iteration_limit(0), + simplex_update_limit(0), + simplex_min_concurrency(0), + simplex_max_concurrency(0), + log_file(""), + write_model_to_file(false), + write_solution_to_file(false), + write_solution_style(0), + glpsol_cost_row_location(0), + output_flag(false), + log_to_console(false), + ipm_iteration_limit(0), + pdlp_native_termination(false), + pdlp_scaling(false), + pdlp_iteration_limit(0), + pdlp_e_restart_method(0), + pdlp_d_gap_tol(0.0), + qp_iteration_limit(0), + qp_nullspace_limit(0), + log_dev_level(0), + log_githash(false), + solve_relaxation(false), + allow_unbounded_or_infeasible(false), + use_implied_bounds_from_presolve(false), + lp_presolve_requires_basis_postsolve(false), + mps_parser_type_free(false), + keep_n_rows(0), + cost_scale_factor(0), + allowed_matrix_scale_factor(0), + allowed_cost_scale_factor(0), + ipx_dualize_strategy(0), + simplex_dualize_strategy(0), + simplex_permute_strategy(0), + max_dual_simplex_cleanup_level(0), + max_dual_simplex_phase1_cleanup_level(0), + simplex_price_strategy(0), + simplex_unscaled_solution_strategy(0), + presolve_reduction_limit(0), + restart_presolve_reduction_limit(0), + presolve_substitution_maxfillin(0), + presolve_rule_off(0), + presolve_rule_logging(false), + simplex_initial_condition_check(false), + no_unnecessary_rebuild_refactor(false), + simplex_initial_condition_tolerance(0.0), + rebuild_refactor_solution_error_tolerance(0.0), + dual_steepest_edge_weight_error_tolerance(0.0), + dual_steepest_edge_weight_log_error_threshold(0.0), + dual_simplex_cost_perturbation_multiplier(0.0), + primal_simplex_bound_perturbation_multiplier(0.0), + dual_simplex_pivot_growth_tolerance(0.0), + presolve_pivot_threshold(0.0), + factor_pivot_threshold(0.0), + factor_pivot_tolerance(0.0), + start_crossover_tolerance(0.0), + less_infeasible_DSE_check(false), + less_infeasible_DSE_choose_row(false), + use_original_HFactor_logic(false), + run_centring(false), + max_centring_steps(0), + centring_ratio_tolerance(0.0), + icrash(false), + icrash_dualize(false), + icrash_strategy(""), + icrash_starting_weight(0.0), + icrash_iterations(0), + icrash_approx_iter(0), + icrash_exact(false), + icrash_breakpoints(false), + mip_detect_symmetry(false), + mip_allow_restart(false), + mip_max_nodes(0), + mip_max_stall_nodes(0), + mip_max_leaves(0), + mip_max_improving_sols(0), + mip_lp_age_limit(0), + mip_pool_age_limit(0), + mip_pool_soft_limit(0), + mip_pscost_minreliable(0), + mip_min_cliquetable_entries_for_parallelism(0), + mip_report_level(0), + mip_feasibility_tolerance(0.0), + mip_rel_gap(0.0), + mip_abs_gap(0.0), + mip_heuristic_effort(0.0), + mip_min_logging_interval(0.0), +#ifdef HIGHS_DEBUGSOL + mip_debug_solution_file(""), +#endif + mip_improving_solution_save(false), + mip_improving_solution_report_sparse(false), + mip_improving_solution_file(""){}; }; // For now, but later change so HiGHS properties are string based so that new @@ -817,7 +939,7 @@ class HighsOptions : public HighsOptionsStruct { record_string = new OptionRecordString( "mip_improving_solution_file", "File for reporting improving MIP solutions: not reported for an empty " - "string \"\"", + "string \\\"\\\"", advanced, &mip_improving_solution_file, kHighsFilenameDefault); records.push_back(record_string); diff --git a/src/lp_data/HighsSolve.cpp b/src/lp_data/HighsSolve.cpp index 29377e7fec..d839bfb88d 100644 --- a/src/lp_data/HighsSolve.cpp +++ b/src/lp_data/HighsSolve.cpp @@ -254,7 +254,7 @@ HighsStatus solveUnconstrainedLp(const HighsOptions& options, const HighsLp& lp, if (lp.num_row_ > 0) { // Assign primal, dual and basis status for rows, checking for - // infeasiblility + // infeasibility for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) { double primal_infeasibility = 0; double lower = lp.row_lower_[iRow]; diff --git a/src/mip/HighsCliqueTable.cpp b/src/mip/HighsCliqueTable.cpp index 9a51cda7f9..54490e08e0 100644 --- a/src/mip/HighsCliqueTable.cpp +++ b/src/mip/HighsCliqueTable.cpp @@ -189,7 +189,7 @@ void HighsCliqueTable::bronKerboschRecurse(BronKerboschData& data, if (data.stop()) return; double pivweight = -1.0; - CliqueVar pivot; + CliqueVar pivot{0, 0}; for (HighsInt i = 0; i != Xlen; ++i) { if (X[i].weight(data.sol) > pivweight) { @@ -2021,8 +2021,9 @@ void HighsCliqueTable::runCliqueMerging(HighsDomain& globaldomain, std::remove_if(clique.begin(), clique.end(), [&](CliqueVar v) { return globaldomain.isFixed(v.col) && - int(globaldomain.col_lower_[v.col]) == - (1 - v.val); + static_cast( + globaldomain.col_lower_[v.col]) == + static_cast(1 - v.val); }), clique.end()); } @@ -2190,8 +2191,9 @@ void HighsCliqueTable::runCliqueMerging(HighsDomain& globaldomain) { std::remove_if(extensionvars.begin(), extensionvars.end(), [&](CliqueVar v) { return globaldomain.isFixed(v.col) && - int(globaldomain.col_lower_[v.col]) == - (1 - v.val); + static_cast( + globaldomain.col_lower_[v.col]) == + static_cast(1 - v.val); }), extensionvars.end()); diff --git a/src/mip/HighsDebugSol.h b/src/mip/HighsDebugSol.h index 9c8852ad9b..ddce632c45 100644 --- a/src/mip/HighsDebugSol.h +++ b/src/mip/HighsDebugSol.h @@ -88,54 +88,47 @@ struct HighsDebugSol { #else struct HighsDebugSol { - HighsDebugSol(HighsMipSolver& mipsolver) {} + HighsDebugSol(HighsMipSolver&) {} void newIncumbentFound() const {} void activate() const {} - void shrink(const std::vector& newColIndex) const {} + void shrink(const std::vector&) const {} - void registerDomain(const HighsDomain& domain) const {} + void registerDomain(const HighsDomain&) const {} - void boundChangeAdded(const HighsDomain& domain, - const HighsDomainChange& domchg, - bool branching = false) const {} + void boundChangeAdded(const HighsDomain&, const HighsDomainChange&, + bool = false) const {} - void boundChangeRemoved(const HighsDomain& domain, - const HighsDomainChange& domchg) const {} + void boundChangeRemoved(const HighsDomain&, const HighsDomainChange&) const {} - void resetDomain(const HighsDomain& domain) const {} + void resetDomain(const HighsDomain&) const {} - void nodePruned(const HighsDomain& localdomain) const {} + void nodePruned(const HighsDomain&) const {} - void checkCut(const HighsInt* Rindex, const double* Rvalue, HighsInt Rlen, - double rhs) const {} + void checkCut(const HighsInt*, const double*, HighsInt, double) const {} - void checkRow(const HighsInt* Rindex, const double* Rvalue, HighsInt Rlen, - double Rlower, double Rupper) const {} + void checkRow(const HighsInt*, const double*, HighsInt, double, + double) const {} - void checkRowAggregation(const HighsLp& lp, const HighsInt* Rindex, - const double* Rvalue, HighsInt Rlen) const {} + void checkRowAggregation(const HighsLp&, const HighsInt*, const double*, + HighsInt) const {} - void checkClique(const HighsCliqueTable::CliqueVar* clq, - HighsInt clqlen) const {} + void checkClique(const HighsCliqueTable::CliqueVar*, HighsInt) const {} - void checkVub(HighsInt col, HighsInt vubcol, double vubcoef, - double vubconstant) const {} + void checkVub(HighsInt, HighsInt, double, double) const {} - void checkVlb(HighsInt col, HighsInt vlbcol, double vlbcoef, - double vlbconstant) const {} + void checkVlb(HighsInt, HighsInt, double, double) const {} void checkConflictReasonFrontier( - const std::set& reasonSideFrontier, - const std::vector& domchgstack) const {} + const std::set&, + const std::vector&) const {} void checkConflictReconvergenceFrontier( - const std::set& - reconvergenceFrontier, - const HighsDomain::ConflictSet::LocalDomChg& reconvDomchgPos, - const std::vector& domchgstack) const {} + const std::set&, + const HighsDomain::ConflictSet::LocalDomChg&, + const std::vector&) const {} }; #endif diff --git a/src/mip/HighsDomain.cpp b/src/mip/HighsDomain.cpp index 8f084fe1f0..a00e8784c0 100644 --- a/src/mip/HighsDomain.cpp +++ b/src/mip/HighsDomain.cpp @@ -46,6 +46,29 @@ static double activityContributionMax(double coef, const double& lb, } } +static double computeDelta(double val, double oldbound, double newbound, + double inf, HighsInt& numinfs) { + // if bounds are huge, HighsCDouble should be used when computing bound + // differences. todo: qualify usage of HighsCDouble in this function. + if (oldbound == inf) { + --numinfs; + return newbound * val; + } else if (newbound == inf) { + ++numinfs; + return -oldbound * val; + } else { + return (newbound - oldbound) * val; + } +} + +static inline double boundRange(double upper_bound, double lower_bound, + double tolerance, HighsVarType var_type) { + double range = upper_bound - lower_bound; + return range - (var_type == HighsVarType::kContinuous + ? std::max(0.3 * range, 1000.0 * tolerance) + : tolerance); +} + HighsDomain::HighsDomain(HighsMipSolver& mipsolver) : mipsolver(&mipsolver) { col_lower_ = mipsolver.model_->col_lower_; col_upper_ = mipsolver.model_->col_upper_; @@ -369,14 +392,11 @@ void HighsDomain::CutpoolPropagation::recomputeCapacityThreshold(HighsInt cut) { if (domain->col_upper_[arindex[i]] == domain->col_lower_[arindex[i]]) continue; - double boundRange = - domain->col_upper_[arindex[i]] - domain->col_lower_[arindex[i]]; - - boundRange -= domain->variableType(arindex[i]) == HighsVarType::kContinuous - ? std::max(0.3 * boundRange, 1000.0 * domain->feastol()) - : domain->feastol(); - - double threshold = std::fabs(arvalue[i]) * boundRange; + double threshold = + std::fabs(arvalue[i]) * boundRange(domain->col_upper_[arindex[i]], + domain->col_lower_[arindex[i]], + domain->feastol(), + domain->variableType(arindex[i])); capacityThreshold_[cut] = std::max({capacityThreshold_[cut], threshold, domain->feastol()}); @@ -461,17 +481,8 @@ void HighsDomain::CutpoolPropagation::updateActivityLbChange(HighsInt col, cutpool->getMatrix().forEachPositiveColumnEntry( col, [&](HighsInt row, double val) { assert(val > 0); - double deltamin; - - if (oldbound == -kHighsInf) { - --activitycutsinf_[row]; - deltamin = newbound * val; - } else if (newbound == -kHighsInf) { - ++activitycutsinf_[row]; - deltamin = -oldbound * val; - } else { - deltamin = (newbound - oldbound) * val; - } + double deltamin = computeDelta(val, oldbound, newbound, -kHighsInf, + activitycutsinf_[row]); activitycuts_[row] += deltamin; if (deltamin <= 0) { @@ -504,18 +515,8 @@ void HighsDomain::CutpoolPropagation::updateActivityLbChange(HighsInt col, cutpool->getMatrix().forEachPositiveColumnEntry( col, [&](HighsInt row, double val) { assert(val > 0); - double deltamin; - - if (oldbound == -kHighsInf) { - --activitycutsinf_[row]; - deltamin = newbound * val; - } else if (newbound == -kHighsInf) { - ++activitycutsinf_[row]; - deltamin = -oldbound * val; - } else { - deltamin = (newbound - oldbound) * val; - } - activitycuts_[row] += deltamin; + activitycuts_[row] += computeDelta(val, oldbound, newbound, + -kHighsInf, activitycutsinf_[row]); if (domain->infeasible_reason.index == row) return false; @@ -541,17 +542,8 @@ void HighsDomain::CutpoolPropagation::updateActivityUbChange(HighsInt col, cutpool->getMatrix().forEachNegativeColumnEntry( col, [&](HighsInt row, double val) { assert(val < 0); - double deltamin; - - if (oldbound == kHighsInf) { - --activitycutsinf_[row]; - deltamin = newbound * val; - } else if (newbound == kHighsInf) { - ++activitycutsinf_[row]; - deltamin = -oldbound * val; - } else { - deltamin = (newbound - oldbound) * val; - } + double deltamin = computeDelta(val, oldbound, newbound, kHighsInf, + activitycutsinf_[row]); activitycuts_[row] += deltamin; if (deltamin <= 0) { @@ -582,18 +574,8 @@ void HighsDomain::CutpoolPropagation::updateActivityUbChange(HighsInt col, cutpool->getMatrix().forEachNegativeColumnEntry( col, [&](HighsInt row, double val) { assert(val < 0); - double deltamin; - - if (oldbound == kHighsInf) { - --activitycutsinf_[row]; - deltamin = newbound * val; - } else if (newbound == kHighsInf) { - ++activitycutsinf_[row]; - deltamin = -oldbound * val; - } else { - deltamin = (newbound - oldbound) * val; - } - activitycuts_[row] += deltamin; + activitycuts_[row] += computeDelta(val, oldbound, newbound, kHighsInf, + activitycutsinf_[row]); if (domain->infeasible_reason.index == row) return false; @@ -780,12 +762,11 @@ void HighsDomain::ObjectivePropagation::recomputeCapacityThreshold() { for (HighsInt i = partitionStarts[numPartitions]; i < numObjNzs; ++i) { HighsInt col = objNonzeros[i]; - double boundRange = (domain->col_upper_[col] - domain->col_lower_[col]); - boundRange -= domain->variableType(col) == HighsVarType::kContinuous - ? std::max(0.3 * boundRange, 1000.0 * domain->feastol()) - : domain->feastol(); - capacityThreshold = - std::max(capacityThreshold, std::fabs(cost[col]) * boundRange); + capacityThreshold = std::max( + capacityThreshold, + std::fabs(cost[col]) * + boundRange(domain->col_upper_[col], domain->col_lower_[col], + domain->feastol(), domain->variableType(col))); } } @@ -793,11 +774,11 @@ void HighsDomain::ObjectivePropagation::updateActivityLbChange( HighsInt col, double oldbound, double newbound) { if (cost[col] <= 0.0) { if (cost[col] != 0.0 && newbound < oldbound) { - double boundRange = domain->col_upper_[col] - newbound; - boundRange -= domain->variableType(col) == HighsVarType::kContinuous - ? std::max(0.3 * boundRange, 1000.0 * domain->feastol()) - : domain->feastol(); - capacityThreshold = std::max(capacityThreshold, -cost[col] * boundRange); + capacityThreshold = + std::max(capacityThreshold, + -cost[col] * boundRange(domain->col_upper_[col], newbound, + domain->feastol(), + domain->variableType(col))); isPropagated = false; } debugCheckObjectiveLower(); @@ -821,11 +802,11 @@ void HighsDomain::ObjectivePropagation::updateActivityLbChange( debugCheckObjectiveLower(); if (newbound < oldbound) { - double boundRange = (domain->col_upper_[col] - domain->col_lower_[col]); - boundRange -= domain->variableType(col) == HighsVarType::kContinuous - ? std::max(0.3 * boundRange, 1000.0 * domain->feastol()) - : domain->feastol(); - capacityThreshold = std::max(capacityThreshold, cost[col] * boundRange); + capacityThreshold = std::max( + capacityThreshold, + cost[col] * boundRange(domain->col_upper_[col], + domain->col_lower_[col], domain->feastol(), + domain->variableType(col))); } else if (numInfObjLower == 0 && objectiveLower > domain->mipsolver->mipdata_->upper_limit) { domain->infeasible_ = true; @@ -914,11 +895,10 @@ void HighsDomain::ObjectivePropagation::updateActivityUbChange( HighsInt col, double oldbound, double newbound) { if (cost[col] >= 0.0) { if (cost[col] != 0.0 && newbound > oldbound) { - double boundRange = newbound - domain->col_lower_[col]; - boundRange -= domain->variableType(col) == HighsVarType::kContinuous - ? std::max(0.3 * boundRange, 1000.0 * domain->feastol()) - : domain->feastol(); - capacityThreshold = std::max(capacityThreshold, cost[col] * boundRange); + capacityThreshold = std::max( + capacityThreshold, + cost[col] * boundRange(newbound, domain->col_lower_[col], + domain->feastol(), domain->variableType(col))); isPropagated = false; } debugCheckObjectiveLower(); @@ -942,11 +922,11 @@ void HighsDomain::ObjectivePropagation::updateActivityUbChange( debugCheckObjectiveLower(); if (newbound > oldbound) { - double boundRange = (domain->col_upper_[col] - domain->col_lower_[col]); - boundRange -= domain->variableType(col) == HighsVarType::kContinuous - ? std::max(0.3 * boundRange, 1000.0 * domain->feastol()) - : domain->feastol(); - capacityThreshold = std::max(capacityThreshold, -cost[col] * boundRange); + capacityThreshold = std::max( + capacityThreshold, + -cost[col] * boundRange(domain->col_upper_[col], + domain->col_lower_[col], domain->feastol(), + domain->variableType(col))); } else if (numInfObjLower == 0 && objectiveLower > domain->mipsolver->mipdata_->upper_limit) { domain->infeasible_ = true; @@ -1287,7 +1267,6 @@ void HighsDomain::computeMinActivity(HighsInt start, HighsInt end, activitymin += contributionmin; } - activitymin.renormalize(); } else { activitymin = 0.0; ninfmin = 0; @@ -1305,9 +1284,8 @@ void HighsDomain::computeMinActivity(HighsInt start, HighsInt end, else activitymin += contributionmin; } - - activitymin.renormalize(); } + activitymin.renormalize(); } void HighsDomain::computeMaxActivity(HighsInt start, HighsInt end, @@ -1333,8 +1311,6 @@ void HighsDomain::computeMaxActivity(HighsInt start, HighsInt end, else activitymax += contributionmin; } - - activitymax.renormalize(); } else { activitymax = 0.0; ninfmax = 0; @@ -1352,9 +1328,8 @@ void HighsDomain::computeMaxActivity(HighsInt start, HighsInt end, else activitymax += contributionmin; } - - activitymax.renormalize(); } + activitymax.renormalize(); } double HighsDomain::adjustedUb(HighsInt col, HighsCDouble boundVal, @@ -1362,13 +1337,10 @@ double HighsDomain::adjustedUb(HighsInt col, HighsCDouble boundVal, double bound; if (mipsolver->variableType(col) != HighsVarType::kContinuous) { - bound = std::floor(double(boundVal + mipsolver->mipdata_->feastol)); - if (bound < col_upper_[col] && - col_upper_[col] - bound > - 1000.0 * mipsolver->mipdata_->feastol * std::fabs(bound)) - accept = true; - else - accept = false; + bound = static_cast(floor(boundVal + mipsolver->mipdata_->feastol)); + accept = bound < col_upper_[col] && + col_upper_[col] - bound > + 1000.0 * mipsolver->mipdata_->feastol * std::fabs(bound); } else { if (std::fabs(double(boundVal) - col_lower_[col]) <= mipsolver->mipdata_->epsilon) @@ -1397,13 +1369,10 @@ double HighsDomain::adjustedLb(HighsInt col, HighsCDouble boundVal, double bound; if (mipsolver->variableType(col) != HighsVarType::kContinuous) { - bound = std::ceil(double(boundVal - mipsolver->mipdata_->feastol)); - if (bound > col_lower_[col] && - bound - col_lower_[col] > - 1000.0 * mipsolver->mipdata_->feastol * std::fabs(bound)) - accept = true; - else - accept = false; + bound = static_cast(ceil(boundVal - mipsolver->mipdata_->feastol)); + accept = bound > col_lower_[col] && + bound - col_lower_[col] > + 1000.0 * mipsolver->mipdata_->feastol * std::fabs(bound); } else { if (std::fabs(col_upper_[col] - double(boundVal)) <= mipsolver->mipdata_->epsilon) @@ -1517,14 +1486,10 @@ HighsInt HighsDomain::propagateRowLower(const HighsInt* Rindex, void HighsDomain::updateThresholdLbChange(HighsInt col, double newbound, double val, double& threshold) { if (newbound != col_upper_[col]) { - double boundRange = (col_upper_[col] - newbound); - - boundRange -= - variableType(col) == HighsVarType::kContinuous - ? std::max(0.3 * boundRange, 1000.0 * mipsolver->mipdata_->feastol) - : mipsolver->mipdata_->feastol; - - double thresholdNew = std::fabs(val) * boundRange; + double thresholdNew = + std::fabs(val) * boundRange(col_upper_[col], newbound, + mipsolver->mipdata_->feastol, + variableType(col)); // the new threshold is now the maximum of the new threshold and the current // one @@ -1536,14 +1501,10 @@ void HighsDomain::updateThresholdLbChange(HighsInt col, double newbound, void HighsDomain::updateThresholdUbChange(HighsInt col, double newbound, double val, double& threshold) { if (newbound != col_lower_[col]) { - double boundRange = (newbound - col_lower_[col]); - - boundRange -= - variableType(col) == HighsVarType::kContinuous - ? std::max(0.3 * boundRange, 1000.0 * mipsolver->mipdata_->feastol) - : mipsolver->mipdata_->feastol; - - double thresholdNew = std::fabs(val) * boundRange; + double thresholdNew = + std::fabs(val) * boundRange(newbound, col_lower_[col], + mipsolver->mipdata_->feastol, + variableType(col)); // the new threshold is now the maximum of the new threshold and the current // one @@ -1567,16 +1528,9 @@ void HighsDomain::updateActivityLbChange(HighsInt col, double oldbound, for (HighsInt i = start; i != end; ++i) { if (mip->a_matrix_.value_[i] > 0) { - double deltamin; - if (oldbound == -kHighsInf) { - --activitymininf_[mip->a_matrix_.index_[i]]; - deltamin = newbound * mip->a_matrix_.value_[i]; - } else if (newbound == -kHighsInf) { - ++activitymininf_[mip->a_matrix_.index_[i]]; - deltamin = -oldbound * mip->a_matrix_.value_[i]; - } else { - deltamin = (newbound - oldbound) * mip->a_matrix_.value_[i]; - } + double deltamin = + computeDelta(mip->a_matrix_.value_[i], oldbound, newbound, -kHighsInf, + activitymininf_[mip->a_matrix_.index_[i]]); activitymin_[mip->a_matrix_.index_[i]] += deltamin; #ifndef NDEBUG @@ -1618,16 +1572,9 @@ void HighsDomain::updateActivityLbChange(HighsInt col, double oldbound, mip->row_upper_[mip->a_matrix_.index_[i]] != kHighsInf) markPropagate(mip->a_matrix_.index_[i]); } else { - double deltamax; - if (oldbound == -kHighsInf) { - --activitymaxinf_[mip->a_matrix_.index_[i]]; - deltamax = newbound * mip->a_matrix_.value_[i]; - } else if (newbound == -kHighsInf) { - ++activitymaxinf_[mip->a_matrix_.index_[i]]; - deltamax = -oldbound * mip->a_matrix_.value_[i]; - } else { - deltamax = (newbound - oldbound) * mip->a_matrix_.value_[i]; - } + double deltamax = + computeDelta(mip->a_matrix_.value_[i], oldbound, newbound, -kHighsInf, + activitymaxinf_[mip->a_matrix_.index_[i]]); activitymax_[mip->a_matrix_.index_[i]] += deltamax; #ifndef NDEBUG @@ -1684,29 +1631,13 @@ void HighsDomain::updateActivityLbChange(HighsInt col, double oldbound, std::swap(oldbound, newbound); for (HighsInt i = start; i != end; ++i) { if (mip->a_matrix_.value_[i] > 0) { - double deltamin; - if (oldbound == -kHighsInf) { - --activitymininf_[mip->a_matrix_.index_[i]]; - deltamin = newbound * mip->a_matrix_.value_[i]; - } else if (newbound == -kHighsInf) { - ++activitymininf_[mip->a_matrix_.index_[i]]; - deltamin = -oldbound * mip->a_matrix_.value_[i]; - } else { - deltamin = (newbound - oldbound) * mip->a_matrix_.value_[i]; - } - activitymin_[mip->a_matrix_.index_[i]] += deltamin; + activitymin_[mip->a_matrix_.index_[i]] += + computeDelta(mip->a_matrix_.value_[i], oldbound, newbound, + -kHighsInf, activitymininf_[mip->a_matrix_.index_[i]]); } else { - double deltamax; - if (oldbound == -kHighsInf) { - --activitymaxinf_[mip->a_matrix_.index_[i]]; - deltamax = newbound * mip->a_matrix_.value_[i]; - } else if (newbound == -kHighsInf) { - ++activitymaxinf_[mip->a_matrix_.index_[i]]; - deltamax = -oldbound * mip->a_matrix_.value_[i]; - } else { - deltamax = (newbound - oldbound) * mip->a_matrix_.value_[i]; - } - activitymax_[mip->a_matrix_.index_[i]] += deltamax; + activitymax_[mip->a_matrix_.index_[i]] += + computeDelta(mip->a_matrix_.value_[i], oldbound, newbound, + -kHighsInf, activitymaxinf_[mip->a_matrix_.index_[i]]); } } @@ -1736,16 +1667,9 @@ void HighsDomain::updateActivityUbChange(HighsInt col, double oldbound, for (HighsInt i = start; i != end; ++i) { if (mip->a_matrix_.value_[i] > 0) { - double deltamax; - if (oldbound == kHighsInf) { - --activitymaxinf_[mip->a_matrix_.index_[i]]; - deltamax = newbound * mip->a_matrix_.value_[i]; - } else if (newbound == kHighsInf) { - ++activitymaxinf_[mip->a_matrix_.index_[i]]; - deltamax = -oldbound * mip->a_matrix_.value_[i]; - } else { - deltamax = (newbound - oldbound) * mip->a_matrix_.value_[i]; - } + double deltamax = + computeDelta(mip->a_matrix_.value_[i], oldbound, newbound, kHighsInf, + activitymaxinf_[mip->a_matrix_.index_[i]]); activitymax_[mip->a_matrix_.index_[i]] += deltamax; #ifndef NDEBUG @@ -1790,17 +1714,9 @@ void HighsDomain::updateActivityUbChange(HighsInt col, double oldbound, // propagateinds_.push_back(mip->a_matrix_.index_[i]); } } else { - double deltamin; - if (oldbound == kHighsInf) { - --activitymininf_[mip->a_matrix_.index_[i]]; - deltamin = newbound * mip->a_matrix_.value_[i]; - } else if (newbound == kHighsInf) { - ++activitymininf_[mip->a_matrix_.index_[i]]; - deltamin = -oldbound * mip->a_matrix_.value_[i]; - } else { - deltamin = (newbound - oldbound) * mip->a_matrix_.value_[i]; - } - + double deltamin = + computeDelta(mip->a_matrix_.value_[i], oldbound, newbound, kHighsInf, + activitymininf_[mip->a_matrix_.index_[i]]); activitymin_[mip->a_matrix_.index_[i]] += deltamin; #ifndef NDEBUG @@ -1860,30 +1776,13 @@ void HighsDomain::updateActivityUbChange(HighsInt col, double oldbound, std::swap(oldbound, newbound); for (HighsInt i = start; i != end; ++i) { if (mip->a_matrix_.value_[i] > 0) { - double deltamax; - if (oldbound == kHighsInf) { - --activitymaxinf_[mip->a_matrix_.index_[i]]; - deltamax = newbound * mip->a_matrix_.value_[i]; - } else if (newbound == kHighsInf) { - ++activitymaxinf_[mip->a_matrix_.index_[i]]; - deltamax = -oldbound * mip->a_matrix_.value_[i]; - } else { - deltamax = (newbound - oldbound) * mip->a_matrix_.value_[i]; - } - activitymax_[mip->a_matrix_.index_[i]] += deltamax; + activitymax_[mip->a_matrix_.index_[i]] += + computeDelta(mip->a_matrix_.value_[i], oldbound, newbound, + kHighsInf, activitymaxinf_[mip->a_matrix_.index_[i]]); } else { - double deltamin; - if (oldbound == kHighsInf) { - --activitymininf_[mip->a_matrix_.index_[i]]; - deltamin = newbound * mip->a_matrix_.value_[i]; - } else if (newbound == kHighsInf) { - ++activitymininf_[mip->a_matrix_.index_[i]]; - deltamin = -oldbound * mip->a_matrix_.value_[i]; - } else { - deltamin = (newbound - oldbound) * mip->a_matrix_.value_[i]; - } - - activitymin_[mip->a_matrix_.index_[i]] += deltamin; + activitymin_[mip->a_matrix_.index_[i]] += + computeDelta(mip->a_matrix_.value_[i], oldbound, newbound, + kHighsInf, activitymininf_[mip->a_matrix_.index_[i]]); } } @@ -1908,13 +1807,9 @@ void HighsDomain::recomputeCapacityThreshold(HighsInt row) { if (col_upper_[col] == col_lower_[col]) continue; - double boundRange = col_upper_[col] - col_lower_[col]; - - boundRange -= variableType(col) == HighsVarType::kContinuous - ? std::max(0.3 * boundRange, 1000.0 * feastol()) - : feastol(); - - double threshold = std::fabs(mipsolver->mipdata_->ARvalue_[i]) * boundRange; + double threshold = std::fabs(mipsolver->mipdata_->ARvalue_[i]) * + boundRange(col_upper_[col], col_lower_[col], feastol(), + variableType(col)); capacityThreshold_[row] = std::max({capacityThreshold_[row], threshold, feastol()}); @@ -2180,13 +2075,13 @@ void HighsDomain::setDomainChangeStack( if (k == stacksize) return; // For redundant branching bound changes we need to be more careful due to - // symmetry handling. If these boundchanges are redundant simply because the - // corresponding subtree was enumerated and hence the global bound updated, - // then we still need to keep their status as branching variables for - // computing correct stabilizers. - // They can, however, be safely dropped if they are either strictly - // redundant in the global domain, or if there is already a local bound - // change that makes the branching change redundant. + // symmetry handling. If these bound changes are redundant simply because + // the corresponding subtree was enumerated and hence the global bound + // updated, then we still need to keep their status as branching variables + // for computing correct stabilizers. They can, however, be safely dropped + // if they are either strictly redundant in the global domain, or if there + // is already a local bound change that makes the branching change + // redundant. if (domchgstack[k].boundtype == HighsBoundType::kLower) { if (domchgstack[k].boundval <= col_lower_[domchgstack[k].column]) { if (domchgstack[k].boundval < col_lower_[domchgstack[k].column]) @@ -3037,6 +2932,7 @@ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper, relaxUb = std::floor(relaxUb); if (relaxUb - ub <= localdom.feastol()) continue; + locdomchg.domchg.boundval = relaxUb; if (relaxUb - gub >= -localdom.mipsolver->mipdata_->epsilon) { diff --git a/src/mip/HighsDomain.h b/src/mip/HighsDomain.h index fb09c99164..57ff4fe45c 100644 --- a/src/mip/HighsDomain.h +++ b/src/mip/HighsDomain.h @@ -358,6 +358,7 @@ class HighsDomain { conflictPoolPropagation(other.conflictPoolPropagation), infeasible_(other.infeasible_), infeasible_reason(other.infeasible_reason), + infeasible_pos(other.infeasible_pos), colLowerPos_(other.colLowerPos_), colUpperPos_(other.colUpperPos_), branchPos_(other.branchPos_), diff --git a/src/mip/HighsGFkSolve.h b/src/mip/HighsGFkSolve.h index 7cfd5a52e2..75519459de 100644 --- a/src/mip/HighsGFkSolve.h +++ b/src/mip/HighsGFkSolve.h @@ -39,7 +39,7 @@ struct HighsGFk; template <> struct HighsGFk<2> { static constexpr unsigned int powk(unsigned int a) { return a * a; } - static constexpr unsigned int inverse(unsigned int a) { return 1; } + static constexpr unsigned int inverse(unsigned int) { return 1; } }; template <> diff --git a/src/mip/HighsMipSolverData.cpp b/src/mip/HighsMipSolverData.cpp index 4070dfb021..1d926134ab 100644 --- a/src/mip/HighsMipSolverData.cpp +++ b/src/mip/HighsMipSolverData.cpp @@ -183,17 +183,17 @@ void HighsMipSolverData::finishSymmetryDetection( "No symmetry present\n\n"); } else if (symmetries.orbitopes.size() == 0) { highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo, - "Found %" HIGHSINT_FORMAT " generators\n\n", + "Found %" HIGHSINT_FORMAT " generator(s)\n\n", symmetries.numGenerators); } else { if (symmetries.numPerms != 0) { - highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo, - "Found %" HIGHSINT_FORMAT " generators and %" HIGHSINT_FORMAT - " full orbitope(s) acting on %" HIGHSINT_FORMAT - " columns\n\n", - symmetries.numPerms, (HighsInt)symmetries.orbitopes.size(), - (HighsInt)symmetries.columnToOrbitope.size()); + highsLogUser( + mipsolver.options_mip_->log_options, HighsLogType::kInfo, + "Found %" HIGHSINT_FORMAT " generator(s) and %" HIGHSINT_FORMAT + " full orbitope(s) acting on %" HIGHSINT_FORMAT " columns\n\n", + symmetries.numPerms, (HighsInt)symmetries.orbitopes.size(), + (HighsInt)symmetries.columnToOrbitope.size()); } else { highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo, "Found %" HIGHSINT_FORMAT diff --git a/src/mip/HighsMipSolverData.h b/src/mip/HighsMipSolverData.h index 07a17e23f6..cbf697fcfc 100644 --- a/src/mip/HighsMipSolverData.h +++ b/src/mip/HighsMipSolverData.h @@ -128,6 +128,46 @@ struct HighsMipSolverData { implications(mipsolver), heuristics(mipsolver), objectiveFunction(mipsolver), + presolve_status(HighsPresolveStatus::kNotSet), + cliquesExtracted(false), + rowMatrixSet(false), + analyticCenterComputed(false), + analyticCenterStatus(HighsModelStatus::kNotset), + detectSymmetries(false), + numRestarts(0), + numRestartsRoot(0), + numCliqueEntriesAfterPresolve(0), + numCliqueEntriesAfterFirstPresolve(0), + feastol(0.0), + epsilon(0.0), + heuristic_effort(0.0), + dispfreq(0), + firstlpsolobj(-kHighsInf), + rootlpsolobj(-kHighsInf), + numintegercols(0), + maxTreeSizeLog2(0), + pruned_treeweight(0), + avgrootlpiters(0.0), + last_disptime(0.0), + firstrootlpiters(0), + num_nodes(0), + num_leaves(0), + num_leaves_before_run(0), + num_nodes_before_run(0), + total_lp_iterations(0), + heuristic_lp_iterations(0), + sepa_lp_iterations(0), + sb_lp_iterations(0), + total_lp_iterations_before_run(0), + heuristic_lp_iterations_before_run(0), + sepa_lp_iterations_before_run(0), + sb_lp_iterations_before_run(0), + num_disp_lines(0), + numImprovingSols(0), + lower_bound(-kHighsInf), + upper_bound(kHighsInf), + upper_limit(kHighsInf), + optimality_limit(kHighsInf), debugSolution(mipsolver) { domain.addCutpool(cutpool); domain.addConflictPool(conflictPool); diff --git a/src/mip/HighsModkSeparator.h b/src/mip/HighsModkSeparator.h index e7c2c9005f..8e6eb88bac 100644 --- a/src/mip/HighsModkSeparator.h +++ b/src/mip/HighsModkSeparator.h @@ -20,7 +20,7 @@ * cut. * * If a row contains continuous variables that sit at zero after bound - * substitution, then those rows are included in the congurence system, as the + * substitution, then those rows are included in the congruence system, as the * presence of such variables does not reduce the cuts violation when applying * the MIR procedure. In order to handle their presence the row must simply be * scaled, such that all integer variables that have a non-zero solution value diff --git a/src/mip/HighsSearch.h b/src/mip/HighsSearch.h index ccea0a26ef..c9c665e21a 100644 --- a/src/mip/HighsSearch.h +++ b/src/mip/HighsSearch.h @@ -96,6 +96,7 @@ class HighsSearch { std::shared_ptr stabilizerOrbits = nullptr) : lower_bound(parentlb), estimate(parentestimate), + branching_point(0.0), lp_objective(-kHighsInf), other_child_lb(parentlb), nodeBasis(std::move(parentBasis)), diff --git a/src/parallel/HighsMutex.h b/src/parallel/HighsMutex.h index cd39788ace..34d8b95541 100644 --- a/src/parallel/HighsMutex.h +++ b/src/parallel/HighsMutex.h @@ -114,7 +114,8 @@ class HighsMutex { } void unlock() { - unsigned int prevState = state.fetch_add(-1, std::memory_order_release); + unsigned int prevState = state.fetch_add( + std::numeric_limits::max(), std::memory_order_release); if (prevState != 1) { unsigned int notifyWorkerId = (prevState >> 1) - 1; diff --git a/src/pdlp/cupdlp/cupdlp_defs.h b/src/pdlp/cupdlp/cupdlp_defs.h index bdc4257a73..068c150935 100644 --- a/src/pdlp/cupdlp/cupdlp_defs.h +++ b/src/pdlp/cupdlp/cupdlp_defs.h @@ -154,7 +154,7 @@ struct CUPDLP_CSC_MATRIX { cupdlp_int *colMatIdx; cupdlp_float *colMatElem; - // Used to aviod implementing NormInf on cuda + // Used to avoid implementing NormInf on cuda cupdlp_float MatElemNormInf; #ifndef CUPDLP_CPU // Pointers to GPU vectors diff --git a/src/presolve/HPresolve.cpp b/src/presolve/HPresolve.cpp index b25b87af00..f2d549e865 100644 --- a/src/presolve/HPresolve.cpp +++ b/src/presolve/HPresolve.cpp @@ -1456,77 +1456,75 @@ HPresolve::Result HPresolve::runProbing(HighsPostsolveStack& postsolve_stack) { for (const auto& binvar : binaries) { HighsInt i = std::get<3>(binvar); - if (cliquetable.getSubstitution(i) != nullptr) continue; - - if (domain.isBinary(i)) { - // when a large percentage of columns have been deleted, stop this round - // of probing - // if (numDel > std::max(model->num_col_ * 0.2, 1000.)) break; - if (numDel > - std::max(1000., (model->num_row_ + model->num_col_) * 0.05)) { - probingEarlyAbort = true; - break; - } + if (cliquetable.getSubstitution(i) != nullptr || !domain.isBinary(i)) + continue; - // break in case of too many new implications to not spent ages in - // probing - if (cliquetable.isFull() || - cliquetable.numCliques() - numCliquesStart > - std::max(HighsInt{1000000}, 2 * numNonzeros()) || - implications.getNumImplications() - numImplicsStart > - std::max(HighsInt{1000000}, 2 * numNonzeros())) - break; + // when a large percentage of columns have been deleted, stop this round + // of probing + // if (numDel > std::max(model->num_col_ * 0.2, 1000.)) break; + probingEarlyAbort = + numDel > + std::max(HighsInt{1000}, (model->num_row_ + model->num_col_) / 20); + if (probingEarlyAbort) break; + + // break in case of too many new implications to not spent ages in + // probing + if (cliquetable.isFull() || + cliquetable.numCliques() - numCliquesStart > + std::max(HighsInt{1000000}, 2 * numNonzeros()) || + implications.getNumImplications() - numImplicsStart > + std::max(HighsInt{1000000}, 2 * numNonzeros())) + break; - // if (numProbed % 10 == 0) - // printf( - // "numprobed=%d numDel=%d newcliques=%d " - // "numNeighbourhoodQueries=%ld " - // "splayContingent=%ld\n", - // numProbed, numDel, cliquetable.numCliques() - numCliquesStart, - // cliquetable.numNeighbourhoodQueries, splayContingent); - if (cliquetable.numNeighbourhoodQueries > splayContingent) break; - - if (probingContingent - numProbed < 0) break; - - HighsInt numBoundChgs = 0; - HighsInt numNewCliques = -cliquetable.numCliques(); - if (!implications.runProbing(i, numBoundChgs)) continue; - probingContingent += numBoundChgs; - numNewCliques += cliquetable.numCliques(); - numNewCliques = std::max(numNewCliques, HighsInt{0}); - while (domain.getChangedCols().size() != numChangedCols) { - if (domain.isFixed(domain.getChangedCols()[numChangedCols++])) - ++probingNumDelCol; - } - HighsInt newNumDel = probingNumDelCol - numDelStart + - implications.substitutions.size() + - cliquetable.getSubstitutions().size(); - - if (newNumDel > numDel) { - probingContingent += numDel; - if (!mipsolver->submip) { - splayContingent += 100 * (newNumDel + numDelStart); - splayContingent += 1000 * numNewCliques; - } - numDel = newNumDel; - numFail = 0; - } else if (mipsolver->submip || numNewCliques == 0) { - splayContingent -= 100 * numFail; - ++numFail; - } else { + // if (numProbed % 10 == 0) + // printf( + // "numprobed=%d numDel=%d newcliques=%d " + // "numNeighbourhoodQueries=%ld " + // "splayContingent=%ld\n", + // numProbed, numDel, cliquetable.numCliques() - numCliquesStart, + // cliquetable.numNeighbourhoodQueries, splayContingent); + if (cliquetable.numNeighbourhoodQueries > splayContingent) break; + + if (probingContingent - numProbed < 0) break; + + HighsInt numBoundChgs = 0; + HighsInt numNewCliques = -cliquetable.numCliques(); + if (!implications.runProbing(i, numBoundChgs)) continue; + probingContingent += numBoundChgs; + numNewCliques += cliquetable.numCliques(); + numNewCliques = std::max(numNewCliques, HighsInt{0}); + while (domain.getChangedCols().size() != numChangedCols) { + if (domain.isFixed(domain.getChangedCols()[numChangedCols++])) + ++probingNumDelCol; + } + HighsInt newNumDel = probingNumDelCol - numDelStart + + implications.substitutions.size() + + cliquetable.getSubstitutions().size(); + + if (newNumDel > numDel) { + probingContingent += numDel; + if (!mipsolver->submip) { + splayContingent += 100 * (newNumDel + numDelStart); splayContingent += 1000 * numNewCliques; - numFail = 0; } + numDel = newNumDel; + numFail = 0; + } else if (mipsolver->submip || numNewCliques == 0) { + splayContingent -= 100 * numFail; + ++numFail; + } else { + splayContingent += 1000 * numNewCliques; + numFail = 0; + } - ++numProbed; - numProbes[i] += 1; + ++numProbed; + numProbes[i] += 1; - // printf("nprobed: %" HIGHSINT_FORMAT ", numCliques: %" HIGHSINT_FORMAT - // "\n", nprobed, - // cliquetable.numCliques()); - if (domain.infeasible()) { - return Result::kPrimalInfeasible; - } + // printf("nprobed: %" HIGHSINT_FORMAT ", numCliques: %" HIGHSINT_FORMAT + // "\n", nprobed, + // cliquetable.numCliques()); + if (domain.infeasible()) { + return Result::kPrimalInfeasible; } } @@ -5195,8 +5193,7 @@ HighsInt HPresolve::strengthenInequalities() { // do not run on very dense rows as this could get expensive if (rowsize[row] > - std::max(HighsInt{1000}, - HighsInt(0.05 * (model->num_col_ - numDeletedCols)))) + std::max(HighsInt{1000}, (model->num_col_ - numDeletedCols) / 20)) continue; // printf("strengthening knapsack of %" HIGHSINT_FORMAT " vars\n", diff --git a/src/presolve/ICrash.h b/src/presolve/ICrash.h index 9484b61535..dfe3d40bc7 100644 --- a/src/presolve/ICrash.h +++ b/src/presolve/ICrash.h @@ -85,7 +85,13 @@ struct Quadratic { double mu; std::vector lambda; - Quadratic(HighsLp lp_, ICrashOptions options_) : lp(lp_), options(options_) {} + Quadratic(HighsLp lp_, ICrashOptions options_) + : lp(lp_), + options(options_), + lp_objective(0.0), + quadratic_objective(0.0), + residual_norm_2(0.0), + mu(0.0) {} }; // Functions: Call. diff --git a/src/qpsolver/a_quass.cpp b/src/qpsolver/a_quass.cpp index a2fda85ff5..b62d22ebc9 100644 --- a/src/qpsolver/a_quass.cpp +++ b/src/qpsolver/a_quass.cpp @@ -4,7 +4,7 @@ #include "qpsolver/feasibility_highs.hpp" #include "qpsolver/feasibility_bounded.hpp" -QpAsmStatus quass2highs(Instance& instance, +static QpAsmStatus quass2highs(Instance& instance, Settings& settings, Statistics& stats, QpModelStatus& qp_model_status, @@ -157,7 +157,7 @@ QpAsmStatus solveqp(Instance& instance, } // solve - QpAsmStatus status = solveqp_actual(instance, settings, startinfo, stats, qp_model_status, qp_solution, qp_timer); + solveqp_actual(instance, settings, startinfo, stats, qp_model_status, qp_solution, qp_timer); // undo perturbation and resolve diff --git a/src/qpsolver/feasibility_bounded.hpp b/src/qpsolver/feasibility_bounded.hpp index e2c345f181..4a92c813e1 100644 --- a/src/qpsolver/feasibility_bounded.hpp +++ b/src/qpsolver/feasibility_bounded.hpp @@ -18,8 +18,8 @@ static void computeStartingPointBounded(Instance& instance, L.resize(instance.num_var * instance.num_var); // compute cholesky factorization of Q - for (size_t col = 0; col < instance.num_var; col++) { - for (size_t idx = instance.Q.mat.start[col]; idx < instance.Q.mat.start[col+1]; idx++) { + for (size_t col = 0; col < (size_t)instance.num_var; col++) { + for (size_t idx = instance.Q.mat.start[col]; idx < (size_t)instance.Q.mat.start[col+1]; idx++) { double sum = 0; size_t row = instance.Q.mat.index[idx]; if (row == col) { diff --git a/src/qpsolver/quass.cpp b/src/qpsolver/quass.cpp index cbff174e58..2b0f825e69 100644 --- a/src/qpsolver/quass.cpp +++ b/src/qpsolver/quass.cpp @@ -266,12 +266,12 @@ static double compute_dual_violation(Instance& instance, QpVector& primal, QpVec } #endif -bool check_reinvert_due(Basis& basis) { +static bool check_reinvert_due(Basis& basis) { // reinvert can be triggered by basis return basis.getreinversionhint(); } -void reinvert(Basis& basis, CholeskyFactor& factor, Gradient& grad, ReducedCosts& rc, ReducedGradient& rg, std::unique_ptr& pricing) { +static void reinvert(Basis& basis, CholeskyFactor& factor, Gradient& grad, ReducedCosts& rc, ReducedGradient& rg, std::unique_ptr& pricing) { basis.rebuild(); factor.recompute(); grad.recompute(); diff --git a/src/qpsolver/runtime.hpp b/src/qpsolver/runtime.hpp index 4630f8fdff..5c9c199a9a 100644 --- a/src/qpsolver/runtime.hpp +++ b/src/qpsolver/runtime.hpp @@ -26,13 +26,13 @@ struct Runtime { Runtime(Instance& inst, Statistics& stats) : instance(inst), + statistics(stats), primal(QpVector(instance.num_var)), rowactivity(QpVector(instance.num_con)), dualvar(instance.num_var), dualcon(instance.num_con), status_var(instance.num_var), - status_con(instance.num_con), - statistics(stats) {} + status_con(instance.num_con) {} }; #endif diff --git a/src/qpsolver/steepestedgepricing.hpp b/src/qpsolver/steepestedgepricing.hpp index 0002bd6e13..0a216394ee 100644 --- a/src/qpsolver/steepestedgepricing.hpp +++ b/src/qpsolver/steepestedgepricing.hpp @@ -91,7 +91,6 @@ class SteepestEdgePricing : public Pricing { std::vector correct_weights; std::vector incorrect_weights; - bool ret = true; for (int i=0; i bad_basis_change_; diff --git a/src/simplex/HEkkDual.cpp b/src/simplex/HEkkDual.cpp index 30d42a96a2..6a6ca9d13e 100644 --- a/src/simplex/HEkkDual.cpp +++ b/src/simplex/HEkkDual.cpp @@ -1063,7 +1063,7 @@ void HEkkDual::rebuild() { // Note that computePrimalObjectiveValue sets // has_primal_objective_value const bool check_updated_objective_value = status.has_dual_objective_value; - double previous_dual_objective_value; + double previous_dual_objective_value = -kHighsInf; if (check_updated_objective_value) { // debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase, // "Before computeDual"); diff --git a/src/simplex/HEkkDualRow.cpp b/src/simplex/HEkkDualRow.cpp index 8bb177fa96..6f0e00bc6c 100644 --- a/src/simplex/HEkkDualRow.cpp +++ b/src/simplex/HEkkDualRow.cpp @@ -186,7 +186,7 @@ HighsInt HEkkDualRow::chooseFinal() { alt_workCount = workCount; } analysis->simplexTimerStart(Chuzc4Clock); - bool choose_ok; + bool choose_ok = false; if (use_quad_sort) { // Use the O(n^2) quadratic sort for the candidates analysis->simplexTimerStart(Chuzc4a0Clock); @@ -212,10 +212,10 @@ HighsInt HEkkDualRow::chooseFinal() { // 3. Choose large alpha analysis->simplexTimerStart(Chuzc4bClock); - HighsInt breakIndex; - HighsInt breakGroup; - HighsInt alt_breakIndex; - HighsInt alt_breakGroup; + HighsInt breakIndex = -1; + HighsInt breakGroup = -1; + HighsInt alt_breakIndex = -1; + HighsInt alt_breakGroup = -1; if (use_quad_sort) chooseFinalLargeAlpha(breakIndex, breakGroup, workCount, workData, workGroup); diff --git a/src/simplex/HEkkPrimal.cpp b/src/simplex/HEkkPrimal.cpp index 8c9787cee4..9a258ad90e 100644 --- a/src/simplex/HEkkPrimal.cpp +++ b/src/simplex/HEkkPrimal.cpp @@ -697,7 +697,7 @@ void HEkkPrimal::rebuild() { // basic variables, and baseValue only corresponds to the new // ordering once computePrimal has been called const bool check_updated_objective_value = status.has_primal_objective_value; - double previous_primal_objective_value; + double previous_primal_objective_value = -kHighsInf; if (check_updated_objective_value) { // debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase, // "Before INVERT"); diff --git a/src/simplex/HighsSimplexAnalysis.h b/src/simplex/HighsSimplexAnalysis.h index 20d1e14e2d..b12dd1c134 100644 --- a/src/simplex/HighsSimplexAnalysis.h +++ b/src/simplex/HighsSimplexAnalysis.h @@ -58,7 +58,135 @@ const HighsLogType kIterationReportLogType = HighsLogType::kVerbose; */ class HighsSimplexAnalysis { public: - HighsSimplexAnalysis() {} + HighsSimplexAnalysis() + : timer_(nullptr), + pointer_serial_factor_clocks(nullptr), + numRow(0), + numCol(0), + numTot(0), + model_name_(""), + lp_name_(""), + analyse_lp_data(false), + analyse_simplex_summary_data(false), + analyse_simplex_runtime_data(false), + analyse_simplex_time(false), + analyse_factor_data(false), + analyse_factor_time(false), + analyse_simplex_data(false), + simplex_strategy(0), + edge_weight_mode(EdgeWeightMode::kSteepestEdge), + solve_phase(0), + simplex_iteration_count(0), + devex_iteration_count(0), + pivotal_row_index(0), + leaving_variable(0), + entering_variable(0), + rebuild_reason(0), + rebuild_reason_string(""), + reduced_rhs_value(0.0), + reduced_cost_value(0.0), + edge_weight(0.0), + edge_weight_error(0.0), + primal_delta(0.0), + primal_step(0.0), + dual_step(0.0), + pivot_value_from_column(0.0), + pivot_value_from_row(0.0), + factor_pivot_threshold(0.0), + numerical_trouble(0.0), + objective_value(0.0), + num_primal_infeasibility(0), + num_dual_infeasibility(0), + sum_primal_infeasibility(0.0), + sum_dual_infeasibility(0.0), + num_dual_phase_1_lp_dual_infeasibility(0), + max_dual_phase_1_lp_dual_infeasibility(0.0), + sum_dual_phase_1_lp_dual_infeasibility(0.0), + num_devex_framework(0), + col_aq_density(0.0), + row_ep_density(0.0), + row_ap_density(0.0), + row_DSE_density(0.0), + col_steepest_edge_density(0.0), + col_basic_feasibility_change_density(0.0), + row_basic_feasibility_change_density(0.0), + col_BFRT_density(0.0), + primal_col_density(0.0), + dual_col_density(0.0), + num_costly_DSE_iteration(0), + costly_DSE_measure(0.0), + multi_iteration_count(0), + multi_chosen(0), + multi_finished(0), + min_concurrency(0), + num_concurrency(0), + max_concurrency(0), + num_col_price(0), + num_row_price(0), + num_row_price_with_switch(0), + num_primal_cycling_detections(0), + num_dual_cycling_detections(0), + num_quad_chuzc(0), + num_heap_chuzc(0), + sum_quad_chuzc_size(0.0), + sum_heap_chuzc_size(0.0), + max_quad_chuzc_size(0), + max_heap_chuzc_size(0), + num_improve_choose_column_row_call(0), + num_remove_pivot_from_pack(0), + num_correct_dual_primal_flip(0), + min_correct_dual_primal_flip_dual_infeasibility(kHighsInf), + max_correct_dual_primal_flip(0.0), + num_correct_dual_cost_shift(0), + max_correct_dual_cost_shift_dual_infeasibility(0.0), + max_correct_dual_cost_shift(0.0), + net_num_single_cost_shift(0), + num_single_cost_shift(0), + max_single_cost_shift(0.0), + sum_single_cost_shift(0.0), + num_dual_steepest_edge_weight_check(0), + num_dual_steepest_edge_weight_reject(0), + num_wrong_low_dual_steepest_edge_weight(0), + num_wrong_high_dual_steepest_edge_weight(0), + average_frequency_low_dual_steepest_edge_weight(0.0), + average_frequency_high_dual_steepest_edge_weight(0.0), + average_log_low_dual_steepest_edge_weight_error(0.0), + average_log_high_dual_steepest_edge_weight_error(0.0), + max_average_frequency_low_dual_steepest_edge_weight(0.0), + max_average_frequency_high_dual_steepest_edge_weight(0.0), + max_sum_average_frequency_extreme_dual_steepest_edge_weight(0.0), + max_average_log_low_dual_steepest_edge_weight_error(0.0), + max_average_log_high_dual_steepest_edge_weight_error(0.0), + max_sum_average_log_extreme_dual_steepest_edge_weight_error(0.0), + num_invert_report_since_last_header(-1), + num_iteration_report_since_last_header(-1), + last_user_log_time(-kHighsInf), + delta_user_log_time(1e0), + average_concurrency(0.0), + average_fraction_of_possible_minor_iterations_performed(0.0), + sum_multi_chosen(0), + sum_multi_finished(0), + num_invert(0), + num_kernel(0), + num_major_kernel(0), + max_kernel_dim(0.0), + sum_kernel_dim(0.0), + running_average_kernel_dim(0.0), + sum_invert_fill_factor(0.0), + sum_kernel_fill_factor(0.0), + sum_major_kernel_fill_factor(0.0), + running_average_invert_fill_factor(1.0), + running_average_kernel_fill_factor(1.0), + running_average_major_kernel_fill_factor(1.0), + AnIterIt0(0), + AnIterPrevIt(0), + AnIterOp{}, + AnIterTraceNumRec(0), + AnIterTraceIterDl(0), + AnIterTrace{}, + AnIterNumInvert{}, + AnIterNumEdWtIt{} {} + // Pointer to timer HighsTimer* timer_; @@ -162,38 +290,38 @@ class HighsSimplexAnalysis { // double dual_steepest_edge_weight_log_error_threshold; // Local copies of simplex data for reporting - HighsInt simplex_strategy = 0; - EdgeWeightMode edge_weight_mode = EdgeWeightMode::kSteepestEdge; - HighsInt solve_phase = 0; - HighsInt simplex_iteration_count = 0; - HighsInt devex_iteration_count = 0; - HighsInt pivotal_row_index = 0; - HighsInt leaving_variable = 0; - HighsInt entering_variable = 0; - HighsInt rebuild_reason = 0; - std::string rebuild_reason_string = ""; - double reduced_rhs_value = 0; - double reduced_cost_value = 0; - double edge_weight = 0; - double edge_weight_error = 0; - double primal_delta = 0; - double primal_step = 0; - double dual_step = 0; - double pivot_value_from_column = 0; - double pivot_value_from_row = 0; - double factor_pivot_threshold = 0; - double numerical_trouble = 0; - double objective_value = 0; - HighsInt num_primal_infeasibility = 0; - HighsInt num_dual_infeasibility = 0; - double sum_primal_infeasibility = 0; - double sum_dual_infeasibility = 0; + HighsInt simplex_strategy; + EdgeWeightMode edge_weight_mode; + HighsInt solve_phase; + HighsInt simplex_iteration_count; + HighsInt devex_iteration_count; + HighsInt pivotal_row_index; + HighsInt leaving_variable; + HighsInt entering_variable; + HighsInt rebuild_reason; + std::string rebuild_reason_string; + double reduced_rhs_value; + double reduced_cost_value; + double edge_weight; + double edge_weight_error; + double primal_delta; + double primal_step; + double dual_step; + double pivot_value_from_column; + double pivot_value_from_row; + double factor_pivot_threshold; + double numerical_trouble; + double objective_value; + HighsInt num_primal_infeasibility; + HighsInt num_dual_infeasibility; + double sum_primal_infeasibility; + double sum_dual_infeasibility; // This triple is an original infeasibility record, so it includes max, // but it's only used for reporting - HighsInt num_dual_phase_1_lp_dual_infeasibility = 0; - double max_dual_phase_1_lp_dual_infeasibility = 0; - double sum_dual_phase_1_lp_dual_infeasibility = 0; - HighsInt num_devex_framework = 0; + HighsInt num_dual_phase_1_lp_dual_infeasibility; + double max_dual_phase_1_lp_dual_infeasibility; + double sum_dual_phase_1_lp_dual_infeasibility; + HighsInt num_devex_framework; double col_aq_density; double row_ep_density; double row_ap_density; @@ -208,21 +336,21 @@ class HighsSimplexAnalysis { double costly_DSE_measure; // Local copies of parallel simplex data for reporting - HighsInt multi_iteration_count = 0; - HighsInt multi_chosen = 0; - HighsInt multi_finished = 0; - HighsInt min_concurrency = 0; - HighsInt num_concurrency = 0; - HighsInt max_concurrency = 0; + HighsInt multi_iteration_count; + HighsInt multi_chosen; + HighsInt multi_finished; + HighsInt min_concurrency; + HighsInt num_concurrency; + HighsInt max_concurrency; // Unused // HighsInt multi_num = 0; // Useless // double basis_condition = 0; // Maybe useful // Records of how pivotal row PRICE was done - HighsInt num_col_price = 0; - HighsInt num_row_price = 0; - HighsInt num_row_price_with_switch = 0; + HighsInt num_col_price; + HighsInt num_row_price; + HighsInt num_row_price_with_switch; HighsValueDistribution before_ftran_upper_sparse_density; HighsValueDistribution ftran_upper_sparse_density; @@ -235,29 +363,29 @@ class HighsSimplexAnalysis { HighsValueDistribution cleanup_dual_step_distribution; HighsValueDistribution cleanup_primal_change_distribution; - HighsInt num_primal_cycling_detections = 0; - HighsInt num_dual_cycling_detections = 0; - - HighsInt num_quad_chuzc = 0; - HighsInt num_heap_chuzc = 0; - double sum_quad_chuzc_size = 0; - double sum_heap_chuzc_size = 0; - HighsInt max_quad_chuzc_size = 0; - HighsInt max_heap_chuzc_size = 0; - - HighsInt num_improve_choose_column_row_call = 0; - HighsInt num_remove_pivot_from_pack = 0; - - HighsInt num_correct_dual_primal_flip = 0; - double min_correct_dual_primal_flip_dual_infeasibility = kHighsInf; - double max_correct_dual_primal_flip = 0; - HighsInt num_correct_dual_cost_shift = 0; - double max_correct_dual_cost_shift_dual_infeasibility = 0; - double max_correct_dual_cost_shift = 0; - HighsInt net_num_single_cost_shift = 0; - HighsInt num_single_cost_shift = 0; - double max_single_cost_shift = 0; - double sum_single_cost_shift = 0; + HighsInt num_primal_cycling_detections; + HighsInt num_dual_cycling_detections; + + HighsInt num_quad_chuzc; + HighsInt num_heap_chuzc; + double sum_quad_chuzc_size; + double sum_heap_chuzc_size; + HighsInt max_quad_chuzc_size; + HighsInt max_heap_chuzc_size; + + HighsInt num_improve_choose_column_row_call; + HighsInt num_remove_pivot_from_pack; + + HighsInt num_correct_dual_primal_flip; + double min_correct_dual_primal_flip_dual_infeasibility; + double max_correct_dual_primal_flip; + HighsInt num_correct_dual_cost_shift; + double max_correct_dual_cost_shift_dual_infeasibility; + double max_correct_dual_cost_shift; + HighsInt net_num_single_cost_shift; + HighsInt num_single_cost_shift; + double max_single_cost_shift; + double sum_single_cost_shift; // Tolerances for analysis of TRAN stages - could be needed for // control if this is ever used again! @@ -290,46 +418,46 @@ class HighsSimplexAnalysis { // double AnIterCostlyDseFq; //!< Frequency of iterations when DSE is costly // double AnIterCostlyDseMeasure; - HighsInt num_dual_steepest_edge_weight_check = 0; - HighsInt num_dual_steepest_edge_weight_reject = 0; - HighsInt num_wrong_low_dual_steepest_edge_weight = 0; - HighsInt num_wrong_high_dual_steepest_edge_weight = 0; - double average_frequency_low_dual_steepest_edge_weight = 0; - double average_frequency_high_dual_steepest_edge_weight = 0; - double average_log_low_dual_steepest_edge_weight_error = 0; - double average_log_high_dual_steepest_edge_weight_error = 0; - double max_average_frequency_low_dual_steepest_edge_weight = 0; - double max_average_frequency_high_dual_steepest_edge_weight = 0; - double max_sum_average_frequency_extreme_dual_steepest_edge_weight = 0; - double max_average_log_low_dual_steepest_edge_weight_error = 0; - double max_average_log_high_dual_steepest_edge_weight_error = 0; - double max_sum_average_log_extreme_dual_steepest_edge_weight_error = 0; - - HighsInt num_invert_report_since_last_header = -1; - HighsInt num_iteration_report_since_last_header = -1; - double last_user_log_time = -kHighsInf; - double delta_user_log_time = 1e0; + HighsInt num_dual_steepest_edge_weight_check; + HighsInt num_dual_steepest_edge_weight_reject; + HighsInt num_wrong_low_dual_steepest_edge_weight; + HighsInt num_wrong_high_dual_steepest_edge_weight; + double average_frequency_low_dual_steepest_edge_weight; + double average_frequency_high_dual_steepest_edge_weight; + double average_log_low_dual_steepest_edge_weight_error; + double average_log_high_dual_steepest_edge_weight_error; + double max_average_frequency_low_dual_steepest_edge_weight; + double max_average_frequency_high_dual_steepest_edge_weight; + double max_sum_average_frequency_extreme_dual_steepest_edge_weight; + double max_average_log_low_dual_steepest_edge_weight_error; + double max_average_log_high_dual_steepest_edge_weight_error; + double max_sum_average_log_extreme_dual_steepest_edge_weight_error; + + HighsInt num_invert_report_since_last_header; + HighsInt num_iteration_report_since_last_header; + double last_user_log_time; + double delta_user_log_time; double average_concurrency; double average_fraction_of_possible_minor_iterations_performed; - HighsInt sum_multi_chosen = 0; - HighsInt sum_multi_finished = 0; + HighsInt sum_multi_chosen; + HighsInt sum_multi_finished; // Analysis of INVERT form - HighsInt num_invert = 0; - HighsInt num_kernel = 0; - HighsInt num_major_kernel = 0; - double max_kernel_dim = 0; - double sum_kernel_dim = 0; - double running_average_kernel_dim = 0; - double sum_invert_fill_factor = 0; - double sum_kernel_fill_factor = 0; - double sum_major_kernel_fill_factor = 0; - double running_average_invert_fill_factor = 1; - double running_average_kernel_fill_factor = 1; - double running_average_major_kernel_fill_factor = 1; - - HighsInt AnIterIt0 = 0; + HighsInt num_invert; + HighsInt num_kernel; + HighsInt num_major_kernel; + double max_kernel_dim; + double sum_kernel_dim; + double running_average_kernel_dim; + double sum_invert_fill_factor; + double sum_kernel_fill_factor; + double sum_major_kernel_fill_factor; + double running_average_invert_fill_factor; + double running_average_kernel_fill_factor; + double running_average_major_kernel_fill_factor; + + HighsInt AnIterIt0; HighsInt AnIterPrevIt; // Major operation analysis struct diff --git a/src/simplex/SimplexStruct.h b/src/simplex/SimplexStruct.h index e29ce4e1ee..eb49c8ca96 100644 --- a/src/simplex/SimplexStruct.h +++ b/src/simplex/SimplexStruct.h @@ -25,7 +25,7 @@ struct SimplexBasis { // The basis for the simplex method consists of basicIndex, // nonbasicFlag and nonbasicMove. If HighsSimplexStatus has_basis // is true then it is assumed that basicIndex_ and nonbasicFlag_ are - // self-consistent and correpond to the dimensions of an associated + // self-consistent and correspond to the dimensions of an associated // HighsLp, but the basis matrix B is not necessarily nonsingular. std::vector basicIndex_; std::vector nonbasicFlag_; diff --git a/src/util/HFactor.h b/src/util/HFactor.h index a846c9c528..d06a79af67 100644 --- a/src/util/HFactor.h +++ b/src/util/HFactor.h @@ -105,6 +105,35 @@ struct InvertibleRepresentation { */ class HFactor { public: + HFactor() + : build_realTick(0.0), + build_synthetic_tick(0.0), + rank_deficiency(0), + basis_matrix_num_el(0), + invert_num_el(0), + kernel_dim(0), + kernel_num_el(0), + num_row(0), + num_col(0), + num_basic(0), + a_matrix_valid(false), + a_start(nullptr), + a_index(nullptr), + a_value(nullptr), + basic_index(nullptr), + pivot_threshold(0.0), + pivot_tolerance(0.0), + highs_debug_level(0), + time_limit_(0.0), + use_original_HFactor_logic(false), + debug_report_(false), + basis_matrix_limit_size(0), + update_method(0), + build_timer_(nullptr), + nwork(0), + u_merit_x(0), + u_total_x(0){}; + /** * @brief Copy problem size and pointers of constraint matrix, and set * up space for INVERT @@ -304,10 +333,10 @@ class HFactor { RefactorInfo refactor_info_; // Properties of data held in HFactor.h - HighsInt basis_matrix_num_el = 0; - HighsInt invert_num_el = 0; - HighsInt kernel_dim = 0; - HighsInt kernel_num_el = 0; + HighsInt basis_matrix_num_el; + HighsInt invert_num_el; + HighsInt kernel_dim; + HighsInt kernel_num_el; /** * Data of the factor @@ -339,7 +368,7 @@ class HFactor { HighsLogOptions log_options; bool use_original_HFactor_logic; - bool debug_report_ = false; + bool debug_report_; HighsInt basis_matrix_limit_size; HighsInt update_method; diff --git a/src/util/HighsCDouble.h b/src/util/HighsCDouble.h index 11cc8460d7..b02622d162 100644 --- a/src/util/HighsCDouble.h +++ b/src/util/HighsCDouble.h @@ -32,7 +32,7 @@ class HighsCDouble { // Proceedings of. 2005. /// performs an exact transformation such that x + y = a + b - /// and x = double(a + b). The operation uses 6 flops (addition/substraction). + /// and x = double(a + b). The operation uses 6 flops (addition/subtraction). static void two_sum(double& x, double& y, double a, double b) { x = a + b; double z = x - a; @@ -50,7 +50,7 @@ class HighsCDouble { /// performs an exact transformation such that x + y = a * b /// and x = double(a * b). The operation uses 10 flops for - /// addition/substraction and 7 flops for multiplication. + /// addition/subtraction and 7 flops for multiplication. static void two_product(double& x, double& y, double a, double b) { x = a * b; double a1, a2, b1, b2; diff --git a/src/util/HighsMatrixSlice.h b/src/util/HighsMatrixSlice.h index 6c71253672..3da09ce402 100644 --- a/src/util/HighsMatrixSlice.h +++ b/src/util/HighsMatrixSlice.h @@ -196,7 +196,7 @@ class HighsMatrixSlice { using pointer = const HighsSliceNonzero*; using reference = const HighsSliceNonzero&; - iterator(HighsInt node) : currentNode(node) {} + iterator(HighsInt node) : pos_(), nodeNext(nullptr), currentNode(node) {} iterator(const HighsInt* nodeIndex, const double* nodeValue, const HighsInt* nodeNext, HighsInt node) : pos_(node == -1 ? nullptr : nodeIndex + node, @@ -276,7 +276,8 @@ class HighsMatrixSlice { using pointer = const HighsSliceNonzero*; using reference = const HighsSliceNonzero&; - iterator(HighsInt node) : currentNode(node) {} + iterator(HighsInt node) + : pos_(), nodeLeft(nullptr), nodeRight(nullptr), currentNode(node) {} iterator(const HighsInt* nodeIndex, const double* nodeValue, const HighsInt* nodeLeft, const HighsInt* nodeRight, HighsInt node) : pos_(nodeIndex + node, nodeValue + node), @@ -374,7 +375,8 @@ class HighsMatrixSlice { using pointer = const HighsSliceNonzero*; using reference = const HighsSliceNonzero&; - iterator(HighsInt node) : currentNode(node) {} + iterator(HighsInt node) + : pos_(), nodeLeft(nullptr), nodeRight(nullptr), currentNode(node) {} iterator(const HighsInt* nodeIndex, const double* nodeValue, const HighsInt* nodeLeft, const HighsInt* nodeRight, HighsInt node) : pos_(nodeIndex, nodeValue), @@ -477,7 +479,7 @@ class HighsMatrixSlice { using pointer = const HighsSliceNonzero*; using reference = const HighsSliceNonzero&; - iterator(const HighsInt* node) : node(node) {} + iterator(const HighsInt* node) : pos_(), node(node), currentNode(0) {} iterator(const HighsInt* nodeIndex, const double* nodeValue, const HighsInt* node) : pos_(nodeIndex, nodeValue), node(node), currentNode(0) {}