diff --git a/.github/workflows/build-python-package.yml b/.github/workflows/build-python-package.yml index 0b6c32f2fe..33bd47786f 100644 --- a/.github/workflows/build-python-package.yml +++ b/.github/workflows/build-python-package.yml @@ -78,17 +78,14 @@ jobs: # ubuntu 22 has a latest version of cmake, but setup-python # does not seem to provide all necessary modules to find python # from cmake. works on my machine, test the wheels manually - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - # strategy: - # matrix: - # python: [3.12] - name: Install correct python version uses: actions/setup-python@v5 - # with: - # python-version: ${{ matrix.python }} + with: + python-version: '3.10' - name: Build wheel run: | diff --git a/.github/workflows/build-wheels-push.yml b/.github/workflows/build-wheels-push.yml index 899d865c9a..b38ebd2280 100644 --- a/.github/workflows/build-wheels-push.yml +++ b/.github/workflows/build-wheels-push.yml @@ -1,12 +1,12 @@ name: build-wheels-push -on: [] +# on: [] # on: push -# on: -# release: -# types: -# - published +on: + release: + types: + - published concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -82,51 +82,22 @@ jobs: name: cibw-wheels-${{ matrix.python }}-${{ matrix.buildplat[1] }} path: wheelhouse/*.whl - upload_testpypi: - name: >- - Publish highspy to TestPyPI - runs-on: ubuntu-latest - needs: [build_wheels, build_sdist] - # needs: [build_sdist] - - # upload to PyPI on every tag starting with 'v' - # if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') - - environment: - name: testpypi - url: https://test.pypi.org/p/highspy - - permissions: - id-token: write # IMPORTANT: mandatory for trusted publishing - steps: - - uses: actions/download-artifact@v4 - with: - pattern: cibw-* - path: dist - merge-multiple: true - - - name: Download all - uses: pypa/gh-action-pypi-publish@release/v1 - with: - repository-url: https://test.pypi.org/legacy/ - verbose: true - - # upload_pypi: + # upload_testpypi: # name: >- - # Publish highspy to PyPI + # Publish highspy to TestPyPI # runs-on: ubuntu-latest # needs: [build_wheels, build_sdist] + # # needs: [build_sdist] # # upload to PyPI on every tag starting with 'v' # # if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') # environment: - # name: pypi - # url: https://pypi.org/p/highspy + # name: testpypi + # url: https://test.pypi.org/p/highspy # permissions: # id-token: write # IMPORTANT: mandatory for trusted publishing - # steps: # - uses: actions/download-artifact@v4 # with: @@ -136,3 +107,32 @@ jobs: # - name: Download all # uses: pypa/gh-action-pypi-publish@release/v1 + # with: + # repository-url: https://test.pypi.org/legacy/ + # verbose: true + + upload_pypi: + name: >- + Publish highspy to PyPI + runs-on: ubuntu-latest + needs: [build_wheels, build_sdist] + + # upload to PyPI on every tag starting with 'v' + # if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + + environment: + name: pypi + url: https://pypi.org/p/highspy + + permissions: + id-token: write # IMPORTANT: mandatory for trusted publishing + + steps: + - uses: actions/download-artifact@v4 + with: + pattern: cibw-* + path: dist + merge-multiple: true + + - name: Download all + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml new file mode 100644 index 0000000000..e4540f2173 --- /dev/null +++ b/.github/workflows/code-coverage.yml @@ -0,0 +1,67 @@ +name: code-coverage + +on: [push, pull_request] + +jobs: + debug: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + + steps: + - uses: actions/checkout@v4 + + - name: install + run: sudo apt-get update && sudo apt-get install lcov + + - name: Create Build Environment + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Configure CMake + shell: bash + working-directory: ${{runner.workspace}}/build + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=Debug -DHIGHS_COVERAGE=ON -DALL_TESTS=ON -DBUILD_SHARED_LIBS=OFF -D CMAKE_C_COMPILER=gcc -D CMAKE_CXX_COMPILER=g++ + + - name: Build + working-directory: ${{runner.workspace}}/build + shell: bash + run: | + cmake --build . --parallel --config Debug + + - name: Test + working-directory: ${{runner.workspace}}/build + shell: bash + run: ctest --parallel --timeout 300 --output-on-failure + + - name: Generate Report + working-directory: ${{runner.workspace}}/build + shell: bash + run: | + lcov -d . -c -o cov.info --ignore-errors empty + lcov --remove cov.info "/usr/include/*" -o cov.info + lcov --remove cov.info "/usr/lib/*" -o cov.info + lcov --remove cov.info "extern/pdqsort/*" -o cov.info + lcov --remove cov.info "extern/zstr/*" -o cov.info + lcov --remove cov.info "extern/catch*" -o cov.info + lcov --remove cov.info "app/cxxopts*" -o cov.info + lcov --remove cov.info "src/test*" -o cov.info + lcov --list cov.info + + - name: Genhtml Results Summary + working-directory: ${{runner.workspace}}/build + shell: bash + run: | + genhtml -o coverage cov.info + + # Made it past the first token issue. + # May need some more time to porpagate on the codecov side. + # - name: Upload coverage reports to Codecov + # uses: codecov/codecov-action@v5 + # with: + # token: ${{ secrets.CODECOV_TOKEN }} + # slug: ERGO-Code/HiGHS + # fail_ci_if_error: true # optional (default = false) + # files: ${{runner.workspace}}/build/cov.info # optional + # # name: codecov-umbrella # optional + # verbose: true # optional (default = false) diff --git a/.gitignore b/.gitignore index 096bc893e1..c36222e48d 100644 --- a/.gitignore +++ b/.gitignore @@ -230,6 +230,7 @@ pip-log.txt # Unit test / coverage reports .coverage +cov.info .tox #Translations diff --git a/CMakeLists.txt b/CMakeLists.txt index dc485c9471..6ef2d28cdd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,8 @@ if (PYTHON_BUILD_SETUP) set(ZLIB OFF) endif() +option(HIGHS_COVERAGE "Activate the code coverage compilation" OFF) + # Address | Thread | Leak # Linux atm # Only Debug is theted atm @@ -328,16 +330,18 @@ if(NOT FAST_BUILD) endif() include(CheckCXXCompilerFlag) -if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(ppc64|powerpc64)" AND NOT APPLE) - check_cxx_compiler_flag("-mpopcntd" COMPILER_SUPPORTS_POPCNTD) - if(COMPILER_SUPPORTS_POPCNTD) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mpopcntd") - endif() -else() - check_cxx_compiler_flag("-mpopcnt" COMPILER_SUPPORTS_POPCNT) - if(COMPILER_SUPPORTS_POPCNT) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mpopcnt") - endif() +if (NOT HIGHS_COVERAGE) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(ppc64|powerpc64)" AND NOT APPLE) + check_cxx_compiler_flag("-mpopcntd" COMPILER_SUPPORTS_POPCNTD) + if(COMPILER_SUPPORTS_POPCNTD) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mpopcntd") + endif() + else() + check_cxx_compiler_flag("-mpopcnt" COMPILER_SUPPORTS_POPCNT) + if(COMPILER_SUPPORTS_POPCNT) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mpopcnt") + endif() + endif() endif() option(DEBUGSOL "check the debug solution" OFF) @@ -473,6 +477,58 @@ elseif (DEBUG_MEMORY STREQUAL "Leak") -fno-omit-frame-pointer ") endif() +# HiGHS coverage update in progress +if(FAST_BUILD AND HIGHS_COVERAGE) + if(WIN32) + message(FATAL_ERROR "Error: code coverage analysis is only available under Linux for now.") + endif() + + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + message(FATAL_ERROR "Warning: to enable coverage, you must compile in Debug mode") + endif() + + # Disable IPO + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF) + message(STATUS "Building in coverage mode") + + # Enable coverage flags + add_compile_options(-O0) + add_compile_options(--coverage) + add_compile_options(-fprofile-update=atomic) + + add_link_options(-O0) + add_link_options(--coverage) # Ensure coverage data is linked correctly + + find_program(GCOV_PATH gcov) + find_program(LCOV_PATH lcov) + find_program(GENHTML_PATH genhtml) + + if(NOT GCOV_PATH) + message(FATAL_ERROR "gcov not found! Please install lcov and gcov. Aborting...") + endif() + + if(NOT LCOV_PATH) + message(FATAL_ERROR "lcov not found! Please install lcov and gcov. Aborting...") + endif() + + if(NOT GENHTML_PATH) + message(FATAL_ERROR "genhtml not found! Please install lcov and gcov. Aborting...") + endif() + + # add_custom_target(coverage + # COMMAND ${LCOV_PATH} -d bin -c -o cov.info --ignore-errors empty + # COMMAND ${LCOV_PATH} --remove "*/usr/include/*" -o ${CMAKE_BINARY_DIR}/cov.info.cleaned + # COMMAND ${LCOV_PATH} --remove "*/usr/lib/*" -o ${CMAKE_BINARY_DIR}/cov.info.cleaned + # COMMAND ${LCOV_PATH} --remove "extern/pdqsort/*" -o ${CMAKE_BINARY_DIR}/cov.info.cleaned + # COMMAND ${LCOV_PATH} --remove "extern/zstr/*" -o ${CMAKE_BINARY_DIR}/cov.info.cleaned + # COMMAND ${LCOV_PATH} --remove "app/cxxopts*" -o ${CMAKE_BINARY_DIR}/cov.info.cleaned + # COMMAND ${GENHTML_PATH} ${CMAKE_BINARY_DIR}/cov.info.cleaned -o ${CMAKE_BINARY_DIR}/cov_report + # VERBATIM + # WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + # COMMENT "Generating code coverage report v2025.") + +endif() + if(NOT FAST_BUILD) # For the moment keep above coverage part in case we are testing at CI. option(CI "CI extended tests" ON) @@ -495,7 +551,7 @@ if(NOT FAST_BUILD) endif() if(HIGHS_COVERAGE) - if(NOT CMAKE_BUILD_TYPE STREQUAL "DEBUG") + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT CMAKE_BUILD_TYPE STREQUAL "DEBUG") message(FATAL_ERROR "Warning: to enable coverage, you must compile in DEBUG mode") endif() endif() diff --git a/FEATURES.md b/FEATURES.md index e3c62da2c9..bc7bf6d82c 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -10,4 +10,9 @@ Added basis solve methods to highspy Added methods to get primal/dual ray and dual unboundedness direction to highspy +When a presolved LP has model status kUnknown, rather than returning this to the user, it performs postsolve and then uses the basis to solve the original LP + +Fixed bug in presolve when pointers stored in HighsMatrixSlice get invalidated when the coefficient matrix is reallocated (e.g. when non-zeros are added in HPresolve::addToMatrix) + +Primal and dual residual tolerances - applied following IPM or PDLP solution - now documented as options diff --git a/app/RunHighs.cpp b/app/RunHighs.cpp index 8813755b4c..f238bc1adc 100644 --- a/app/RunHighs.cpp +++ b/app/RunHighs.cpp @@ -46,7 +46,7 @@ int main(int argc, char** argv) { // call this first so that printHighsVersionCopyright uses reporting // settings defined in any options file. highs.passOptions(loaded_options); - // highs.writeOptions("Options.md"); + highs.writeOptions("Options.md"); // Load the model from model_file HighsStatus read_status = highs.readModel(model_file); diff --git a/check/CMakeLists.txt b/check/CMakeLists.txt index b1076e1825..4ba1f995eb 100644 --- a/check/CMakeLists.txt +++ b/check/CMakeLists.txt @@ -129,25 +129,29 @@ if ((NOT FAST_BUILD OR ALL_TESTS) AND NOT (BUILD_EXTRA_UNIT_ONLY)) add_test(NAME capi_unit_tests COMMAND capi_unit_tests) # Check whether test executable builds OK. - add_test(NAME unit-test-build - COMMAND ${CMAKE_COMMAND} - --build ${HIGHS_BINARY_DIR} - --target unit_tests - # --config ${CMAKE_BUILD_TYPE} - ) - + if (NOT HIGHS_COVERAGE) + add_test(NAME unit-test-build + COMMAND ${CMAKE_COMMAND} + --build ${HIGHS_BINARY_DIR} + --target unit_tests + # --config ${CMAKE_BUILD_TYPE} + ) - # Avoid that several build jobs try to concurretly build. - set_tests_properties(unit-test-build - PROPERTIES - RESOURCE_LOCK unittestbin) + # Avoid that several build jobs try to concurretly build. + set_tests_properties(unit-test-build + PROPERTIES + RESOURCE_LOCK unittestbin) - # create a binary running all the tests in the executable - add_test(NAME unit_tests_all COMMAND unit_tests --success) - set_tests_properties(unit_tests_all - PROPERTIES - DEPENDS unit-test-build) - set_tests_properties(unit_tests_all PROPERTIES TIMEOUT 10000) + # create a binary running all the tests in the executable + add_test(NAME unit_tests_all COMMAND unit_tests --success) + set_tests_properties(unit_tests_all + PROPERTIES + DEPENDS unit-test-build) + set_tests_properties(unit_tests_all PROPERTIES TIMEOUT 10000) + else() + add_test(NAME unit_tests_all COMMAND unit_tests --success) + set_tests_properties(unit_tests_all PROPERTIES TIMEOUT 10000) + endif() # An individual test can be added with the command below but the approach # above with a single add_test for all the unit tests automatically detects all diff --git a/check/TestPresolve.cpp b/check/TestPresolve.cpp index 7d2e5d9604..505373c156 100644 --- a/check/TestPresolve.cpp +++ b/check/TestPresolve.cpp @@ -639,3 +639,13 @@ TEST_CASE("presolve-slacks", "[highs_test_presolve]") { REQUIRE(h.getPresolvedLp().num_col_ == 2); REQUIRE(h.getPresolvedLp().num_row_ == 2); } + +TEST_CASE("presolve-issue-2095", "[highs_test_presolve]") { + std::string model_file = + std::string(HIGHS_DIR) + "/check/instances/issue-2095.mps"; + Highs highs; + highs.setOptionValue("output_flag", dev_run); + highs.readModel(model_file); + REQUIRE(highs.presolve() == HighsStatus::kOk); + REQUIRE(highs.getModelPresolveStatus() == HighsPresolveStatus::kReduced); +} diff --git a/check/instances/issue-2095.mps b/check/instances/issue-2095.mps new file mode 100644 index 0000000000..a05dc4ef22 --- /dev/null +++ b/check/instances/issue-2095.mps @@ -0,0 +1,836 @@ +NAME +ROWS + N Obj + E r0 + E r1 + E r2 + E r3 + E r4 + E r5 + E r6 + E r7 + E r8 + E r9 + E r10 + E r11 + E r12 + E r13 + E r14 + E r15 + E r16 + E r17 + E r18 + E r19 + E r20 + E r21 + E r22 + E r23 + E r24 + E r25 + E r26 + E r27 + E r28 +COLUMNS + MARK0000 'MARKER' 'INTORG' + c0 Obj 1 + c0 r0 1 + c1 Obj 1 + c1 r1 1 + c2 Obj 1 + c2 r2 1 + c3 Obj 1 + c3 r3 1 + c4 Obj 1 + c4 r5 1 + c5 Obj 1 + c5 r6 1 + c6 Obj 1 + c6 r7 1 + c7 Obj 1 + c7 r25 1 + c8 Obj 1 + c8 r26 1 + c9 Obj 1 + c9 r27 1 + c10 Obj 1 + c10 r28 1 + c11 Obj 1 + c11 r0 1 + c11 r1 1 + c11 r2 1 + c11 r3 1 + c12 Obj 1 + c12 r1 1 + c12 r2 1 + c12 r3 1 + c12 r4 1 + c13 Obj 1 + c13 r5 1 + c13 r6 1 + c13 r7 1 + c13 r8 1 + c14 Obj 1 + c14 r8 1 + c14 r9 1 + c14 r10 1 + c14 r11 1 + c15 Obj 1 + c15 r24 1 + c15 r25 1 + c15 r26 1 + c15 r27 1 + c16 Obj 1 + c16 r0 1 + c16 r1 1 + c16 r2 1 + c16 r3 1 + c16 r4 1 + c17 Obj 1 + c17 r4 1 + c17 r5 1 + c17 r6 1 + c17 r7 1 + c17 r8 1 + c18 Obj 1 + c18 r5 1 + c18 r6 1 + c18 r7 1 + c18 r8 1 + c18 r9 1 + c19 Obj 1 + c19 r8 1 + c19 r9 1 + c19 r10 1 + c19 r11 1 + c19 r12 1 + c20 Obj 1 + c20 r23 1 + c20 r24 1 + c20 r25 1 + c20 r26 1 + c20 r27 1 + c21 Obj 1 + c21 r4 1 + c21 r5 1 + c21 r6 1 + c21 r7 1 + c21 r8 1 + c21 r9 1 + c22 Obj 1 + c22 r5 1 + c22 r6 1 + c22 r7 1 + c22 r8 1 + c22 r9 1 + c22 r10 1 + c23 Obj 1 + c23 r8 1 + c23 r9 1 + c23 r10 1 + c23 r11 1 + c23 r12 1 + c23 r13 1 + c24 Obj 1 + c24 r22 1 + c24 r23 1 + c24 r24 1 + c24 r25 1 + c24 r26 1 + c24 r27 1 + c25 Obj 1 + c25 r4 1 + c25 r5 1 + c25 r6 1 + c25 r7 1 + c25 r8 1 + c25 r9 1 + c25 r10 1 + c26 Obj 1 + c26 r8 1 + c26 r9 1 + c26 r10 1 + c26 r11 1 + c26 r12 1 + c26 r13 1 + c26 r14 1 + c27 Obj 1 + c27 r21 1 + c27 r22 1 + c27 r23 1 + c27 r24 1 + c27 r25 1 + c27 r26 1 + c27 r27 1 + c28 Obj 1 + c28 r8 1 + c28 r9 1 + c28 r10 1 + c28 r11 1 + c28 r12 1 + c28 r13 1 + c28 r14 1 + c28 r15 1 + c29 Obj 1 + c29 r20 1 + c29 r21 1 + c29 r22 1 + c29 r23 1 + c29 r24 1 + c29 r25 1 + c29 r26 1 + c29 r27 1 + c30 Obj 1 + c30 r8 1 + c30 r9 1 + c30 r10 1 + c30 r11 1 + c30 r12 1 + c30 r13 1 + c30 r14 1 + c30 r15 1 + c30 r16 1 + c31 Obj 1 + c31 r19 1 + c31 r20 1 + c31 r21 1 + c31 r22 1 + c31 r23 1 + c31 r24 1 + c31 r25 1 + c31 r26 1 + c31 r27 1 + c32 Obj 1 + c32 r8 1 + c32 r9 1 + c32 r10 1 + c32 r11 1 + c32 r12 1 + c32 r13 1 + c32 r14 1 + c32 r15 1 + c32 r16 1 + c32 r17 1 + c33 Obj 1 + c33 r18 1 + c33 r19 1 + c33 r20 1 + c33 r21 1 + c33 r22 1 + c33 r23 1 + c33 r24 1 + c33 r25 1 + c33 r26 1 + c33 r27 1 + c34 Obj 1 + c34 r8 1 + c34 r9 1 + c34 r10 1 + c34 r11 1 + c34 r12 1 + c34 r13 1 + c34 r14 1 + c34 r15 1 + c34 r16 1 + c34 r17 1 + c34 r18 1 + c35 Obj 1 + c35 r17 1 + c35 r18 1 + c35 r19 1 + c35 r20 1 + c35 r21 1 + c35 r22 1 + c35 r23 1 + c35 r24 1 + c35 r25 1 + c35 r26 1 + c35 r27 1 + c36 Obj 1 + c36 r7 1 + c36 r8 1 + c36 r9 1 + c36 r10 1 + c36 r11 1 + c36 r12 1 + c36 r13 1 + c36 r14 1 + c36 r15 1 + c36 r16 1 + c36 r17 1 + c36 r18 1 + c37 Obj 1 + c37 r8 1 + c37 r9 1 + c37 r10 1 + c37 r11 1 + c37 r12 1 + c37 r13 1 + c37 r14 1 + c37 r15 1 + c37 r16 1 + c37 r17 1 + c37 r18 1 + c37 r19 1 + c38 Obj 1 + c38 r16 1 + c38 r17 1 + c38 r18 1 + c38 r19 1 + c38 r20 1 + c38 r21 1 + c38 r22 1 + c38 r23 1 + c38 r24 1 + c38 r25 1 + c38 r26 1 + c38 r27 1 + c39 Obj 1 + c39 r17 1 + c39 r18 1 + c39 r19 1 + c39 r20 1 + c39 r21 1 + c39 r22 1 + c39 r23 1 + c39 r24 1 + c39 r25 1 + c39 r26 1 + c39 r27 1 + c39 r28 1 + c40 Obj 1 + c40 r7 1 + c40 r8 1 + c40 r9 1 + c40 r10 1 + c40 r11 1 + c40 r12 1 + c40 r13 1 + c40 r14 1 + c40 r15 1 + c40 r16 1 + c40 r17 1 + c40 r18 1 + c40 r19 1 + c41 Obj 1 + c41 r8 1 + c41 r9 1 + c41 r10 1 + c41 r11 1 + c41 r12 1 + c41 r13 1 + c41 r14 1 + c41 r15 1 + c41 r16 1 + c41 r17 1 + c41 r18 1 + c41 r19 1 + c41 r20 1 + c42 Obj 1 + c42 r15 1 + c42 r16 1 + c42 r17 1 + c42 r18 1 + c42 r19 1 + c42 r20 1 + c42 r21 1 + c42 r22 1 + c42 r23 1 + c42 r24 1 + c42 r25 1 + c42 r26 1 + c42 r27 1 + c43 Obj 1 + c43 r16 1 + c43 r17 1 + c43 r18 1 + c43 r19 1 + c43 r20 1 + c43 r21 1 + c43 r22 1 + c43 r23 1 + c43 r24 1 + c43 r25 1 + c43 r26 1 + c43 r27 1 + c43 r28 1 + c44 Obj 1 + c44 r7 1 + c44 r8 1 + c44 r9 1 + c44 r10 1 + c44 r11 1 + c44 r12 1 + c44 r13 1 + c44 r14 1 + c44 r15 1 + c44 r16 1 + c44 r17 1 + c44 r18 1 + c44 r19 1 + c44 r20 1 + c45 Obj 1 + c45 r8 1 + c45 r9 1 + c45 r10 1 + c45 r11 1 + c45 r12 1 + c45 r13 1 + c45 r14 1 + c45 r15 1 + c45 r16 1 + c45 r17 1 + c45 r18 1 + c45 r19 1 + c45 r20 1 + c45 r21 1 + c46 Obj 1 + c46 r14 1 + c46 r15 1 + c46 r16 1 + c46 r17 1 + c46 r18 1 + c46 r19 1 + c46 r20 1 + c46 r21 1 + c46 r22 1 + c46 r23 1 + c46 r24 1 + c46 r25 1 + c46 r26 1 + c46 r27 1 + c47 Obj 1 + c47 r15 1 + c47 r16 1 + c47 r17 1 + c47 r18 1 + c47 r19 1 + c47 r20 1 + c47 r21 1 + c47 r22 1 + c47 r23 1 + c47 r24 1 + c47 r25 1 + c47 r26 1 + c47 r27 1 + c47 r28 1 + c48 Obj 1 + c48 r7 1 + c48 r8 1 + c48 r9 1 + c48 r10 1 + c48 r11 1 + c48 r12 1 + c48 r13 1 + c48 r14 1 + c48 r15 1 + c48 r16 1 + c48 r17 1 + c48 r18 1 + c48 r19 1 + c48 r20 1 + c48 r21 1 + c49 Obj 1 + c49 r8 1 + c49 r9 1 + c49 r10 1 + c49 r11 1 + c49 r12 1 + c49 r13 1 + c49 r14 1 + c49 r15 1 + c49 r16 1 + c49 r17 1 + c49 r18 1 + c49 r19 1 + c49 r20 1 + c49 r21 1 + c49 r22 1 + c50 Obj 1 + c50 r13 1 + c50 r14 1 + c50 r15 1 + c50 r16 1 + c50 r17 1 + c50 r18 1 + c50 r19 1 + c50 r20 1 + c50 r21 1 + c50 r22 1 + c50 r23 1 + c50 r24 1 + c50 r25 1 + c50 r26 1 + c50 r27 1 + c51 Obj 1 + c51 r14 1 + c51 r15 1 + c51 r16 1 + c51 r17 1 + c51 r18 1 + c51 r19 1 + c51 r20 1 + c51 r21 1 + c51 r22 1 + c51 r23 1 + c51 r24 1 + c51 r25 1 + c51 r26 1 + c51 r27 1 + c51 r28 1 + c52 Obj 1 + c52 r7 1 + c52 r8 1 + c52 r9 1 + c52 r10 1 + c52 r11 1 + c52 r12 1 + c52 r13 1 + c52 r14 1 + c52 r15 1 + c52 r16 1 + c52 r17 1 + c52 r18 1 + c52 r19 1 + c52 r20 1 + c52 r21 1 + c52 r22 1 + c53 Obj 1 + c53 r8 1 + c53 r9 1 + c53 r10 1 + c53 r11 1 + c53 r12 1 + c53 r13 1 + c53 r14 1 + c53 r15 1 + c53 r16 1 + c53 r17 1 + c53 r18 1 + c53 r19 1 + c53 r20 1 + c53 r21 1 + c53 r22 1 + c53 r23 1 + c54 Obj 1 + c54 r12 1 + c54 r13 1 + c54 r14 1 + c54 r15 1 + c54 r16 1 + c54 r17 1 + c54 r18 1 + c54 r19 1 + c54 r20 1 + c54 r21 1 + c54 r22 1 + c54 r23 1 + c54 r24 1 + c54 r25 1 + c54 r26 1 + c54 r27 1 + c55 Obj 1 + c55 r13 1 + c55 r14 1 + c55 r15 1 + c55 r16 1 + c55 r17 1 + c55 r18 1 + c55 r19 1 + c55 r20 1 + c55 r21 1 + c55 r22 1 + c55 r23 1 + c55 r24 1 + c55 r25 1 + c55 r26 1 + c55 r27 1 + c55 r28 1 + c56 Obj 1 + c56 r7 1 + c56 r8 1 + c56 r9 1 + c56 r10 1 + c56 r11 1 + c56 r12 1 + c56 r13 1 + c56 r14 1 + c56 r15 1 + c56 r16 1 + c56 r17 1 + c56 r18 1 + c56 r19 1 + c56 r20 1 + c56 r21 1 + c56 r22 1 + c56 r23 1 + c57 Obj 1 + c57 r8 1 + c57 r9 1 + c57 r10 1 + c57 r11 1 + c57 r12 1 + c57 r13 1 + c57 r14 1 + c57 r15 1 + c57 r16 1 + c57 r17 1 + c57 r18 1 + c57 r19 1 + c57 r20 1 + c57 r21 1 + c57 r22 1 + c57 r23 1 + c57 r24 1 + c58 Obj 1 + c58 r11 1 + c58 r12 1 + c58 r13 1 + c58 r14 1 + c58 r15 1 + c58 r16 1 + c58 r17 1 + c58 r18 1 + c58 r19 1 + c58 r20 1 + c58 r21 1 + c58 r22 1 + c58 r23 1 + c58 r24 1 + c58 r25 1 + c58 r26 1 + c58 r27 1 + c59 Obj 1 + c59 r12 1 + c59 r13 1 + c59 r14 1 + c59 r15 1 + c59 r16 1 + c59 r17 1 + c59 r18 1 + c59 r19 1 + c59 r20 1 + c59 r21 1 + c59 r22 1 + c59 r23 1 + c59 r24 1 + c59 r25 1 + c59 r26 1 + c59 r27 1 + c59 r28 1 + c60 Obj 1 + c60 r7 1 + c60 r8 1 + c60 r9 1 + c60 r10 1 + c60 r11 1 + c60 r12 1 + c60 r13 1 + c60 r14 1 + c60 r15 1 + c60 r16 1 + c60 r17 1 + c60 r18 1 + c60 r19 1 + c60 r20 1 + c60 r21 1 + c60 r22 1 + c60 r23 1 + c60 r24 1 + c61 Obj 1 + c61 r10 1 + c61 r11 1 + c61 r12 1 + c61 r13 1 + c61 r14 1 + c61 r15 1 + c61 r16 1 + c61 r17 1 + c61 r18 1 + c61 r19 1 + c61 r20 1 + c61 r21 1 + c61 r22 1 + c61 r23 1 + c61 r24 1 + c61 r25 1 + c61 r26 1 + c61 r27 1 + c62 Obj 1 + c62 r11 1 + c62 r12 1 + c62 r13 1 + c62 r14 1 + c62 r15 1 + c62 r16 1 + c62 r17 1 + c62 r18 1 + c62 r19 1 + c62 r20 1 + c62 r21 1 + c62 r22 1 + c62 r23 1 + c62 r24 1 + c62 r25 1 + c62 r26 1 + c62 r27 1 + c62 r28 1 + c63 Obj 1 + c63 r9 1 + c63 r10 1 + c63 r11 1 + c63 r12 1 + c63 r13 1 + c63 r14 1 + c63 r15 1 + c63 r16 1 + c63 r17 1 + c63 r18 1 + c63 r19 1 + c63 r20 1 + c63 r21 1 + c63 r22 1 + c63 r23 1 + c63 r24 1 + c63 r25 1 + c63 r26 1 + c63 r27 1 + c64 Obj 1 + c64 r10 1 + c64 r11 1 + c64 r12 1 + c64 r13 1 + c64 r14 1 + c64 r15 1 + c64 r16 1 + c64 r17 1 + c64 r18 1 + c64 r19 1 + c64 r20 1 + c64 r21 1 + c64 r22 1 + c64 r23 1 + c64 r24 1 + c64 r25 1 + c64 r26 1 + c64 r27 1 + c64 r28 1 + c65 Obj 1 + c65 r9 1 + c65 r10 1 + c65 r11 1 + c65 r12 1 + c65 r13 1 + c65 r14 1 + c65 r15 1 + c65 r16 1 + c65 r17 1 + c65 r18 1 + c65 r19 1 + c65 r20 1 + c65 r21 1 + c65 r22 1 + c65 r23 1 + c65 r24 1 + c65 r25 1 + c65 r26 1 + c65 r27 1 + c65 r28 1 + MARK0001 'MARKER' 'INTEND' +RHS + RHS_V r0 1 + RHS_V r1 1 + RHS_V r2 1 + RHS_V r3 1 + RHS_V r4 1 + RHS_V r5 1 + RHS_V r6 1 + RHS_V r7 1 + RHS_V r8 1 + RHS_V r9 1 + RHS_V r10 1 + RHS_V r11 1 + RHS_V r12 1 + RHS_V r13 1 + RHS_V r14 1 + RHS_V r15 1 + RHS_V r16 1 + RHS_V r17 1 + RHS_V r18 1 + RHS_V r19 1 + RHS_V r20 1 + RHS_V r21 1 + RHS_V r22 1 + RHS_V r23 1 + RHS_V r24 1 + RHS_V r25 1 + RHS_V r26 1 + RHS_V r27 1 + RHS_V r28 1 +BOUNDS + BV BOUND c0 + BV BOUND c1 + BV BOUND c2 + BV BOUND c3 + BV BOUND c4 + BV BOUND c5 + BV BOUND c6 + BV BOUND c7 + BV BOUND c8 + BV BOUND c9 + BV BOUND c10 + BV BOUND c11 + BV BOUND c12 + BV BOUND c13 + BV BOUND c14 + BV BOUND c15 + BV BOUND c16 + BV BOUND c17 + BV BOUND c18 + BV BOUND c19 + BV BOUND c20 + BV BOUND c21 + BV BOUND c22 + BV BOUND c23 + BV BOUND c24 + BV BOUND c25 + BV BOUND c26 + BV BOUND c27 + BV BOUND c28 + BV BOUND c29 + BV BOUND c30 + BV BOUND c31 + BV BOUND c32 + BV BOUND c33 + BV BOUND c34 + BV BOUND c35 + BV BOUND c36 + BV BOUND c37 + BV BOUND c38 + BV BOUND c39 + BV BOUND c40 + BV BOUND c41 + BV BOUND c42 + BV BOUND c43 + BV BOUND c44 + BV BOUND c45 + BV BOUND c46 + BV BOUND c47 + BV BOUND c48 + BV BOUND c49 + BV BOUND c50 + BV BOUND c51 + BV BOUND c52 + BV BOUND c53 + BV BOUND c54 + BV BOUND c55 + BV BOUND c56 + BV BOUND c57 + BV BOUND c58 + BV BOUND c59 + BV BOUND c60 + BV BOUND c61 + BV BOUND c62 + BV BOUND c63 + BV BOUND c64 + BV BOUND c65 +ENDATA diff --git a/cmake/cpp-highs.cmake b/cmake/cpp-highs.cmake index 88a529a6f3..3e25a3e601 100644 --- a/cmake/cpp-highs.cmake +++ b/cmake/cpp-highs.cmake @@ -57,18 +57,20 @@ install(TARGETS highs PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/highs) # Add library targets to the build-tree export set -export(TARGETS highs - NAMESPACE ${PROJECT_NAMESPACE}::highs - FILE "${HIGHS_BINARY_DIR}/highs-targets.cmake") - -install(EXPORT ${lower}-targets - NAMESPACE ${PROJECT_NAMESPACE}:: - FILE highs-targets.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${lower}) -# install(FILES "${HIGHS_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/highs-config.cmake" -# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/highs) -# install(FILES "${HIGHS_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/highs.pc" -# DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +if (NOT HIGHS_COVERAGE) + export(TARGETS highs + NAMESPACE ${PROJECT_NAMESPACE}::highs + FILE "${HIGHS_BINARY_DIR}/highs-targets.cmake") + + install(EXPORT ${lower}-targets + NAMESPACE ${PROJECT_NAMESPACE}:: + FILE highs-targets.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${lower}) + # install(FILES "${HIGHS_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/highs-config.cmake" + # DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/highs) + # install(FILES "${HIGHS_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/highs.pc" + # DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +endif() include(CMakePackageConfigHelpers) diff --git a/docs/src/options/definitions.md b/docs/src/options/definitions.md index f4e932523c..92ac80c889 100644 --- a/docs/src/options/definitions.md +++ b/docs/src/options/definitions.md @@ -73,6 +73,18 @@ - Range: [1e-12, inf] - Default: 1e-08 +## primal\_residual\_tolerance +- Primal residual tolerance +- Type: double +- Range: [1e-10, inf] +- Default: 1e-07 + +## dual\_residual\_tolerance +- Dual residual tolerance +- Type: double +- Range: [1e-10, inf] +- Default: 1e-07 + ## objective\_bound - Objective bound for termination of the dual simplex solver - Type: double @@ -198,6 +210,16 @@ - Type: boolean - Default: "false" +## write\_presolved\_model\_file +- Write presolved model file +- Type: string +- Default: "" + +## write\_presolved\_model\_to\_file +- Write the presolved model to a file +- Type: boolean +- Default: "false" + ## mip\_detect\_symmetry - Whether MIP symmetry should be detected - Type: boolean @@ -220,6 +242,12 @@ - Range: {0, 2147483647} - Default: 2147483647 +## mip\_max\_start\_nodes +- MIP solver max number of nodes when completing a partial MIP start +- Type: integer +- Range: {0, 2147483647} +- Default: 500 + ## mip\_improving\_solution\_save - Whether improving MIP solutions should be saved - Type: boolean @@ -354,7 +382,7 @@ - Default: 4000 ## blend\_multi\_objectives -- Blend multiple objectives or apply lexicographically +- Blend multiple objectives or apply lexicographically: Default = true - Type: boolean - Default: "true" diff --git a/src/highs_bindings.cpp b/src/highs_bindings.cpp index c9b6c42269..d4c7ad0ebe 100644 --- a/src/highs_bindings.cpp +++ b/src/highs_bindings.cpp @@ -886,27 +886,27 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { // parent scope, which should be skipped for newer C++11-style strongly typed // enums." // [1]: https://pybind11.readthedocs.io/en/stable/classes.html - py::enum_(m, "ObjSense") + py::enum_(m, "ObjSense", py::module_local()) .value("kMinimize", ObjSense::kMinimize) .value("kMaximize", ObjSense::kMaximize); - py::enum_(m, "MatrixFormat") + py::enum_(m, "MatrixFormat", py::module_local()) .value("kColwise", MatrixFormat::kColwise) .value("kRowwise", MatrixFormat::kRowwise) .value("kRowwisePartitioned", MatrixFormat::kRowwisePartitioned); - py::enum_(m, "HessianFormat") + py::enum_(m, "HessianFormat", py::module_local()) .value("kTriangular", HessianFormat::kTriangular) .value("kSquare", HessianFormat::kSquare); - py::enum_(m, "SolutionStatus") + py::enum_(m, "SolutionStatus", py::module_local()) .value("kSolutionStatusNone", SolutionStatus::kSolutionStatusNone) .value("kSolutionStatusInfeasible", SolutionStatus::kSolutionStatusInfeasible) .value("kSolutionStatusFeasible", SolutionStatus::kSolutionStatusFeasible) .export_values(); - py::enum_(m, "BasisValidity") + py::enum_(m, "BasisValidity", py::module_local()) .value("kBasisValidityInvalid", BasisValidity::kBasisValidityInvalid) .value("kBasisValidityValid", BasisValidity::kBasisValidityValid) .export_values(); - py::enum_(m, "HighsModelStatus") + py::enum_(m, "HighsModelStatus", py::module_local()) .value("kNotset", HighsModelStatus::kNotset) .value("kLoadError", HighsModelStatus::kLoadError) .value("kModelError", HighsModelStatus::kModelError) @@ -926,7 +926,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kSolutionLimit", HighsModelStatus::kSolutionLimit) .value("kInterrupt", HighsModelStatus::kInterrupt) .value("kMemoryLimit", HighsModelStatus::kMemoryLimit); - py::enum_(m, "HighsPresolveStatus") + py::enum_(m, "HighsPresolveStatus", py::module_local()) .value("kNotPresolved", HighsPresolveStatus::kNotPresolved) .value("kNotReduced", HighsPresolveStatus::kNotReduced) .value("kInfeasible", HighsPresolveStatus::kInfeasible) @@ -937,37 +937,37 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kTimeout", HighsPresolveStatus::kTimeout) .value("kNullError", HighsPresolveStatus::kNullError) .value("kOptionsError", HighsPresolveStatus::kOptionsError); - py::enum_(m, "HighsBasisStatus") + py::enum_(m, "HighsBasisStatus", py::module_local()) .value("kLower", HighsBasisStatus::kLower) .value("kBasic", HighsBasisStatus::kBasic) .value("kUpper", HighsBasisStatus::kUpper) .value("kZero", HighsBasisStatus::kZero) .value("kNonbasic", HighsBasisStatus::kNonbasic); - py::enum_(m, "HighsVarType") + py::enum_(m, "HighsVarType", py::module_local()) .value("kContinuous", HighsVarType::kContinuous) .value("kInteger", HighsVarType::kInteger) .value("kSemiContinuous", HighsVarType::kSemiContinuous) .value("kSemiInteger", HighsVarType::kSemiInteger); - py::enum_(m, "HighsOptionType") + py::enum_(m, "HighsOptionType", py::module_local()) .value("kBool", HighsOptionType::kBool) .value("kInt", HighsOptionType::kInt) .value("kDouble", HighsOptionType::kDouble) .value("kString", HighsOptionType::kString); - py::enum_(m, "HighsInfoType") + py::enum_(m, "HighsInfoType", py::module_local()) .value("kInt64", HighsInfoType::kInt64) .value("kInt", HighsInfoType::kInt) .value("kDouble", HighsInfoType::kDouble); - py::enum_(m, "HighsStatus") + py::enum_(m, "HighsStatus", py::module_local()) .value("kError", HighsStatus::kError) .value("kOk", HighsStatus::kOk) .value("kWarning", HighsStatus::kWarning); - py::enum_(m, "HighsLogType") + py::enum_(m, "HighsLogType", py::module_local()) .value("kInfo", HighsLogType::kInfo) .value("kDetailed", HighsLogType::kDetailed) .value("kVerbose", HighsLogType::kVerbose) .value("kWarning", HighsLogType::kWarning) .value("kError", HighsLogType::kError); - py::enum_(m, "IisStrategy") + py::enum_(m, "IisStrategy", py::module_local()) .value("kIisStrategyMin", IisStrategy::kIisStrategyMin) .value("kIisStrategyFromLpRowPriority", IisStrategy::kIisStrategyFromLpRowPriority) @@ -975,7 +975,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { IisStrategy::kIisStrategyFromLpColPriority) .value("kIisStrategyMax", IisStrategy::kIisStrategyMax) .export_values(); - py::enum_(m, "IisBoundStatus") + py::enum_(m, "IisBoundStatus", py::module_local()) .value("kIisBoundStatusDropped", IisBoundStatus::kIisBoundStatusDropped) .value("kIisBoundStatusNull", IisBoundStatus::kIisBoundStatusNull) .value("kIisBoundStatusFree", IisBoundStatus::kIisBoundStatusFree) @@ -983,7 +983,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kIisBoundStatusUpper", IisBoundStatus::kIisBoundStatusUpper) .value("kIisBoundStatusBoxed", IisBoundStatus::kIisBoundStatusBoxed) .export_values(); - py::enum_(m, "HighsDebugLevel") + py::enum_(m, "HighsDebugLevel", py::module_local()) .value("kHighsDebugLevelNone", HighsDebugLevel::kHighsDebugLevelNone) .value("kHighsDebugLevelCheap", HighsDebugLevel::kHighsDebugLevelCheap) .value("kHighsDebugLevelCostly", HighsDebugLevel::kHighsDebugLevelCostly) @@ -992,7 +992,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kHighsDebugLevelMax", HighsDebugLevel::kHighsDebugLevelMax) .export_values(); // Classes - py::class_(m, "HighsSparseMatrix") + py::class_(m, "HighsSparseMatrix", py::module_local()) .def(py::init<>()) .def_readwrite("format_", &HighsSparseMatrix::format_) .def_readwrite("num_col_", &HighsSparseMatrix::num_col_) @@ -1001,9 +1001,9 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def_readwrite("p_end_", &HighsSparseMatrix::p_end_) .def_readwrite("index_", &HighsSparseMatrix::index_) .def_readwrite("value_", &HighsSparseMatrix::value_); - py::class_(m, "HighsLpMods"); - py::class_(m, "HighsScale"); - py::class_(m, "HighsLp") + py::class_(m, "HighsLpMods", py::module_local()); + py::class_(m, "HighsScale", py::module_local()); + py::class_(m, "HighsLp", py::module_local()) .def(py::init<>()) .def_readwrite("num_col_", &HighsLp::num_col_) .def_readwrite("num_row_", &HighsLp::num_row_) @@ -1023,18 +1023,18 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def_readwrite("is_scaled_", &HighsLp::is_scaled_) .def_readwrite("is_moved_", &HighsLp::is_moved_) .def_readwrite("mods_", &HighsLp::mods_); - py::class_(m, "HighsHessian") + py::class_(m, "HighsHessian", py::module_local()) .def(py::init<>()) .def_readwrite("dim_", &HighsHessian::dim_) .def_readwrite("format_", &HighsHessian::format_) .def_readwrite("start_", &HighsHessian::start_) .def_readwrite("index_", &HighsHessian::index_) .def_readwrite("value_", &HighsHessian::value_); - py::class_(m, "HighsModel") + py::class_(m, "HighsModel", py::module_local()) .def(py::init<>()) .def_readwrite("lp_", &HighsModel::lp_) .def_readwrite("hessian_", &HighsModel::hessian_); - py::class_(m, "HighsInfo") + py::class_(m, "HighsInfo", py::module_local()) .def(py::init<>()) .def_readwrite("valid", &HighsInfo::valid) .def_readwrite("mip_node_count", &HighsInfo::mip_node_count) @@ -1073,7 +1073,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { &HighsInfo::sum_complementarity_violations) .def_readwrite("primal_dual_integral", &HighsInfo::primal_dual_integral); - py::class_(m, "HighsOptions") + py::class_(m, "HighsOptions", py::module_local()) .def(py::init<>()) .def_readwrite("presolve", &HighsOptions::presolve) .def_readwrite("solver", &HighsOptions::solver) @@ -1161,7 +1161,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { &HighsOptions::mip_heuristic_effort) .def_readwrite("mip_min_logging_interval", &HighsOptions::mip_min_logging_interval); - py::class_(m, "_Highs") + py::class_(m, "_Highs", py::module_local()) .def(py::init<>()) .def("version", &Highs::version) .def("versionMajor", &Highs::versionMajor) @@ -1356,7 +1356,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def("stopCallbackInt", static_cast( &Highs::stopCallback)); - py::class_(m, "HighsIis") + py::class_(m, "HighsIis", py::module_local()) .def(py::init<>()) .def("invalidate", &HighsIis::invalidate) .def_readwrite("valid", &HighsIis::valid_) @@ -1367,7 +1367,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def_readwrite("row_bound", &HighsIis::row_bound_) .def_readwrite("info", &HighsIis::info_); // structs - py::class_(m, "HighsSolution") + py::class_(m, "HighsSolution", py::module_local()) .def(py::init<>()) .def_readwrite("value_valid", &HighsSolution::value_valid) .def_readwrite("dual_valid", &HighsSolution::dual_valid) @@ -1375,11 +1375,11 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def_readwrite("col_dual", &HighsSolution::col_dual) .def_readwrite("row_value", &HighsSolution::row_value) .def_readwrite("row_dual", &HighsSolution::row_dual); - py::class_(m, "HighsObjectiveSolution") + py::class_(m, "HighsObjectiveSolution", py::module_local()) .def(py::init<>()) .def_readwrite("objective", &HighsObjectiveSolution::objective) .def_readwrite("col_value", &HighsObjectiveSolution::col_value); - py::class_(m, "HighsBasis") + py::class_(m, "HighsBasis", py::module_local()) .def(py::init<>()) .def_readwrite("valid", &HighsBasis::valid) .def_readwrite("alien", &HighsBasis::alien) @@ -1389,13 +1389,13 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def_readwrite("debug_origin_name", &HighsBasis::debug_origin_name) .def_readwrite("col_status", &HighsBasis::col_status) .def_readwrite("row_status", &HighsBasis::row_status); - py::class_(m, "HighsRangingRecord") + py::class_(m, "HighsRangingRecord", py::module_local()) .def(py::init<>()) .def_readwrite("value_", &HighsRangingRecord::value_) .def_readwrite("objective_", &HighsRangingRecord::objective_) .def_readwrite("in_var_", &HighsRangingRecord::in_var_) .def_readwrite("ou_var_", &HighsRangingRecord::ou_var_); - py::class_(m, "HighsRanging") + py::class_(m, "HighsRanging", py::module_local()) .def(py::init<>()) .def_readwrite("valid", &HighsRanging::valid) .def_readwrite("col_cost_up", &HighsRanging::col_cost_up) @@ -1404,11 +1404,11 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .def_readwrite("col_bound_dn", &HighsRanging::col_bound_dn) .def_readwrite("row_bound_up", &HighsRanging::row_bound_up) .def_readwrite("row_bound_dn", &HighsRanging::row_bound_dn); - py::class_(m, "HighsIisInfo") + py::class_(m, "HighsIisInfo", py::module_local()) .def(py::init<>()) .def_readwrite("simplex_time", &HighsIisInfo::simplex_time) .def_readwrite("simplex_iterations", &HighsIisInfo::simplex_iterations); - py::class_(m, "HighsLinearObjective") + py::class_(m, "HighsLinearObjective", py::module_local()) .def(py::init<>()) .def_readwrite("weight", &HighsLinearObjective::weight) .def_readwrite("offset", &HighsLinearObjective::offset) @@ -1428,7 +1428,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { py::module_ simplex_constants = m.def_submodule("simplex_constants", "Submodule for simplex constants"); - py::enum_(simplex_constants, "SimplexStrategy") + py::enum_(simplex_constants, "SimplexStrategy", py::module_local()) .value("kSimplexStrategyMin", SimplexStrategy::kSimplexStrategyMin) .value("kSimplexStrategyChoose", SimplexStrategy::kSimplexStrategyChoose) .value("kSimplexStrategyDual", SimplexStrategy::kSimplexStrategyDual) @@ -1443,7 +1443,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kSimplexStrategyNum", SimplexStrategy::kSimplexStrategyNum) .export_values(); py::enum_(simplex_constants, - "SimplexUnscaledSolutionStrategy") + "SimplexUnscaledSolutionStrategy", py::module_local()) .value( "kSimplexUnscaledSolutionStrategyMin", SimplexUnscaledSolutionStrategy::kSimplexUnscaledSolutionStrategyMin) @@ -1463,7 +1463,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { "kSimplexUnscaledSolutionStrategyNum", SimplexUnscaledSolutionStrategy::kSimplexUnscaledSolutionStrategyNum) .export_values(); - py::enum_(simplex_constants, "SimplexSolvePhase") + py::enum_(simplex_constants, "SimplexSolvePhase", py::module_local()) .value("kSolvePhaseMin", SimplexSolvePhase::kSolvePhaseMin) .value("kSolvePhaseError", SimplexSolvePhase::kSolvePhaseError) .value("kSolvePhaseExit", SimplexSolvePhase::kSolvePhaseExit) @@ -1479,7 +1479,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kSolvePhaseMax", SimplexSolvePhase::kSolvePhaseMax) .export_values(); py::enum_(simplex_constants, - "SimplexEdgeWeightStrategy") + "SimplexEdgeWeightStrategy", py::module_local()) .value("kSimplexEdgeWeightStrategyMin", SimplexEdgeWeightStrategy::kSimplexEdgeWeightStrategyMin) .value("kSimplexEdgeWeightStrategyChoose", @@ -1493,7 +1493,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kSimplexEdgeWeightStrategyMax", SimplexEdgeWeightStrategy::kSimplexEdgeWeightStrategyMax) .export_values(); - py::enum_(simplex_constants, "SimplexPriceStrategy") + py::enum_(simplex_constants, "SimplexPriceStrategy", py::module_local()) .value("kSimplexPriceStrategyMin", SimplexPriceStrategy::kSimplexPriceStrategyMin) .value("kSimplexPriceStrategyCol", @@ -1508,7 +1508,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { SimplexPriceStrategy::kSimplexPriceStrategyMax) .export_values(); py::enum_( - simplex_constants, "SimplexPivotalRowRefinementStrategy") + simplex_constants, "SimplexPivotalRowRefinementStrategy", py::module_local()) .value("kSimplexInfeasibilityProofRefinementMin", SimplexPivotalRowRefinementStrategy:: kSimplexInfeasibilityProofRefinementMin) @@ -1526,7 +1526,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { kSimplexInfeasibilityProofRefinementMax) .export_values(); py::enum_(simplex_constants, - "SimplexPrimalCorrectionStrategy") + "SimplexPrimalCorrectionStrategy", py::module_local()) .value( "kSimplexPrimalCorrectionStrategyNone", SimplexPrimalCorrectionStrategy::kSimplexPrimalCorrectionStrategyNone) @@ -1537,7 +1537,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { SimplexPrimalCorrectionStrategy:: kSimplexPrimalCorrectionStrategyAlways) .export_values(); - py::enum_(simplex_constants, "SimplexNlaOperation") + py::enum_(simplex_constants, "SimplexNlaOperation", py::module_local()) .value("kSimplexNlaNull", SimplexNlaOperation::kSimplexNlaNull) .value("kSimplexNlaBtranFull", SimplexNlaOperation::kSimplexNlaBtranFull) .value("kSimplexNlaPriceFull", SimplexNlaOperation::kSimplexNlaPriceFull) @@ -1554,14 +1554,14 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kNumSimplexNlaOperation", SimplexNlaOperation::kNumSimplexNlaOperation) .export_values(); - py::enum_(simplex_constants, "EdgeWeightMode") + py::enum_(simplex_constants, "EdgeWeightMode", py::module_local()) .value("kDantzig", EdgeWeightMode::kDantzig) .value("kDevex", EdgeWeightMode::kDevex) .value("kSteepestEdge", EdgeWeightMode::kSteepestEdge) .value("kCount", EdgeWeightMode::kCount); py::module_ callbacks = m.def_submodule("cb", "Callback interface submodule"); // Types for interface - py::enum_(callbacks, "HighsCallbackType") + py::enum_(callbacks, "HighsCallbackType", py::module_local()) .value("kCallbackMin", HighsCallbackType::kCallbackMin) .value("kCallbackLogging", HighsCallbackType::kCallbackLogging) .value("kCallbackSimplexInterrupt", @@ -1580,12 +1580,12 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kNumCallbackType", HighsCallbackType::kNumCallbackType) .export_values(); // Classes - py::class_>(m, "readonly_ptr_wrapper_double") + py::class_>(m, "readonly_ptr_wrapper_double", py::module_local()) .def(py::init()) .def("__getitem__", &readonly_ptr_wrapper::operator[]) .def("__bool__", &readonly_ptr_wrapper::is_valid) .def("to_array", &readonly_ptr_wrapper::to_array); - py::class_(callbacks, "HighsCallbackDataOut") + py::class_(callbacks, "HighsCallbackDataOut", py::module_local()) .def(py::init<>()) .def_readwrite("log_type", &HighsCallbackDataOut::log_type) .def_readwrite("running_time", &HighsCallbackDataOut::running_time) @@ -1607,7 +1607,7 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { [](const HighsCallbackDataOut& self) -> readonly_ptr_wrapper { return readonly_ptr_wrapper(self.mip_solution); }); - py::class_(callbacks, "HighsCallbackDataIn") + py::class_(callbacks, "HighsCallbackDataIn", py::module_local()) .def(py::init<>()) .def_readwrite("user_interrupt", &HighsCallbackDataIn::user_interrupt); } diff --git a/src/lp_data/HighsOptions.h b/src/lp_data/HighsOptions.h index eb315b8bcd..842f432b00 100644 --- a/src/lp_data/HighsOptions.h +++ b/src/lp_data/HighsOptions.h @@ -299,6 +299,8 @@ struct HighsOptionsStruct { double primal_feasibility_tolerance; double dual_feasibility_tolerance; double ipm_optimality_tolerance; + double primal_residual_tolerance; + double dual_residual_tolerance; double objective_bound; double objective_target; HighsInt threads; @@ -390,8 +392,6 @@ struct HighsOptionsStruct { bool less_infeasible_DSE_choose_row; bool use_original_HFactor_logic; bool run_centring; - double primal_residual_tolerance; - double dual_residual_tolerance; HighsInt max_centring_steps; double centring_ratio_tolerance; @@ -452,6 +452,8 @@ struct HighsOptionsStruct { primal_feasibility_tolerance(0.0), dual_feasibility_tolerance(0.0), ipm_optimality_tolerance(0.0), + primal_residual_tolerance(0.0), + dual_residual_tolerance(0.0), objective_bound(0.0), objective_target(0.0), threads(0), @@ -528,8 +530,6 @@ struct HighsOptionsStruct { less_infeasible_DSE_choose_row(false), use_original_HFactor_logic(false), run_centring(false), - primal_residual_tolerance(0.0), - dual_residual_tolerance(0.0), max_centring_steps(0), centring_ratio_tolerance(0.0), icrash(false), @@ -707,6 +707,16 @@ class HighsOptions : public HighsOptionsStruct { &ipm_optimality_tolerance, 1e-12, 1e-8, kHighsInf); records.push_back(record_double); + record_double = new OptionRecordDouble( + "primal_residual_tolerance", "Primal residual tolerance", advanced, + &primal_residual_tolerance, 1e-10, 1e-7, kHighsInf); + records.push_back(record_double); + + record_double = new OptionRecordDouble( + "dual_residual_tolerance", "Dual residual tolerance", advanced, + &dual_residual_tolerance, 1e-10, 1e-7, kHighsInf); + records.push_back(record_double); + record_double = new OptionRecordDouble( "objective_bound", "Objective bound for termination of the dual simplex solver", advanced, @@ -1399,16 +1409,6 @@ class HighsOptions : public HighsOptionsStruct { advanced, ¢ring_ratio_tolerance, 0, 100, kHighsInf); records.push_back(record_double); - record_double = new OptionRecordDouble( - "primal_residual_tolerance", "Primal residual tolerance", advanced, - &primal_residual_tolerance, 1e-10, 1e-7, kHighsInf); - records.push_back(record_double); - - record_double = new OptionRecordDouble( - "dual_residual_tolerance", "Dual residual tolerance", advanced, - &dual_residual_tolerance, 1e-10, 1e-7, kHighsInf); - records.push_back(record_double); - // Set up the log_options aliases log_options.clear(); log_options.log_stream = diff --git a/src/presolve/HPresolve.cpp b/src/presolve/HPresolve.cpp index d7977a0ebb..38e56fc9f0 100644 --- a/src/presolve/HPresolve.cpp +++ b/src/presolve/HPresolve.cpp @@ -2052,14 +2052,17 @@ HPresolve::Result HPresolve::applyConflictGraphSubstitutions( return Result::kOk; } -void HPresolve::storeRow(HighsInt row) { - rowpositions.clear(); +void HPresolve::getRowPositions(HighsInt row, + std::vector& myrowpositions) const { + myrowpositions.clear(); - auto rowVec = getSortedRowVector(row); - for (auto iter = rowVec.begin(); iter != rowVec.end(); ++iter) - rowpositions.push_back(iter.position()); + auto rowvector = getSortedRowVector(row); + for (auto rowiter = rowvector.begin(); rowiter != rowvector.end(); ++rowiter) + myrowpositions.push_back(rowiter.position()); } +void HPresolve::storeRow(HighsInt row) { getRowPositions(row, rowpositions); } + HighsTripletPositionSlice HPresolve::getStoredRow() const { return HighsTripletPositionSlice(Acol.data(), Avalue.data(), rowpositions.data(), rowpositions.size()); @@ -3542,19 +3545,27 @@ HPresolve::Result HPresolve::rowPresolve(HighsPostsolveStack& postsolve_stack, auto strengthenCoefs = [&](HighsCDouble& rhs, HighsInt direction, double maxCoefValue) { - for (const HighsSliceNonzero& nonz : getStoredRow()) { - if (model->integrality_[nonz.index()] == HighsVarType::kContinuous) - continue; - - if (direction * nonz.value() > maxCoefValue + primal_feastol) { - double delta = direction * maxCoefValue - nonz.value(); - addToMatrix(row, nonz.index(), delta); - rhs += delta * model->col_upper_[nonz.index()]; - } else if (direction * nonz.value() < - -maxCoefValue - primal_feastol) { - double delta = -direction * maxCoefValue - nonz.value(); - addToMatrix(row, nonz.index(), delta); - rhs += delta * model->col_lower_[nonz.index()]; + // iterate over non-zero positions instead of iterating over the + // HighsMatrixSlice (provided by HPresolve::getStoredRow) because the + // latter contains pointers to Acol and Avalue that may be invalidated + // if these vectors are reallocated (see std::vector::push_back + // performed in HPresolve::addToMatrix). + for (HighsInt rowiter : rowpositions) { + // get column index and coefficient + HighsInt col = Acol[rowiter]; + double val = Avalue[rowiter]; + + // skip continuous variables + if (model->integrality_[col] == HighsVarType::kContinuous) continue; + + if (direction * val > maxCoefValue + primal_feastol) { + double delta = direction * maxCoefValue - val; + addToMatrix(row, col, delta); + rhs += delta * model->col_upper_[col]; + } else if (direction * val < -maxCoefValue - primal_feastol) { + double delta = -direction * maxCoefValue - val; + addToMatrix(row, col, delta); + rhs += delta * model->col_lower_[col]; } } }; @@ -6128,15 +6139,25 @@ HPresolve::Result HPresolve::detectParallelRowsAndCols( template HPresolve::Result HPresolve::equalityRowAddition( HighsPostsolveStack& postsolve_stack, HighsInt stayrow, HighsInt removerow, - double scale, const HighsMatrixSlice& vector) { - postsolve_stack.equalityRowAddition(removerow, stayrow, scale, vector); - for (const auto& rowNz : vector) { - HighsInt pos = findNonzero(removerow, rowNz.index()); + double scale, const HighsMatrixSlice& rowvector) { + // extract non-zero positions + std::vector stay_rowpositions; + getRowPositions(stayrow, stay_rowpositions); + + // update postsolve information + postsolve_stack.equalityRowAddition(removerow, stayrow, scale, rowvector); + + // iterate over non-zero positions instead of iterating over the + // HighsMatrixSlice because the latter contains pointers to Acol and Avalue + // that may be invalidated if these vectors are reallocated + // (see std::vector::push_back performed in HPresolve::addToMatrix). + for (HighsInt rowiter : stay_rowpositions) { + HighsInt pos = findNonzero(removerow, Acol[rowiter]); if (pos != -1) unlink(pos); // all common nonzeros are cancelled, as the rows are // parallel else // might introduce a singleton - addToMatrix(removerow, rowNz.index(), scale * rowNz.value()); + addToMatrix(removerow, Acol[rowiter], scale * Avalue[rowiter]); } if (model->row_upper_[removerow] != kHighsInf) diff --git a/src/presolve/HPresolve.h b/src/presolve/HPresolve.h index a64bbf07fb..9781e2567b 100644 --- a/src/presolve/HPresolve.h +++ b/src/presolve/HPresolve.h @@ -212,6 +212,9 @@ class HPresolve { void toCSR(std::vector& ARval, std::vector& ARindex, std::vector& ARstart); + void getRowPositions(HighsInt row, + std::vector& myrowpositions) const; + void storeRow(HighsInt row); HighsTripletPositionSlice getStoredRow() const;