diff --git a/.github/workflows/build-python-package.yml b/.github/workflows/build-python-package.yml index 33bd47786f..df73a2e47a 100644 --- a/.github/workflows/build-python-package.yml +++ b/.github/workflows/build-python-package.yml @@ -75,23 +75,23 @@ jobs: python -m pytest build_wheel_linux: - # 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-22.04 + runs-on: ubuntu-24.04 + strategy: + matrix: + python: [3.11] steps: - uses: actions/checkout@v4 - name: Install correct python version uses: actions/setup-python@v5 with: - python-version: '3.10' + python-version: ${{ matrix.python }} - name: Build wheel run: | python3 --version python3 -m pip install cibuildwheel - python3 -m cibuildwheel --only cp310-manylinux_x86_64 $GITHUB_WORKSPACE + python3 -m cibuildwheel --only cp311-manylinux_x86_64 $GITHUB_WORKSPACE - name: Install wheel run: | @@ -102,7 +102,36 @@ jobs: run: | python3 -m pip install pytest python3 -m pytest $GITHUB_WORKSPACE - + + build_wheel_linux_arm: + runs-on: ubuntu-24.04-arm + strategy: + matrix: + python: [3.11] + steps: + - uses: actions/checkout@v4 + + - name: Install python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python }} + + - name: Build wheel + run: | + python3 --version + python3 -m pip install cibuildwheel + python3 -m cibuildwheel --only cp311-manylinux_aarch64 $GITHUB_WORKSPACE + + - name: Install wheel + run: | + ls wheelhouse + python3 -m pip install wheelhouse/*.whl + + - name: Test highspy + run: | + python3 -m pip install pytest + python3 -m pytest $GITHUB_WORKSPACE + # macos 13 is Intel build_wheel_macos_13: runs-on: macos-13 diff --git a/.github/workflows/build-wheels-push.yml b/.github/workflows/build-wheels-push.yml index b38ebd2280..19851951d7 100644 --- a/.github/workflows/build-wheels-push.yml +++ b/.github/workflows/build-wheels-push.yml @@ -43,12 +43,12 @@ jobs: # Github Actions doesn't support pairing matrix values together, let's improvise # https://github.com/github/feedback/discussions/7835#discussioncomment-1769026 buildplat: - - [ubuntu-20.04, manylinux_x86_64] - - [ubuntu-20.04, manylinux_i686] - - [ubuntu-20.04, manylinux_aarch64] - - [ubuntu-20.04, musllinux_x86_64] # No OpenBlas, no test - - [ubuntu-20.04, musllinux_i686] - - [ubuntu-20.04, musllinux_aarch64] + - [ubuntu-24.04, manylinux_x86_64] + - [ubuntu-24.04, manylinux_i686] + - [ubuntu-24.04-arm, manylinux_aarch64] + - [ubuntu-24.04, musllinux_x86_64] # No OpenBlas, no test + - [ubuntu-24.04, musllinux_i686] + - [ubuntu-24.04-arm, musllinux_aarch64] - [macos-13, macosx_x86_64] - [macos-14, macosx_arm64] - [windows-2019, win_amd64] @@ -58,21 +58,7 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up QEMU # Required for aarch64 builds - if: ${{ contains(matrix.buildplat[1], 'aarch64') }} - uses: docker/setup-qemu-action@v3 - with: - platforms: all - - - name: Build wheels (aarch64) - if: ${{ contains(matrix.buildplat[1], 'aarch64') }} - uses: pypa/cibuildwheel@v2.21 - env: - CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }} - CIBW_ARCHS_LINUX: aarch64 - - - name: Build wheels (not aarch64) - if: ${{ !contains(matrix.buildplat[1], 'aarch64') }} + - name: Build wheels uses: pypa/cibuildwheel@v2.21 env: CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }} diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index 25819ad7e0..02ad4908c8 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -32,12 +32,12 @@ jobs: # Github Actions doesn't support pairing matrix values together, let's improvise # https://github.com/github/feedback/discussions/7835#discussioncomment-1769026 buildplat: - - [ubuntu-20.04, manylinux_x86_64] - - [ubuntu-20.04, manylinux_i686] - - [ubuntu-20.04, manylinux_aarch64] - - [ubuntu-20.04, musllinux_x86_64] # No OpenBlas, no test - - [ubuntu-20.04, musllinux_i686] - - [ubuntu-20.04, musllinux_aarch64] + - [ubuntu-24.04, manylinux_x86_64] + - [ubuntu-24.04, manylinux_i686] + - [ubuntu-24.04-arm, manylinux_aarch64] + - [ubuntu-24.04, musllinux_x86_64] # No OpenBlas, no test + - [ubuntu-24.04, musllinux_i686] + - [ubuntu-24.04-arm, musllinux_aarch64] - [macos-13, macosx_x86_64] - [macos-14, macosx_arm64] - [windows-2019, win_amd64] @@ -46,21 +46,7 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up QEMU # Required for aarch64 builds - if: ${{ contains(matrix.buildplat[1], 'aarch64') }} - uses: docker/setup-qemu-action@v3 - with: - platforms: all - - - name: Build wheels (aarch64) - if: ${{ contains(matrix.buildplat[1], 'aarch64') }} - uses: pypa/cibuildwheel@v2.21 - env: - CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }} - CIBW_ARCHS_LINUX: aarch64 - - - name: Build wheels (not aarch64) - if: ${{ !contains(matrix.buildplat[1], 'aarch64') }} + - name: Build wheels uses: pypa/cibuildwheel@v2.21 env: CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }} diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index e4540f2173..ab8d51dc6d 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -1,6 +1,6 @@ name: code-coverage -on: [push, pull_request] +on: [pull_request] jobs: debug: @@ -47,21 +47,22 @@ jobs: lcov --remove cov.info "app/cxxopts*" -o cov.info lcov --remove cov.info "src/test*" -o cov.info lcov --list cov.info + mv cov.info coverage.info - name: Genhtml Results Summary working-directory: ${{runner.workspace}}/build shell: bash run: | - genhtml -o coverage cov.info + genhtml -o coverage coverage.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) + - 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/coverage.info # optional + # name: codecov-umbrella # optional + verbose: true # optional (default = false) \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index db47e76f15..f10017e576 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -363,8 +363,8 @@ if(NOT FAST_BUILD) endif() include(CheckCXXCompilerFlag) -if (NOT HIGHS_COVERAGE) - if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(ppc64|powerpc64)" AND NOT APPLE) +if (NOT HIGHS_COVERAGE AND NOT APPLE) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(ppc64|powerpc64)") check_cxx_compiler_flag("-mpopcntd" COMPILER_SUPPORTS_POPCNTD) if(COMPILER_SUPPORTS_POPCNTD) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mpopcntd") @@ -372,7 +372,7 @@ if (NOT HIGHS_COVERAGE) else() check_cxx_compiler_flag("-mpopcnt" COMPILER_SUPPORTS_POPCNT) if(COMPILER_SUPPORTS_POPCNT) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mpopcnt") + add_compile_options(-mpopcnt) endif() endif() endif() diff --git a/check/TestFilereader.cpp b/check/TestFilereader.cpp index 63fe50e8a2..e08eced444 100644 --- a/check/TestFilereader.cpp +++ b/check/TestFilereader.cpp @@ -416,3 +416,26 @@ TEST_CASE("writeLocalModel", "[highs_filereader]") { std::remove(write_model_file.c_str()); } + +TEST_CASE("write-MI-bound-model", "[highs_filereader]") { + std::string write_model_file = "temp.mps"; + Highs h; + h.setOptionValue("output_flag", dev_run); + h.addCol(1, -kHighsInf, 1, 0, nullptr, nullptr); + h.changeColIntegrality(0, HighsVarType::kInteger); + h.passColName(0, "x"); + std::vector index = {0}; + std::vector value = {1}; + h.addRow(-10, kHighsInf, 1, index.data(), value.data()); + h.passRowName(0, "r"); + h.run(); + double required_objective_value = h.getInfo().objective_function_value; + // writeModel must ensure that there is a line + // + // MI BOUND x + h.writeModel(write_model_file); + h.readModel(write_model_file); + h.run(); + REQUIRE(required_objective_value == h.getInfo().objective_function_value); + std::remove(write_model_file.c_str()); +} diff --git a/check/TestMipSolver.cpp b/check/TestMipSolver.cpp index ecb3502316..080f3d124b 100644 --- a/check/TestMipSolver.cpp +++ b/check/TestMipSolver.cpp @@ -701,7 +701,7 @@ TEST_CASE("IP-with-fract-bounds-no-presolve", "[highs_test_mip_solver]") { Highs highs; // No presolve highs.setOptionValue("output_flag", dev_run); - highs.setOptionValue("presolve", "off"); + highs.setOptionValue("presolve", kHighsOffString); // IP without constraints and fractional bounds on variables HighsLp lp; @@ -772,7 +772,7 @@ void distillationMIP(Highs& highs) { special_lps.distillationMip(lp, require_model_status, optimal_objective); REQUIRE(highs.passModel(lp) == HighsStatus::kOk); // Presolve doesn't reduce the LP - solve(highs, "on", require_model_status, optimal_objective); + solve(highs, kHighsOnString, require_model_status, optimal_objective); } void rowlessMIP(Highs& highs) { @@ -793,6 +793,17 @@ void rowlessMIP(Highs& highs) { optimal_objective = -1.0; REQUIRE(highs.passModel(lp) == HighsStatus::kOk); // Presolve reduces the LP to empty - solve(highs, "on", require_model_status, optimal_objective); - solve(highs, "off", require_model_status, optimal_objective); + solve(highs, kHighsOnString, require_model_status, optimal_objective); + solve(highs, kHighsOffString, require_model_status, optimal_objective); +} + +TEST_CASE("issue-2122", "[highs_test_mip_solver]") { + std::string filename = std::string(HIGHS_DIR) + "/check/instances/2122.lp"; + Highs highs; + highs.setOptionValue("mip_rel_gap", 0); + highs.setOptionValue("mip_abs_gap", 0); + highs.readModel(filename); + const HighsModelStatus require_model_status = HighsModelStatus::kOptimal; + const double optimal_objective = -187612.944194; + solve(highs, kHighsOnString, require_model_status, optimal_objective); } diff --git a/check/instances/2122.lp b/check/instances/2122.lp new file mode 100644 index 0000000000..e408f2da38 --- /dev/null +++ b/check/instances/2122.lp @@ -0,0 +1,1822 @@ +\ File written by HiGHS .lp file handler +max + obj: -1050.09490748148 x1 +0.077 x2 +0.068 x3 +0.05912 x4 +0.07261 x5 +0.05721 x6 +0.05509 x7 +0.05085 x8 +0.05085 x9 +0.06442 x10 +0.07947 x11 +0.08693 x12 +0.09921 x13 +0.09671 x14 +0.10135 x15 +0.09307 x16 +0.08284 x17 +0.07707 x18 +0.05433 x19 +0.07567 x20 +0.03881 x21 +0.06258 x22 +0.02425 x23 +0.04996 x24 +0.02532 x25 -0.077 x26 -0.068 x27 -0.05912 x28 -0.07261 x29 -0.05721 x30 -0.05509 x31 -0.05085 x32 -0.05085 x33 -0.06442 x34 -0.07947 x35 -0.08693 x36 -0.09921 x37 -0.09671 x38 -0.10135 x39 -0.09307 x40 -0.08284 x41 -0.07707 x42 -0.05433 x43 + -0.07567 x44 -0.03881 x45 -0.06258 x46 -0.02425 x47 -0.04996 x48 -0.02532 x49 +0.02532 x50 -0.02532 x51 -0.00042330288 x52 -0.00042330288 x53 -0.00042330288 x54 -0.00042330288 x55 -0.00042330288 x56 -0.00042330288 x57 -0.00042330288 x58 -0.00042330288 x59 -0.00042330288 x60 -0.00042330288 x61 -0.00042330288 x62 -0.00042330288 x63 -0.00042330288 x64 -0.00042330288 x65 -0.00042330288 x66 -0.00042330288 x67 -0.00042330288 x68 -0.00042330288 x69 -0.00042330288 x70 -0.00042330288 x71 -0.00042330288 x72 -0.00042330288 x73 -0.00042330288 x74 -0.00042330288 + x75 -0.00042330288 x76 -0.00042330288 x77 -0.00042330288 x78 -10 x79 -10 x80 -10 x81 -10 x82 -10 x83 -10 x84 -10 x85 -10 x86 -10 x87 -10 x88 -10 x89 -10 x90 -10 x91 -10 x92 -10 x93 -10 x94 -10 x95 -10 x96 -10 x97 -10 x98 -10 x99 -10 x100 -10 x101 -10 x102 -10 x103 -10 x104 -10 x105 -10 x106 -10 x107 -10 x108 -10 x109 -10 x110 -10 x111 -10 x112 -10 x113 -10 x114 -10 x115 -10 x116 -10 x117 -10 x118 -10 x119 -10 x120 -10 x121 -10 x122 -10 x123 -10 x124 -10 x125 -10 x126 -10 x127 -10 x128 -10 x129 -10 x130 -10 x131 -10 x132 -10 x133 -10 x134 -0.01 x135 + -0.01 x136 -0.01 x137 -0.01 x138 -0.01 x139 -0.01 x140 -0.01 x141 -0.01 x142 -0.01 x143 -0.01 x144 -0.01 x145 -0.01 x146 -0.01 x147 -0.01 x148 -0.01 x149 -0.01 x150 -0.01 x151 -0.01 x152 -0.01 x153 -0.01 x154 -0.01 x155 -0.01 x156 -0.01 x157 -0.01 x158 +st + con1: +1 x159 -0.5 x160 -0.00833333333333333 x161 +0.00833333333333333 x162 +0.00833333333333333 x163 = +0 + con2: +1 x164 -0.5 x165 -0.00833333333333333 x166 +0.00833333333333333 x167 +0.00833333333333333 x168 = +0 + con3: +1 x169 -0.5 x170 +0.00833333333333333 x171 +0.00833333333333333 x172 = +0 + con4: +1 x173 -0.5 x174 +0.00833333333333333 x175 +0.00833333333333333 x176 = +0 + con5: +1 x177 -0.5 x178 +0.00833333333333333 x179 +0.00833333333333333 x180 = +0 + con6: +1 x181 -0.5 x182 +0.00833333333333333 x183 +0.00833333333333333 x184 = +0 + con7: +1 x185 -0.5 x186 +0.00833333333333333 x187 +0.00833333333333333 x188 = +0 + con8: +1 x189 -0.5 x190 +0.00833333333333333 x191 +0.00833333333333333 x192 = +0 + con9: +1 x193 -0.5 x194 +0.00833333333333333 x195 +0.00833333333333333 x196 = +0 + con10: +1 x197 -0.5 x198 +0.00833333333333333 x199 +0.00833333333333333 x200 = +0 + con11: +1 x201 -0.5 x202 +0.00833333333333333 x203 +0.00833333333333333 x204 = +0 + con12: +1 x205 -0.5 x206 +0.00833333333333333 x207 +0.00833333333333333 x208 = +0 + con13: +1 x209 -0.5 x210 +0.00833333333333333 x211 +0.00833333333333333 x212 = +0 + con14: +1 x213 -0.5 x214 +0.00833333333333333 x215 +0.00833333333333333 x216 = +0 + con15: +1 x217 -0.5 x218 +0.00833333333333333 x219 +0.00833333333333333 x220 = +0 + con16: +1 x221 -0.5 x222 +0.00833333333333333 x223 +0.00833333333333333 x224 = +0 + con17: +1 x225 -0.5 x226 +0.00833333333333333 x227 +0.00833333333333333 x228 = +0 + con18: +1 x229 -0.5 x230 +0.00833333333333333 x231 +0.00833333333333333 x232 = +0 + con19: +1 x233 -0.5 x234 +0.00833333333333333 x235 +0.00833333333333333 x236 = +0 + con20: +1 x237 -0.5 x238 +0.00833333333333333 x239 +0.00833333333333333 x240 = +0 + con21: +1 x241 -0.5 x242 +0.00833333333333333 x243 +0.00833333333333333 x244 = +0 + con22: +1 x245 -0.5 x246 +0.00833333333333333 x247 +0.00833333333333333 x248 = +0 + con23: +1 x249 -0.5 x250 +0.00833333333333333 x251 +0.00833333333333333 x252 = +0 + con24: +1 x253 -0.5 x254 +0.00833333333333333 x255 +0.00833333333333333 x256 = +0 + con25: -12000 x257 <= -12000 + con26: +8000 x257 <= +8000 + con27: +1 x160 -12000 x258 <= +0 + con28: +1 x165 +7000 x258 <= +7000 + con29: +1 x170 -12000 x259 <= +0 + con30: +1 x174 +7000 x259 <= +7000 + con31: +1 x178 -12000 x260 <= +0 + con32: +1 x182 +7000 x260 <= +7000 + con33: +1 x186 -12000 x261 <= +0 + con34: +1 x190 +7000 x261 <= +7000 + con35: +1 x194 -12000 x262 <= +0 + con36: +1 x198 +7000 x262 <= +7000 + con37: +1 x202 -12000 x263 <= +0 + con38: +1 x206 +7000 x263 <= +7000 + con39: +1 x210 -12000 x264 <= +0 + con40: +1 x214 +7000 x264 <= +7000 + con41: +1 x218 -12000 x265 <= +0 + con42: +1 x222 +7000 x265 <= +7000 + con43: +1 x226 -12000 x266 <= +0 + con44: +1 x230 +8000 x266 <= +8000 + con45: +1 x234 -12000 x267 <= +0 + con46: +1 x238 +8000 x267 <= +8000 + con47: +1 x242 -12000 x268 <= +0 + con48: +1 x246 +8000 x268 <= +8000 + con49: +1 x250 -12000 x269 <= +0 + con50: +1 x254 +8000 x269 <= +8000 + con51: +1 x270 -12000 x271 <= +0 + con52: +8000 x271 +1 x272 <= +8000 + con53: +1 x163 -12000 x273 <= +0 + con54: +1 x161 +12000 x273 <= +12000 + con55: +1 x168 -8000 x274 <= +0 + con56: +1 x166 +8000 x274 <= +8000 + con57: +1 x172 -12000 x275 <= +0 + con58: +1 x162 +12000 x275 <= +12000 + con59: +1 x176 -7000 x276 <= +0 + con60: +1 x167 +7000 x276 <= +7000 + con61: +1 x180 -12000 x277 <= +0 + con62: +1 x171 +12000 x277 <= +12000 + con63: +1 x184 -7000 x278 <= +0 + con64: +1 x175 +7000 x278 <= +7000 + con65: +1 x188 -12000 x279 <= +0 + con66: +1 x179 +12000 x279 <= +12000 + con67: +1 x192 -7000 x280 <= +0 + con68: +1 x183 +7000 x280 <= +7000 + con69: +1 x196 -12000 x281 <= +0 + con70: +1 x187 +12000 x281 <= +12000 + con71: +1 x200 -7000 x282 <= +0 + con72: +1 x191 +7000 x282 <= +7000 + con73: +1 x204 -12000 x283 <= +0 + con74: +1 x195 +12000 x283 <= +12000 + con75: +1 x208 -7000 x284 <= +0 + con76: +1 x199 +7000 x284 <= +7000 + con77: +1 x212 -12000 x285 <= +0 + con78: +1 x203 +12000 x285 <= +12000 + con79: +1 x216 -7000 x286 <= +0 + con80: +1 x207 +7000 x286 <= +7000 + con81: +1 x220 -12000 x287 <= +0 + con82: +1 x211 +12000 x287 <= +12000 + con83: +1 x224 -7000 x288 <= +0 + con84: +1 x215 +7000 x288 <= +7000 + con85: +1 x228 -12000 x289 <= +0 + con86: +1 x219 +12000 x289 <= +12000 + con87: +1 x232 -8000 x290 <= +0 + con88: +1 x223 +8000 x290 <= +8000 + con89: +1 x236 -12000 x291 <= +0 + con90: +1 x227 +12000 x291 <= +12000 + con91: +1 x240 -8000 x292 <= +0 + con92: +1 x231 +8000 x292 <= +8000 + con93: +1 x244 -12000 x293 <= +0 + con94: +1 x235 +12000 x293 <= +12000 + con95: +1 x248 -8000 x294 <= +0 + con96: +1 x239 +8000 x294 <= +8000 + con97: +1 x252 -12000 x295 <= +0 + con98: +1 x243 +12000 x295 <= +12000 + con99: +1 x256 -8000 x296 <= +0 + con100: +1 x247 +8000 x296 <= +8000 + con101: -12000 x297 <= +0 + con102: +1 x251 +12000 x297 <= +12000 + con103: -8000 x298 <= +0 + con104: +1 x255 +8000 x298 <= +8000 + con105: +1 x160 +1 x161 -1 x163 = +12000 + con106: +1 x165 +1 x166 -1 x168 = +0 + con107: -1 x160 +1 x162 +1 x170 -1 x172 = +0 + con108: -1 x165 +1 x167 +1 x174 -1 x176 = +0 + con109: -1 x170 +1 x171 +1 x178 -1 x180 = +0 + con110: -1 x174 +1 x175 +1 x182 -1 x184 = +0 + con111: -1 x178 +1 x179 +1 x186 -1 x188 = +0 + con112: -1 x182 +1 x183 +1 x190 -1 x192 = +0 + con113: -1 x186 +1 x187 +1 x194 -1 x196 = +0 + con114: -1 x190 +1 x191 +1 x198 -1 x200 = +0 + con115: -1 x194 +1 x195 +1 x202 -1 x204 = +0 + con116: -1 x198 +1 x199 +1 x206 -1 x208 = +0 + con117: -1 x202 +1 x203 +1 x210 -1 x212 = +0 + con118: -1 x206 +1 x207 +1 x214 -1 x216 = +0 + con119: -1 x210 +1 x211 +1 x218 -1 x220 = +0 + con120: -1 x214 +1 x215 +1 x222 -1 x224 = +0 + con121: -1 x218 +1 x219 +1 x226 -1 x228 = +0 + con122: -1 x222 +1 x223 +1 x230 -1 x232 = +0 + con123: -1 x226 +1 x227 +1 x234 -1 x236 = +0 + con124: -1 x230 +1 x231 +1 x238 -1 x240 = +0 + con125: -1 x234 +1 x235 +1 x242 -1 x244 = +0 + con126: -1 x238 +1 x239 +1 x246 -1 x248 = +0 + con127: -1 x242 +1 x243 +1 x250 -1 x252 = +0 + con128: -1 x246 +1 x247 +1 x254 -1 x256 = +0 + con129: -1 x250 +1 x251 +1 x270 = +0 + con130: -1 x254 +1 x255 +1 x272 = +0 + con131: -1000 x299 = -12000 + con132: -1000 x300 = +0 + con133: +1 x160 -1000 x301 = +0 + con134: +1 x165 -1000 x302 = +0 + con135: +1 x170 -1000 x303 = +0 + con136: +1 x174 -1000 x304 = +0 + con137: +1 x178 -1000 x305 = +0 + con138: +1 x182 -1000 x306 = +0 + con139: +1 x186 -1000 x307 = +0 + con140: +1 x190 -1000 x308 = +0 + con141: +1 x194 -1000 x309 = +0 + con142: +1 x198 -1000 x310 = +0 + con143: +1 x202 -1000 x311 = +0 + con144: +1 x206 -1000 x312 = +0 + con145: +1 x210 -1000 x313 = +0 + con146: +1 x214 -1000 x314 = +0 + con147: +1 x218 -1000 x315 = +0 + con148: +1 x222 -1000 x316 = +0 + con149: +1 x226 -1000 x317 = +0 + con150: +1 x230 -1000 x318 = +0 + con151: +1 x234 -1000 x319 = +0 + con152: +1 x238 -1000 x320 = +0 + con153: +1 x242 -1000 x321 = +0 + con154: +1 x246 -1000 x322 = +0 + con155: +1 x250 -1000 x323 = +0 + con156: +1 x254 -1000 x324 = +0 + con157: +1 x270 -1000 x325 = +0 + con158: +1 x272 -1000 x326 = +0 + con159: +1 x160 +1 x161 <= +12000 + con160: +1 x165 +1 x166 <= +7000 + con161: -1 x257 +1 x258 = +0 + con162: +1 x327 -1 x328 = -222.34033333 + con163: +1 x329 -1 x330 = +4423.87633333333 + con164: +1 x331 -1 x332 = +4490.543 + con165: +1 x135 +1 x333 -1 x334 -1 x335 = -1583.939 + con166: +1 x136 +1 x336 -1 x337 -1 x338 = -1583.939 + con167: +1 x137 +1 x339 -1 x340 -1 x341 = -1583.939 + con168: +1 x138 +1 x342 -1 x343 -1 x344 = -1583.939 + con169: +1 x139 +1 x345 -1 x346 -1 x347 = -1583.939 + con170: +1 x140 +1 x348 -1 x349 -1 x350 = -1583.939 + con171: +1 x141 +1 x351 -1 x352 -1 x353 = -1583.939 + con172: +1 x142 +1 x354 -1 x355 -1 x356 = -1583.939 + con173: +1 x143 +1 x357 -1 x358 -1 x359 = -1509.457 + con174: +1 x144 +1 x360 -1 x361 -1 x362 = -1509.457 + con175: +1 x145 +1 x363 -1 x364 -1 x365 = -1509.457 + con176: +1 x146 +1 x366 -1 x367 -1 x368 = -1509.457 + con177: +1 x147 +1 x369 -1 x370 -1 x371 = -1509.457 + con178: +1 x148 +1 x372 -1 x373 -1 x374 = -1509.457 + con179: +1 x149 +1 x375 -1 x376 -1 x377 = -1509.457 + con180: +1 x150 +1 x378 -1 x379 -1 x380 = -1509.457 + con181: +1 x151 +1 x381 -1 x382 -1 x383 = -1583.939 + con182: +1 x152 +1 x384 -1 x385 -1 x386 = -1583.939 + con183: +1 x153 +1 x387 -1 x388 -1 x389 = -1583.939 + con184: +1 x154 +1 x390 -1 x391 -1 x392 = -1583.939 + con185: +1 x155 +1 x393 -1 x394 -1 x395 = -1583.939 + con186: +1 x156 +1 x396 -1 x397 -1 x398 = -1583.939 + con187: +1 x157 +1 x399 -1 x400 -1 x401 = -1583.939 + con188: +1 x158 +1 x402 -1 x403 -1 x404 = -1583.939 + con189: -17400 x405 <= -1491.66666667 + con190: +17400 x405 <= +17400 + con191: -29000 x406 <= -5933.33333333333 + con192: +29000 x406 <= +29000 + con193: -29000 x407 <= -6000 + con194: +29000 x407 <= +29000 + con195: +1 x335 -29000 x408 <= +0 + con196: +1 x135 +29000 x408 <= +29000 + con197: +1 x338 -29000 x409 <= +0 + con198: +1 x136 +29000 x409 <= +29000 + con199: +1 x341 -29000 x410 <= +0 + con200: +1 x137 +29000 x410 <= +29000 + con201: +1 x344 -29000 x411 <= +0 + con202: +1 x138 +29000 x411 <= +29000 + con203: +1 x347 -29000 x412 <= +0 + con204: +1 x139 +29000 x412 <= +29000 + con205: +1 x350 -29000 x413 <= +0 + con206: +1 x140 +29000 x413 <= +29000 + con207: +1 x353 -29000 x414 <= +0 + con208: +1 x141 +29000 x414 <= +29000 + con209: +1 x356 -29000 x415 <= +0 + con210: +1 x142 +29000 x415 <= +29000 + con211: +1 x359 -29000 x416 <= +0 + con212: +1 x143 +29000 x416 <= +29000 + con213: +1 x362 -29000 x417 <= +0 + con214: +1 x144 +29000 x417 <= +29000 + con215: +1 x365 -29000 x418 <= +0 + con216: +1 x145 +29000 x418 <= +29000 + con217: +1 x368 -29000 x419 <= +0 + con218: +1 x146 +29000 x419 <= +29000 + con219: +1 x371 -29000 x420 <= +0 + con220: +1 x147 +29000 x420 <= +29000 + con221: +1 x374 -29000 x421 <= +0 + con222: +1 x148 +29000 x421 <= +29000 + con223: +1 x377 -29000 x422 <= +0 + con224: +1 x149 +29000 x422 <= +29000 + con225: +1 x380 -29000 x423 <= +0 + con226: +1 x150 +29000 x423 <= +29000 + con227: +1 x383 -29000 x424 <= +0 + con228: +1 x151 +29000 x424 <= +29000 + con229: +1 x386 -29000 x425 <= +0 + con230: +1 x152 +29000 x425 <= +29000 + con231: +1 x389 -29000 x426 <= +0 + con232: +1 x153 +29000 x426 <= +29000 + con233: +1 x392 -29000 x427 <= +0 + con234: +1 x154 +29000 x427 <= +29000 + con235: +1 x395 -29000 x428 <= +0 + con236: +1 x155 +29000 x428 <= +29000 + con237: +1 x398 -29000 x429 <= +0 + con238: +1 x156 +29000 x429 <= +29000 + con239: +1 x401 -29000 x430 <= +0 + con240: +1 x157 +29000 x430 <= +29000 + con241: +1 x404 -29000 x431 <= +0 + con242: +1 x158 +29000 x431 <= +29000 + con243: -0.9 x327 +1 x432 = +0 + con244: +1 x328 -1 x433 = +0 + con245: -0.9 x329 +1 x434 = +0 + con246: +1 x330 -1 x435 = +0 + con247: -0.9 x331 +1 x436 = +0 + con248: +1 x332 -1 x437 = +0 + con249: -0.9 x333 +1 x438 = +0 + con250: +1 x334 -1 x439 = +0 + con251: -0.9 x336 +1 x440 = +0 + con252: +1 x337 -1 x441 = +0 + con253: -0.9 x339 +1 x442 = +0 + con254: +1 x340 -1 x443 = +0 + con255: -0.9 x342 +1 x444 = +0 + con256: +1 x343 -1 x445 = +0 + con257: -0.9 x345 +1 x446 = +0 + con258: +1 x346 -1 x447 = +0 + con259: -0.9 x348 +1 x448 = +0 + con260: +1 x349 -1 x449 = +0 + con261: -0.9 x351 +1 x450 = +0 + con262: +1 x352 -1 x451 = +0 + con263: -0.9 x354 +1 x452 = +0 + con264: +1 x355 -1 x453 = +0 + con265: -0.9 x357 +1 x454 = +0 + con266: +1 x358 -1 x455 = +0 + con267: -0.9 x360 +1 x456 = +0 + con268: +1 x361 -1 x457 = +0 + con269: -0.9 x363 +1 x458 = +0 + con270: +1 x364 -1 x459 = +0 + con271: -0.9 x366 +1 x460 = +0 + con272: +1 x367 -1 x461 = +0 + con273: -0.9 x369 +1 x462 = +0 + con274: +1 x370 -1 x463 = +0 + con275: -0.9 x372 +1 x464 = +0 + con276: +1 x373 -1 x465 = +0 + con277: -0.9 x375 +1 x466 = +0 + con278: +1 x376 -1 x467 = +0 + con279: -0.9 x378 +1 x468 = +0 + con280: +1 x379 -1 x469 = +0 + con281: -0.9 x381 +1 x470 = +0 + con282: +1 x382 -1 x471 = +0 + con283: -0.9 x384 +1 x472 = +0 + con284: +1 x385 -1 x473 = +0 + con285: -0.9 x387 +1 x474 = +0 + con286: +1 x388 -1 x475 = +0 + con287: -0.9 x390 +1 x476 = +0 + con288: +1 x391 -1 x477 = +0 + con289: -0.9 x393 +1 x478 = +0 + con290: +1 x394 -1 x479 = +0 + con291: -0.9 x396 +1 x480 = +0 + con292: +1 x397 -1 x481 = +0 + con293: -0.9 x399 +1 x482 = +0 + con294: +1 x400 -1 x483 = +0 + con295: -0.9 x402 +1 x484 = +0 + con296: +1 x403 -1 x485 = +0 + con297: -1 x135 -1 x159 +1 x164 +1 x335 = +0 + con298: -1 x136 -1 x169 +1 x173 +1 x338 = +0 + con299: -1 x137 -1 x177 +1 x181 +1 x341 = +0 + con300: -1 x138 -1 x185 +1 x189 +1 x344 = +0 + con301: -1 x139 -1 x193 +1 x197 +1 x347 = +0 + con302: -1 x140 -1 x201 +1 x205 +1 x350 = +0 + con303: -1 x141 -1 x209 +1 x213 +1 x353 = +0 + con304: -1 x142 -1 x217 +1 x221 +1 x356 = +0 + con305: -1 x143 -1 x225 +1 x229 +1 x359 = +0 + con306: -1 x144 -1 x233 +1 x237 +1 x362 = +0 + con307: -1 x145 -1 x241 +1 x245 +1 x365 = +0 + con308: -1 x146 -1 x249 +1 x253 +1 x368 = +0 + con309: +1 x486 = +0 + con310: +1 x487 = +0 + con311: +1 x488 = +0 + con312: +1 x489 = +0 + con313: +1 x490 = +0 + con314: +1 x491 = +0 + con315: +1 x492 = +0 + con316: +1 x493 = +0 + con317: +1 x494 = +0 + con318: +1 x495 = +0 + con319: +1 x496 = +0 + con320: +1 x497 = +0 + con321: +1 x498 = +0 + con322: +1 x499 = +0 + con323: +1 x500 = +0 + con324: +1 x501 = +0 + con325: +1 x502 = +0 + con326: +1 x503 = +0 + con327: +1 x504 = +0 + con328: +1 x505 = +0 + con329: +1 x506 = +0 + con330: +1 x507 = +0 + con331: +1 x508 = +0 + con332: +1 x509 = +0 + con333: +1 x510 = +0 + con334: +1 x511 = +0 + con335: +1 x512 = +0 + con336: +1 x513 = +0 + con337: +1 x514 = +0 + con338: +1 x515 = +0 + con339: +1 x516 = +0 + con340: +1 x517 = +0 + con341: +1 x518 = +0 + con342: +1 x519 = +0 + con343: +1 x520 = +0 + con344: +1 x521 = +0 + con345: +1 x522 = +0 + con346: +1 x523 = +0 + con347: +1 x524 = +0 + con348: +1 x525 = +0 + con349: +1 x526 = +0 + con350: +1 x527 = +0 + con351: +1 x528 = +0 + con352: +1 x529 = +0 + con353: +1 x530 = +0 + con354: +1 x531 = +0 + con355: +1 x532 = +0 + con356: +1 x533 = +0 + con357: +1 x534 = +0 + con358: +1 x535 = +0 + con359: +1 x536 = +0 + con360: +1 x537 = +0 + con361: +1 x538 = +0 + con362: +1 x539 = +0 + con363: +1 x327 <= +8700 + con364: +1 x329 <= +14500 + con365: +1 x331 <= +14500 + con366: +1 x333 <= +14500 + con367: +1 x336 <= +14500 + con368: +1 x339 <= +14500 + con369: +1 x342 <= +14500 + con370: +1 x345 <= +14500 + con371: +1 x348 <= +14500 + con372: +1 x351 <= +14500 + con373: +1 x354 <= +14500 + con374: +1 x357 <= +14500 + con375: +1 x360 <= +14500 + con376: +1 x363 <= +14500 + con377: +1 x366 <= +14500 + con378: +1 x369 <= +14500 + con379: +1 x372 <= +14500 + con380: +1 x375 <= +14500 + con381: +1 x378 <= +14500 + con382: +1 x381 <= +14500 + con383: +1 x384 <= +14500 + con384: +1 x387 <= +14500 + con385: +1 x390 <= +14500 + con386: +1 x393 <= +14500 + con387: +1 x396 <= +14500 + con388: +1 x399 <= +14500 + con389: +1 x402 <= +14500 + con390: +1 x328 <= +8700 + con391: +1 x330 <= +14500 + con392: +1 x332 <= +14500 + con393: +1 x334 <= +14500 + con394: +1 x337 <= +14500 + con395: +1 x340 <= +14500 + con396: +1 x343 <= +14500 + con397: +1 x346 <= +14500 + con398: +1 x349 <= +14500 + con399: +1 x352 <= +14500 + con400: +1 x355 <= +14500 + con401: +1 x358 <= +14500 + con402: +1 x361 <= +14500 + con403: +1 x364 <= +14500 + con404: +1 x367 <= +14500 + con405: +1 x370 <= +14500 + con406: +1 x373 <= +14500 + con407: +1 x376 <= +14500 + con408: +1 x379 <= +14500 + con409: +1 x382 <= +14500 + con410: +1 x385 <= +14500 + con411: +1 x388 <= +14500 + con412: +1 x391 <= +14500 + con413: +1 x394 <= +14500 + con414: +1 x397 <= +14500 + con415: +1 x400 <= +14500 + con416: +1 x403 <= +14500 + con417: +1 x327 -14501 x540 <= +0 + con418: +1 x328 +14501 x540 <= +14501 + con419: +1 x329 -14501 x541 <= +0 + con420: +1 x330 +14501 x541 <= +14501 + con421: +1 x331 -14501 x542 <= +0 + con422: +1 x332 +14501 x542 <= +14501 + con423: +1 x333 -14501 x543 <= +0 + con424: +1 x334 +14501 x543 <= +14501 + con425: +1 x336 -14501 x544 <= +0 + con426: +1 x337 +14501 x544 <= +14501 + con427: +1 x339 -14501 x545 <= +0 + con428: +1 x340 +14501 x545 <= +14501 + con429: +1 x342 -14501 x546 <= +0 + con430: +1 x343 +14501 x546 <= +14501 + con431: +1 x345 -14501 x547 <= +0 + con432: +1 x346 +14501 x547 <= +14501 + con433: +1 x348 -14501 x548 <= +0 + con434: +1 x349 +14501 x548 <= +14501 + con435: +1 x351 -14501 x549 <= +0 + con436: +1 x352 +14501 x549 <= +14501 + con437: +1 x354 -14501 x550 <= +0 + con438: +1 x355 +14501 x550 <= +14501 + con439: +1 x357 -14501 x551 <= +0 + con440: +1 x358 +14501 x551 <= +14501 + con441: +1 x360 -14501 x552 <= +0 + con442: +1 x361 +14501 x552 <= +14501 + con443: +1 x363 -14501 x553 <= +0 + con444: +1 x364 +14501 x553 <= +14501 + con445: +1 x366 -14501 x554 <= +0 + con446: +1 x367 +14501 x554 <= +14501 + con447: +1 x369 -14501 x555 <= +0 + con448: +1 x370 +14501 x555 <= +14501 + con449: +1 x372 -14501 x556 <= +0 + con450: +1 x373 +14501 x556 <= +14501 + con451: +1 x375 -14501 x557 <= +0 + con452: +1 x376 +14501 x557 <= +14501 + con453: +1 x378 -14501 x558 <= +0 + con454: +1 x379 +14501 x558 <= +14501 + con455: +1 x381 -14501 x559 <= +0 + con456: +1 x382 +14501 x559 <= +14501 + con457: +1 x384 -14501 x560 <= +0 + con458: +1 x385 +14501 x560 <= +14501 + con459: +1 x387 -14501 x561 <= +0 + con460: +1 x388 +14501 x561 <= +14501 + con461: +1 x390 -14501 x562 <= +0 + con462: +1 x391 +14501 x562 <= +14501 + con463: +1 x393 -14501 x563 <= +0 + con464: +1 x394 +14501 x563 <= +14501 + con465: +1 x396 -14501 x564 <= +0 + con466: +1 x397 +14501 x564 <= +14501 + con467: +1 x399 -14501 x565 <= +0 + con468: +1 x400 +14501 x565 <= +14501 + con469: +1 x402 -14501 x566 <= +0 + con470: +1 x403 +14501 x566 <= +14501 + con471: -1 x432 +1 x433 +1 x486 +1 x513 +1 x567 = +3776 + con472: -1 x434 +1 x435 +1 x487 +1 x514 -1 x567 +1 x568 = +0 + con473: -1 x436 +1 x437 +1 x488 +1 x515 -1 x568 +1 x569 = +0 + con474: -1 x438 +1 x439 +1 x489 +1 x516 -1 x569 +1 x570 = +0 + con475: -1 x440 +1 x441 +1 x490 +1 x517 -1 x570 +1 x571 = +0 + con476: -1 x442 +1 x443 +1 x491 +1 x518 -1 x571 +1 x572 = +0 + con477: -1 x444 +1 x445 +1 x492 +1 x519 -1 x572 +1 x573 = +0 + con478: -1 x446 +1 x447 +1 x493 +1 x520 -1 x573 +1 x574 = +0 + con479: -1 x448 +1 x449 +1 x494 +1 x521 -1 x574 +1 x575 = +0 + con480: -1 x450 +1 x451 +1 x495 +1 x522 -1 x575 +1 x576 = +0 + con481: -1 x452 +1 x453 +1 x496 +1 x523 -1 x576 +1 x577 = +0 + con482: -1 x454 +1 x455 +1 x497 +1 x524 -1 x577 +1 x578 = +0 + con483: -1 x456 +1 x457 +1 x498 +1 x525 -1 x578 +1 x579 = +0 + con484: -1 x458 +1 x459 +1 x499 +1 x526 -1 x579 +1 x580 = +0 + con485: -1 x460 +1 x461 +1 x500 +1 x527 -1 x580 +1 x581 = +0 + con486: -1 x462 +1 x463 +1 x501 +1 x528 -1 x581 +1 x582 = +0 + con487: -1 x464 +1 x465 +1 x502 +1 x529 -1 x582 +1 x583 = +0 + con488: -1 x466 +1 x467 +1 x503 +1 x530 -1 x583 +1 x584 = +0 + con489: -1 x468 +1 x469 +1 x504 +1 x531 -1 x584 +1 x585 = +0 + con490: -1 x470 +1 x471 +1 x505 +1 x532 -1 x585 +1 x586 = +0 + con491: -1 x472 +1 x473 +1 x506 +1 x533 -1 x586 +1 x587 = +0 + con492: -1 x474 +1 x475 +1 x507 +1 x534 -1 x587 +1 x588 = +0 + con493: -1 x476 +1 x477 +1 x508 +1 x535 -1 x588 +1 x589 = +0 + con494: -1 x478 +1 x479 +1 x509 +1 x536 -1 x589 +1 x590 = +0 + con495: -1 x480 +1 x481 +1 x510 +1 x537 -1 x590 +1 x591 = +0 + con496: -1 x482 +1 x483 +1 x511 +1 x538 -1 x591 +1 x592 = +0 + con497: -1 x484 +1 x485 +1 x512 +1 x539 -1 x592 +1 x593 = +0 + con498: -1 x79 <= +0 + con499: -1 x80 -1 x567 <= -13507.000312 + con500: -1 x81 -1 x568 <= -13507.000312 + con501: -1 x82 -1 x569 <= -14081.143184 + con502: -1 x83 -1 x570 <= -14081.143184 + con503: -1 x84 -1 x571 <= -14081.143184 + con504: -1 x85 -1 x572 <= -14081.143184 + con505: -1 x86 -1 x573 <= -14081.143184 + con506: -1 x87 -1 x574 <= -14081.143184 + con507: -1 x88 -1 x575 <= -14081.143184 + con508: -1 x89 -1 x576 <= -14081.143184 + con509: -1 x90 -1 x577 <= -14081.143184 + con510: -1 x91 -1 x578 <= -13507.000312 + con511: -1 x92 -1 x579 <= -13507.000312 + con512: -1 x93 -1 x580 <= -13507.000312 + con513: -1 x94 -1 x581 <= -13507.000312 + con514: -1 x95 -1 x582 <= -13507.000312 + con515: -1 x96 -1 x583 <= -13507.000312 + con516: -1 x97 -1 x584 <= -13507.000312 + con517: -1 x98 -1 x585 <= -14081.143184 + con518: -1 x99 -1 x586 <= -14081.143184 + con519: -1 x100 -1 x587 <= -14081.143184 + con520: -1 x101 -1 x588 <= -14081.143184 + con521: -1 x102 -1 x589 <= -14081.143184 + con522: -1 x103 -1 x590 <= -14081.143184 + con523: -1 x104 -1 x591 <= -14081.143184 + con524: -1 x105 -1 x592 <= -14081.143184 + con525: -1 x106 -1 x593 <= -14081.143184 + con526: -1 x107 <= +0 + con527: -1 x108 +1 x567 <= +22857.628918 + con528: -1 x109 +1 x568 <= +22857.628918 + con529: -1 x110 +1 x569 <= +22634.182676 + con530: -1 x111 +1 x570 <= +22634.182676 + con531: -1 x112 +1 x571 <= +22634.182676 + con532: -1 x113 +1 x572 <= +22634.182676 + con533: -1 x114 +1 x573 <= +22634.182676 + con534: -1 x115 +1 x574 <= +22634.182676 + con535: -1 x116 +1 x575 <= +22634.182676 + con536: -1 x117 +1 x576 <= +22634.182676 + con537: -1 x118 +1 x577 <= +22634.182676 + con538: -1 x119 +1 x578 <= +22857.628918 + con539: -1 x120 +1 x579 <= +22857.628918 + con540: -1 x121 +1 x580 <= +22857.628918 + con541: -1 x122 +1 x581 <= +22857.628918 + con542: -1 x123 +1 x582 <= +22857.628918 + con543: -1 x124 +1 x583 <= +22857.628918 + con544: -1 x125 +1 x584 <= +22857.628918 + con545: -1 x126 +1 x585 <= +22634.182676 + con546: -1 x127 +1 x586 <= +22634.182676 + con547: -1 x128 +1 x587 <= +22634.182676 + con548: -1 x129 +1 x588 <= +22634.182676 + con549: -1 x130 +1 x589 <= +22634.182676 + con550: -1 x131 +1 x590 <= +22634.182676 + con551: -1 x132 +1 x591 <= +22634.182676 + con552: -1 x133 +1 x592 <= +22634.182676 + con553: -1 x134 +1 x593 <= +14081.143184 + con554: -1 x594 = -1714.007 + con555: -1 x595 = -1509.457 + con556: -1 x596 = -1509.457 + con557: -1 x597 = -1583.939 + con558: -1 x598 = -1583.939 + con559: -1 x599 = -1583.939 + con560: -1 x600 = -1583.939 + con561: -1 x601 = -1583.939 + con562: -1 x602 = -1583.939 + con563: -1 x603 = -1583.939 + con564: -1 x604 = -1583.939 + con565: -1 x605 = -1509.457 + con566: -1 x606 = -1509.457 + con567: -1 x607 = -1509.457 + con568: -1 x608 = -1509.457 + con569: -1 x609 = -1509.457 + con570: -1 x610 = -1509.457 + con571: -1 x611 = -1509.457 + con572: -1 x612 = -1509.457 + con573: -1 x613 = -1583.939 + con574: -1 x614 = -1583.939 + con575: -1 x615 = -1583.939 + con576: -1 x616 = -1583.939 + con577: -1 x617 = -1583.939 + con578: -1 x618 = -1583.939 + con579: -1 x619 = -1583.939 + con580: -1 x620 = -1583.939 + con581: -1 x621 = +0 + con582: -1 x622 = +0 + con583: -1 x623 = +0 + con584: -1 x624 = +0 + con585: -1 x625 = +0 + con586: -1 x626 = +0 + con587: -1 x627 = +0 + con588: -1 x628 = +0 + con589: -1 x629 = +0 + con590: -1 x630 = +0 + con591: -1 x631 = +0 + con592: -1 x632 = +0 + con593: -1 x633 = +0 + con594: -1 x634 = +0 + con595: -1 x635 = +0 + con596: -1 x636 = +0 + con597: -1 x637 = +0 + con598: -1 x638 = +0 + con599: -1 x639 = +0 + con600: -1 x640 = +0 + con601: -1 x641 = +0 + con602: -1 x642 = +0 + con603: -1 x643 = +0 + con604: -1 x644 = +0 + con605: -1 x645 = +0 + con606: -1 x646 = +0 + con607: -1 x647 = +0 + con608: +1 x52 <= +8700 + con609: +1 x53 <= +14500 + con610: +1 x54 <= +14500 + con611: +1 x55 <= +14500 + con612: +1 x56 <= +14500 + con613: +1 x57 <= +14500 + con614: +1 x58 <= +14500 + con615: +1 x59 <= +14500 + con616: +1 x60 <= +14500 + con617: +1 x61 <= +14500 + con618: +1 x62 <= +14500 + con619: +1 x63 <= +14500 + con620: +1 x64 <= +14500 + con621: +1 x65 <= +14500 + con622: +1 x66 <= +14500 + con623: +1 x67 <= +14500 + con624: +1 x68 <= +14500 + con625: +1 x69 <= +14500 + con626: +1 x70 <= +14500 + con627: +1 x71 <= +14500 + con628: +1 x72 <= +14500 + con629: +1 x73 <= +14500 + con630: +1 x74 <= +14500 + con631: +1 x75 <= +14500 + con632: +1 x76 <= +14500 + con633: +1 x77 <= +14500 + con634: +1 x78 <= +14500 + con635: +1 x648 <= +8700 + con636: +1 x649 <= +14500 + con637: +1 x650 <= +14500 + con638: +1 x651 <= +14500 + con639: +1 x652 <= +14500 + con640: +1 x653 <= +14500 + con641: +1 x654 <= +14500 + con642: +1 x655 <= +14500 + con643: +1 x656 <= +14500 + con644: +1 x657 <= +14500 + con645: +1 x658 <= +14500 + con646: +1 x659 <= +14500 + con647: +1 x660 <= +14500 + con648: +1 x661 <= +14500 + con649: +1 x662 <= +14500 + con650: +1 x663 <= +14500 + con651: +1 x664 <= +14500 + con652: +1 x665 <= +14500 + con653: +1 x666 <= +14500 + con654: +1 x667 <= +14500 + con655: +1 x668 <= +14500 + con656: +1 x669 <= +14500 + con657: +1 x670 <= +14500 + con658: +1 x671 <= +14500 + con659: +1 x672 <= +14500 + con660: +1 x673 <= +14500 + con661: +1 x674 <= +14500 + con662: +1 x52 -14501 x675 <= +0 + con663: +1 x648 +14501 x675 <= +14501 + con664: +1 x53 -14501 x676 <= +0 + con665: +1 x649 +14501 x676 <= +14501 + con666: +1 x54 -14501 x677 <= +0 + con667: +1 x650 +14501 x677 <= +14501 + con668: +1 x55 -14501 x678 <= +0 + con669: +1 x651 +14501 x678 <= +14501 + con670: +1 x56 -14501 x679 <= +0 + con671: +1 x652 +14501 x679 <= +14501 + con672: +1 x57 -14501 x680 <= +0 + con673: +1 x653 +14501 x680 <= +14501 + con674: +1 x58 -14501 x681 <= +0 + con675: +1 x654 +14501 x681 <= +14501 + con676: +1 x59 -14501 x682 <= +0 + con677: +1 x655 +14501 x682 <= +14501 + con678: +1 x60 -14501 x683 <= +0 + con679: +1 x656 +14501 x683 <= +14501 + con680: +1 x61 -14501 x684 <= +0 + con681: +1 x657 +14501 x684 <= +14501 + con682: +1 x62 -14501 x685 <= +0 + con683: +1 x658 +14501 x685 <= +14501 + con684: +1 x63 -14501 x686 <= +0 + con685: +1 x659 +14501 x686 <= +14501 + con686: +1 x64 -14501 x687 <= +0 + con687: +1 x660 +14501 x687 <= +14501 + con688: +1 x65 -14501 x688 <= +0 + con689: +1 x661 +14501 x688 <= +14501 + con690: +1 x66 -14501 x689 <= +0 + con691: +1 x662 +14501 x689 <= +14501 + con692: +1 x67 -14501 x690 <= +0 + con693: +1 x663 +14501 x690 <= +14501 + con694: +1 x68 -14501 x691 <= +0 + con695: +1 x664 +14501 x691 <= +14501 + con696: +1 x69 -14501 x692 <= +0 + con697: +1 x665 +14501 x692 <= +14501 + con698: +1 x70 -14501 x693 <= +0 + con699: +1 x666 +14501 x693 <= +14501 + con700: +1 x71 -14501 x694 <= +0 + con701: +1 x667 +14501 x694 <= +14501 + con702: +1 x72 -14501 x695 <= +0 + con703: +1 x668 +14501 x695 <= +14501 + con704: +1 x73 -14501 x696 <= +0 + con705: +1 x669 +14501 x696 <= +14501 + con706: +1 x74 -14501 x697 <= +0 + con707: +1 x670 +14501 x697 <= +14501 + con708: +1 x75 -14501 x698 <= +0 + con709: +1 x671 +14501 x698 <= +14501 + con710: +1 x76 -14501 x699 <= +0 + con711: +1 x672 +14501 x699 <= +14501 + con712: +1 x77 -14501 x700 <= +0 + con713: +1 x673 +14501 x700 <= +14501 + con714: +1 x78 -14501 x701 <= +0 + con715: +1 x674 +14501 x701 <= +14501 + con716: +1 x52 -1 x327 +1 x328 -1 x648 = +0 + con717: +1 x53 -1 x329 +1 x330 -1 x649 = +0 + con718: +1 x54 -1 x331 +1 x332 -1 x650 = +0 + con719: +1 x55 -1 x333 +1 x334 -1 x651 = +0 + con720: +1 x56 -1 x336 +1 x337 -1 x652 = +0 + con721: +1 x57 -1 x339 +1 x340 -1 x653 = +0 + con722: +1 x58 -1 x342 +1 x343 -1 x654 = +0 + con723: +1 x59 -1 x345 +1 x346 -1 x655 = +0 + con724: +1 x60 -1 x348 +1 x349 -1 x656 = +0 + con725: +1 x61 -1 x351 +1 x352 -1 x657 = +0 + con726: +1 x62 -1 x354 +1 x355 -1 x658 = +0 + con727: +1 x63 -1 x357 +1 x358 -1 x659 = +0 + con728: +1 x64 -1 x360 +1 x361 -1 x660 = +0 + con729: +1 x65 -1 x363 +1 x364 -1 x661 = +0 + con730: +1 x66 -1 x366 +1 x367 -1 x662 = +0 + con731: +1 x67 -1 x369 +1 x370 -1 x663 = +0 + con732: +1 x68 -1 x372 +1 x373 -1 x664 = +0 + con733: +1 x69 -1 x375 +1 x376 -1 x665 = +0 + con734: +1 x70 -1 x378 +1 x379 -1 x666 = +0 + con735: +1 x71 -1 x381 +1 x382 -1 x667 = +0 + con736: +1 x72 -1 x384 +1 x385 -1 x668 = +0 + con737: +1 x73 -1 x387 +1 x388 -1 x669 = +0 + con738: +1 x74 -1 x390 +1 x391 -1 x670 = +0 + con739: +1 x75 -1 x393 +1 x394 -1 x671 = +0 + con740: +1 x76 -1 x396 +1 x397 -1 x672 = +0 + con741: +1 x77 -1 x399 +1 x400 -1 x673 = +0 + con742: +1 x78 -1 x402 +1 x403 -1 x674 = +0 + con743: -1.01333353535354 x52 -1.01333353535354 x594 +1.01333353535354 x621 +1.01333353535354 x648 = -1511.55585690236 + con744: -1.02286483146067 x53 -1.02286483146067 x595 +1.02286483146067 x622 +1.02286483146067 x649 = -6068.998 + con745: -1.02294058333333 x54 -1.02294058333333 x596 +1.02294058333333 x623 +1.02294058333333 x650 = -6137.6435 + con746: -1 x2 +1 x26 -1.029686 x55 -1.002874 x597 +1.029686 x624 +1.002874 x651 -1 x702 +1 x703 = +0 + con747: -1 x3 +1 x27 -1.029686 x56 -1.002874 x598 +1.029686 x625 +1.002874 x652 -1 x704 +1 x705 = +0 + con748: -1 x4 +1 x28 -1.029686 x57 -1.002874 x599 +1.029686 x626 +1.002874 x653 -1 x706 +1 x707 = +0 + con749: -1 x5 +1 x29 -1.029686 x58 -1.002874 x600 +1.029686 x627 +1.002874 x654 -1 x708 +1 x709 = +0 + con750: -1 x6 +1 x30 -1.029686 x59 -1.002874 x601 +1.029686 x628 +1.002874 x655 -1 x710 +1 x711 = +0 + con751: -1 x7 +1 x31 -1.029686 x60 -1.002874 x602 +1.029686 x629 +1.002874 x656 -1 x712 +1 x713 = +0 + con752: -1 x8 +1 x32 -1.029686 x61 -1.002874 x603 +1.029686 x630 +1.002874 x657 -1 x714 +1 x715 = +0 + con753: -1 x9 +1 x33 -1.029686 x62 -1.002874 x604 +1.029686 x631 +1.002874 x658 -1 x716 +1 x717 = +0 + con754: -1 x10 +1 x34 -1.029686 x63 -1.002874 x605 +1.029686 x632 +1.002874 x659 -1 x718 +1 x719 = +0 + con755: -1 x11 +1 x35 -1.029686 x64 -1.002874 x606 +1.029686 x633 +1.002874 x660 -1 x720 +1 x721 = +0 + con756: -1 x12 +1 x36 -1.029686 x65 -1.002874 x607 +1.029686 x634 +1.002874 x661 -1 x722 +1 x723 = +0 + con757: -1 x13 +1 x37 -1.029686 x66 -1.002874 x608 +1.029686 x635 +1.002874 x662 -1 x724 +1 x725 = +0 + con758: -1 x14 +1 x38 -1.029686 x67 -1.002874 x609 +1.029686 x636 +1.002874 x663 -1 x726 +1 x727 = +0 + con759: -1 x15 +1 x39 -1.029686 x68 -1.002874 x610 +1.029686 x637 +1.002874 x664 -1 x728 +1 x729 = +0 + con760: -1 x16 +1 x40 -1.029686 x69 -1.002874 x611 +1.029686 x638 +1.002874 x665 -1 x730 +1 x731 = +0 + con761: -1 x17 +1 x41 -1.029686 x70 -1.002874 x612 +1.029686 x639 +1.002874 x666 -1 x732 +1 x733 = +0 + con762: -1 x18 +1 x42 -1.029686 x71 -1.002874 x613 +1.029686 x640 +1.002874 x667 -1 x734 +1 x735 = +0 + con763: -1 x19 +1 x43 -1.029686 x72 -1.002874 x614 +1.029686 x641 +1.002874 x668 -1 x736 +1 x737 = +0 + con764: -1 x20 +1 x44 -1.029686 x73 -1.002874 x615 +1.029686 x642 +1.002874 x669 -1 x738 +1 x739 = +0 + con765: -1 x21 +1 x45 -1.029686 x74 -1.002874 x616 +1.029686 x643 +1.002874 x670 -1 x740 +1 x741 = +0 + con766: -1 x22 +1 x46 -1.029686 x75 -1.002874 x617 +1.029686 x644 +1.002874 x671 -1 x742 +1 x743 = +0 + con767: -1 x23 +1 x47 -1.029686 x76 -1.002874 x618 +1.029686 x645 +1.002874 x672 -1 x744 +1 x745 = +0 + con768: -1 x24 +1 x48 -1.029686 x77 -1.002874 x619 +1.029686 x646 +1.002874 x673 -1 x746 +1 x747 = +0 + con769: -1 x25 +1 x49 -1 x50 +1 x51 -1.029686 x78 -1.002874 x620 +1.029686 x647 +1.002874 x674 = +0 + con770: -17400 x748 <= -1511.55585690236 + con771: +17400 x748 <= +17400 + con772: -17400 x749 <= -1511.55585690236 + con773: -29000 x750 <= -6068.998 + con774: +29000 x750 <= +29000 + con775: -29000 x751 <= -6068.998 + con776: -29000 x752 <= -6137.6435 + con777: +29000 x752 <= +29000 + con778: -29000 x753 <= -6137.6435 + con779: +1 x26 -29000 x754 <= +0 + con780: +1 x2 +29000 x754 <= +29000 + con781: +1 x2 +1 x26 -29000 x755 <= +0 + con782: +1 x27 -29000 x756 <= +0 + con783: +1 x3 +29000 x756 <= +29000 + con784: +1 x3 +1 x27 -29000 x757 <= +0 + con785: +1 x28 -29000 x758 <= +0 + con786: +1 x4 +29000 x758 <= +29000 + con787: +1 x4 +1 x28 -29000 x759 <= +0 + con788: +1 x29 -29000 x760 <= +0 + con789: +1 x5 +29000 x760 <= +29000 + con790: +1 x5 +1 x29 -29000 x761 <= +0 + con791: +1 x30 -29000 x762 <= +0 + con792: +1 x6 +29000 x762 <= +29000 + con793: +1 x6 +1 x30 -29000 x763 <= +0 + con794: +1 x31 -29000 x764 <= +0 + con795: +1 x7 +29000 x764 <= +29000 + con796: +1 x7 +1 x31 -29000 x765 <= +0 + con797: +1 x32 -29000 x766 <= +0 + con798: +1 x8 +29000 x766 <= +29000 + con799: +1 x8 +1 x32 -29000 x767 <= +0 + con800: +1 x33 -29000 x768 <= +0 + con801: +1 x9 +29000 x768 <= +29000 + con802: +1 x9 +1 x33 -29000 x769 <= +0 + con803: +1 x34 -29000 x770 <= +0 + con804: +1 x10 +29000 x770 <= +29000 + con805: +1 x10 +1 x34 -29000 x771 <= +0 + con806: +1 x35 -29000 x772 <= +0 + con807: +1 x11 +29000 x772 <= +29000 + con808: +1 x11 +1 x35 -29000 x773 <= +0 + con809: +1 x36 -29000 x774 <= +0 + con810: +1 x12 +29000 x774 <= +29000 + con811: +1 x12 +1 x36 -29000 x775 <= +0 + con812: +1 x37 -29000 x776 <= +0 + con813: +1 x13 +29000 x776 <= +29000 + con814: +1 x13 +1 x37 -29000 x777 <= +0 + con815: +1 x38 -29000 x778 <= +0 + con816: +1 x14 +29000 x778 <= +29000 + con817: +1 x14 +1 x38 -29000 x779 <= +0 + con818: +1 x39 -29000 x780 <= +0 + con819: +1 x15 +29000 x780 <= +29000 + con820: +1 x15 +1 x39 -29000 x781 <= +0 + con821: +1 x40 -29000 x782 <= +0 + con822: +1 x16 +29000 x782 <= +29000 + con823: +1 x16 +1 x40 -29000 x783 <= +0 + con824: +1 x41 -29000 x784 <= +0 + con825: +1 x17 +29000 x784 <= +29000 + con826: +1 x17 +1 x41 -29000 x785 <= +0 + con827: +1 x42 -29000 x786 <= +0 + con828: +1 x18 +29000 x786 <= +29000 + con829: +1 x18 +1 x42 -29000 x787 <= +0 + con830: +1 x43 -29000 x788 <= +0 + con831: +1 x19 +29000 x788 <= +29000 + con832: +1 x19 +1 x43 -29000 x789 <= +0 + con833: +1 x44 -29000 x790 <= +0 + con834: +1 x20 +29000 x790 <= +29000 + con835: +1 x20 +1 x44 -29000 x791 <= +0 + con836: +1 x45 -29000 x792 <= +0 + con837: +1 x21 +29000 x792 <= +29000 + con838: +1 x21 +1 x45 -29000 x793 <= +0 + con839: +1 x46 -29000 x794 <= +0 + con840: +1 x22 +29000 x794 <= +29000 + con841: +1 x22 +1 x46 -29000 x795 <= +0 + con842: +1 x47 -29000 x796 <= +0 + con843: +1 x23 +29000 x796 <= +29000 + con844: +1 x23 +1 x47 -29000 x797 <= +0 + con845: +1 x48 -29000 x798 <= +0 + con846: +1 x24 +29000 x798 <= +29000 + con847: +1 x24 +1 x48 -29000 x799 <= +0 + con848: +1 x49 -29000 x800 <= +0 + con849: +1 x25 +29000 x800 <= +29000 + con850: +1 x25 +1 x49 -29000 x801 <= +0 + con851: -17400 x802 <= +0 + con852: +17400 x802 <= +17400 + con853: -17400 x803 <= +0 + con854: -29000 x804 <= +0 + con855: +29000 x804 <= +29000 + con856: -29000 x805 <= +0 + con857: -29000 x806 <= +0 + con858: +29000 x806 <= +29000 + con859: -29000 x807 <= +0 + con860: +1 x703 -29000 x808 <= +0 + con861: +1 x702 +29000 x808 <= +29000 + con862: +1 x702 +1 x703 -29000 x809 <= +0 + con863: +1 x705 -29000 x810 <= +0 + con864: +1 x704 +29000 x810 <= +29000 + con865: +1 x704 +1 x705 -29000 x811 <= +0 + con866: +1 x707 -29000 x812 <= +0 + con867: +1 x706 +29000 x812 <= +29000 + con868: +1 x706 +1 x707 -29000 x813 <= +0 + con869: +1 x709 -29000 x814 <= +0 + con870: +1 x708 +29000 x814 <= +29000 + con871: +1 x708 +1 x709 -29000 x815 <= +0 + con872: +1 x711 -29000 x816 <= +0 + con873: +1 x710 +29000 x816 <= +29000 + con874: +1 x710 +1 x711 -29000 x817 <= +0 + con875: +1 x713 -29000 x818 <= +0 + con876: +1 x712 +29000 x818 <= +29000 + con877: +1 x712 +1 x713 -29000 x819 <= +0 + con878: +1 x715 -29000 x820 <= +0 + con879: +1 x714 +29000 x820 <= +29000 + con880: +1 x714 +1 x715 -29000 x821 <= +0 + con881: +1 x717 -29000 x822 <= +0 + con882: +1 x716 +29000 x822 <= +29000 + con883: +1 x716 +1 x717 -29000 x823 <= +0 + con884: +1 x719 -29000 x824 <= +0 + con885: +1 x718 +29000 x824 <= +29000 + con886: +1 x718 +1 x719 -29000 x825 <= +0 + con887: +1 x721 -29000 x826 <= +0 + con888: +1 x720 +29000 x826 <= +29000 + con889: +1 x720 +1 x721 -29000 x827 <= +0 + con890: +1 x723 -29000 x828 <= +0 + con891: +1 x722 +29000 x828 <= +29000 + con892: +1 x722 +1 x723 -29000 x829 <= +0 + con893: +1 x725 -29000 x830 <= +0 + con894: +1 x724 +29000 x830 <= +29000 + con895: +1 x724 +1 x725 -29000 x831 <= +0 + con896: +1 x727 -29000 x832 <= +0 + con897: +1 x726 +29000 x832 <= +29000 + con898: +1 x726 +1 x727 -29000 x833 <= +0 + con899: +1 x729 -29000 x834 <= +0 + con900: +1 x728 +29000 x834 <= +29000 + con901: +1 x728 +1 x729 -29000 x835 <= +0 + con902: +1 x731 -29000 x836 <= +0 + con903: +1 x730 +29000 x836 <= +29000 + con904: +1 x730 +1 x731 -29000 x837 <= +0 + con905: +1 x733 -29000 x838 <= +0 + con906: +1 x732 +29000 x838 <= +29000 + con907: +1 x732 +1 x733 -29000 x839 <= +0 + con908: +1 x735 -29000 x840 <= +0 + con909: +1 x734 +29000 x840 <= +29000 + con910: +1 x734 +1 x735 -29000 x841 <= +0 + con911: +1 x737 -29000 x842 <= +0 + con912: +1 x736 +29000 x842 <= +29000 + con913: +1 x736 +1 x737 -29000 x843 <= +0 + con914: +1 x739 -29000 x844 <= +0 + con915: +1 x738 +29000 x844 <= +29000 + con916: +1 x738 +1 x739 -29000 x845 <= +0 + con917: +1 x741 -29000 x846 <= +0 + con918: +1 x740 +29000 x846 <= +29000 + con919: +1 x740 +1 x741 -29000 x847 <= +0 + con920: +1 x743 -29000 x848 <= +0 + con921: +1 x742 +29000 x848 <= +29000 + con922: +1 x742 +1 x743 -29000 x849 <= +0 + con923: +1 x745 -29000 x850 <= +0 + con924: +1 x744 +29000 x850 <= +29000 + con925: +1 x744 +1 x745 -29000 x851 <= +0 + con926: +1 x747 -29000 x852 <= +0 + con927: +1 x746 +29000 x852 <= +29000 + con928: +1 x746 +1 x747 -29000 x853 <= +0 + con929: +1 x51 -29000 x854 <= +0 + con930: +1 x50 +29000 x854 <= +29000 + con931: +1 x50 +1 x51 -29000 x855 <= +0 + con932: = +0 + con933: = +0 + con934: = +0 + con935: +1 x703 = +0 + con936: +1 x705 = +0 + con937: +1 x707 = +0 + con938: +1 x709 = +0 + con939: +1 x711 = +0 + con940: +1 x713 = +0 + con941: +1 x715 = +0 + con942: +1 x717 = +0 + con943: +1 x719 = +0 + con944: +1 x721 = +0 + con945: +1 x723 = +0 + con946: +1 x725 = +0 + con947: +1 x727 = +0 + con948: +1 x729 = +0 + con949: +1 x731 = +0 + con950: +1 x733 = +0 + con951: +1 x735 = +0 + con952: +1 x737 = +0 + con953: +1 x739 = +0 + con954: +1 x741 = +0 + con955: +1 x743 = +0 + con956: +1 x745 = +0 + con957: +1 x747 = +0 + con958: = +0 + con959: = +0 + con960: = +0 + con961: +1 x702 = +0 + con962: +1 x704 = +0 + con963: +1 x706 = +0 + con964: +1 x708 = +0 + con965: +1 x710 = +0 + con966: +1 x712 = +0 + con967: +1 x714 = +0 + con968: +1 x716 = +0 + con969: +1 x718 = +0 + con970: +1 x720 = +0 + con971: +1 x722 = +0 + con972: +1 x724 = +0 + con973: +1 x726 = +0 + con974: +1 x728 = +0 + con975: +1 x730 = +0 + con976: +1 x732 = +0 + con977: +1 x734 = +0 + con978: +1 x736 = +0 + con979: +1 x738 = +0 + con980: +1 x740 = +0 + con981: +1 x742 = +0 + con982: +1 x744 = +0 + con983: +1 x746 = +0 + con984: +1 x328 +1 x330 +1 x332 +1 x334 +1 x337 +1 x340 +1 x343 +1 x346 +1 x349 +1 x352 +1 x355 +1 x358 +1 x361 +1 x364 +1 x367 +1 x370 +1 x373 +1 x376 +1 x379 +1 x382 +1 x385 +1 x388 +1 x391 +1 x394 +1 x397 +1 x400 +1 x403 <= +20970.557 + con985: +1 x135 +1 x136 +1 x137 +1 x138 +1 x139 +1 x140 +1 x141 +1 x142 +1 x143 +1 x144 +1 x145 +1 x146 +1 x147 +1 x148 +1 x149 +1 x150 +1 x151 +1 x152 +1 x153 +1 x154 +1 x155 +1 x156 +1 x157 +1 x158 <= +20970.557 + con986: +1 x335 <= +6000 + con987: +1 x338 <= +6000 + con988: +1 x341 <= +6000 + con989: +1 x344 <= +6000 + con990: +1 x347 <= +6000 + con991: +1 x350 <= +6000 + con992: +1 x353 <= +6000 + con993: +1 x356 <= +6000 + con994: +1 x359 <= +6000 + con995: +1 x362 <= +6000 + con996: +1 x365 <= +6000 + con997: +1 x368 <= +6000 + con998: +1 x371 <= +6000 + con999: +1 x374 <= +6000 + con1000: +1 x377 <= +6000 + con1001: +1 x380 <= +6000 + con1002: +1 x383 <= +6000 + con1003: +1 x386 <= +6000 + con1004: +1 x389 <= +6000 + con1005: +1 x392 <= +6000 + con1006: +1 x395 <= +6000 + con1007: +1 x398 <= +6000 + con1008: +1 x401 <= +6000 + con1009: +1 x404 <= +6000 + con1010: +1 x135 <= +3500 + con1011: +1 x136 <= +3500 + con1012: +1 x137 <= +3500 + con1013: +1 x138 <= +3500 + con1014: +1 x139 <= +3500 + con1015: +1 x140 <= +3500 + con1016: +1 x141 <= +3500 + con1017: +1 x142 <= +3500 + con1018: +1 x143 <= +4000 + con1019: +1 x144 <= +4000 + con1020: +1 x145 <= +4000 + con1021: +1 x146 <= +4000 + con1022: +1 x147 <= +4000 + con1023: +1 x148 <= +4000 + con1024: +1 x149 <= +4000 + con1025: +1 x150 <= +4000 + con1026: +1 x151 <= +3500 + con1027: +1 x152 <= +3500 + con1028: +1 x153 <= +3500 + con1029: +1 x154 <= +3500 + con1030: +1 x155 <= +3500 + con1031: +1 x156 <= +3500 + con1032: +1 x157 <= +3500 + con1033: +1 x158 <= +3500 + con1034: +1 x749 +1 x803 <= +2 + con1035: +1 x751 +1 x805 <= +2 + con1036: +1 x753 +1 x807 <= +2 + con1037: +1 x755 +1 x809 <= +1 + con1038: +1 x757 +1 x811 <= +1 + con1039: +1 x759 +1 x813 <= +1 + con1040: +1 x761 +1 x815 <= +1 + con1041: +1 x763 +1 x817 <= +1 + con1042: +1 x765 +1 x819 <= +1 + con1043: +1 x767 +1 x821 <= +1 + con1044: +1 x769 +1 x823 <= +1 + con1045: +1 x771 +1 x825 <= +1 + con1046: +1 x773 +1 x827 <= +1 + con1047: +1 x775 +1 x829 <= +1 + con1048: +1 x777 +1 x831 <= +1 + con1049: +1 x779 +1 x833 <= +1 + con1050: +1 x781 +1 x835 <= +1 + con1051: +1 x783 +1 x837 <= +1 + con1052: +1 x785 +1 x839 <= +1 + con1053: +1 x787 +1 x841 <= +1 + con1054: +1 x789 +1 x843 <= +1 + con1055: +1 x791 +1 x845 <= +1 + con1056: +1 x793 +1 x847 <= +1 + con1057: +1 x795 +1 x849 <= +1 + con1058: +1 x797 +1 x851 <= +1 + con1059: +1 x799 +1 x853 <= +1 + con1060: +1 x801 +1 x855 <= +1 +bounds + x1 = 1 + x52 <= 8700 + x53 <= 14500 + x54 <= 14500 + x55 <= 14500 + x56 <= 14500 + x57 <= 14500 + x58 <= 14500 + x59 <= 14500 + x60 <= 14500 + x61 <= 14500 + x62 <= 14500 + x63 <= 14500 + x64 <= 14500 + x65 <= 14500 + x66 <= 14500 + x67 <= 14500 + x68 <= 14500 + x69 <= 14500 + x70 <= 14500 + x71 <= 14500 + x72 <= 14500 + x73 <= 14500 + x74 <= 14500 + x75 <= 14500 + x76 <= 14500 + x77 <= 14500 + x78 <= 14500 + x159 <= 6000 + x160 <= 12000 + x161 <= 12000 + x162 <= 12000 + x163 <= 12000 + x164 <= 3500 + x165 <= 7000 + x166 <= 8000 + x167 <= 7000 + x168 <= 8000 + x169 <= 6000 + x170 <= 12000 + x171 <= 12000 + x172 <= 12000 + x173 <= 3500 + x174 <= 7000 + x175 <= 7000 + x176 <= 7000 + x177 <= 6000 + x178 <= 12000 + x179 <= 12000 + x180 <= 12000 + x181 <= 3500 + x182 <= 7000 + x183 <= 7000 + x184 <= 7000 + x185 <= 6000 + x186 <= 12000 + x187 <= 12000 + x188 <= 12000 + x189 <= 3500 + x190 <= 7000 + x191 <= 7000 + x192 <= 7000 + x193 <= 6000 + x194 <= 12000 + x195 <= 12000 + x196 <= 12000 + x197 <= 3500 + x198 <= 7000 + x199 <= 7000 + x200 <= 7000 + x201 <= 6000 + x202 <= 12000 + x203 <= 12000 + x204 <= 12000 + x205 <= 3500 + x206 <= 7000 + x207 <= 7000 + x208 <= 7000 + x209 <= 6000 + x210 <= 12000 + x211 <= 12000 + x212 <= 12000 + x213 <= 3500 + x214 <= 7000 + x215 <= 7000 + x216 <= 7000 + x217 <= 6000 + x218 <= 12000 + x219 <= 12000 + x220 <= 12000 + x221 <= 3500 + x222 <= 7000 + x223 <= 8000 + x224 <= 7000 + x225 <= 6000 + x226 <= 12000 + x227 <= 12000 + x228 <= 12000 + x229 <= 4000 + x230 <= 8000 + x231 <= 8000 + x232 <= 8000 + x233 <= 6000 + x234 <= 12000 + x235 <= 12000 + x236 <= 12000 + x237 <= 4000 + x238 <= 8000 + x239 <= 8000 + x240 <= 8000 + x241 <= 6000 + x242 <= 12000 + x243 <= 12000 + x244 <= 12000 + x245 <= 4000 + x246 <= 8000 + x247 <= 8000 + x248 <= 8000 + x249 <= 6000 + x250 <= 12000 + x251 <= 12000 + x252 <= 12000 + x253 <= 4000 + x254 <= 8000 + x255 <= 8000 + x256 <= 8000 + x257 <= 1 + x258 <= 1 + x259 <= 1 + x260 <= 1 + x261 <= 1 + x262 <= 1 + x263 <= 1 + x264 <= 1 + x265 <= 1 + x266 <= 1 + x267 <= 1 + x268 <= 1 + x269 <= 1 + x270 <= 12000 + x271 <= 1 + x272 <= 8000 + x273 <= 1 + x274 <= 1 + x275 <= 1 + x276 <= 1 + x277 <= 1 + x278 <= 1 + x279 <= 1 + x280 <= 1 + x281 <= 1 + x282 <= 1 + x283 <= 1 + x284 <= 1 + x285 <= 1 + x286 <= 1 + x287 <= 1 + x288 <= 1 + x289 <= 1 + x290 <= 1 + x291 <= 1 + x292 <= 1 + x293 <= 1 + x294 <= 1 + x295 <= 1 + x296 <= 1 + x297 <= 1 + x298 <= 1 + x299 <= 12 + x300 <= 8 + x301 <= 12 + x302 <= 7 + x303 <= 12 + x304 <= 7 + x305 <= 12 + x306 <= 7 + x307 <= 12 + x308 <= 7 + x309 <= 12 + x310 <= 7 + x311 <= 12 + x312 <= 7 + x313 <= 12 + x314 <= 7 + x315 <= 12 + x316 <= 7 + x317 <= 12 + x318 <= 8 + x319 <= 12 + x320 <= 8 + x321 <= 12 + x322 <= 8 + x323 <= 12 + x324 <= 8 + x325 <= 12 + x326 <= 8 + x327 <= 8700 + x328 <= 8700 + x329 <= 14500 + x330 <= 14500 + x331 <= 14500 + x332 <= 14500 + x333 <= 14500 + x334 <= 14500 + x336 <= 14500 + x337 <= 14500 + x339 <= 14500 + x340 <= 14500 + x342 <= 14500 + x343 <= 14500 + x345 <= 14500 + x346 <= 14500 + x348 <= 14500 + x349 <= 14500 + x351 <= 14500 + x352 <= 14500 + x354 <= 14500 + x355 <= 14500 + x357 <= 14500 + x358 <= 14500 + x360 <= 14500 + x361 <= 14500 + x363 <= 14500 + x364 <= 14500 + x366 <= 14500 + x367 <= 14500 + x369 <= 14500 + x370 <= 14500 + x372 <= 14500 + x373 <= 14500 + x375 <= 14500 + x376 <= 14500 + x378 <= 14500 + x379 <= 14500 + x381 <= 14500 + x382 <= 14500 + x384 <= 14500 + x385 <= 14500 + x387 <= 14500 + x388 <= 14500 + x390 <= 14500 + x391 <= 14500 + x393 <= 14500 + x394 <= 14500 + x396 <= 14500 + x397 <= 14500 + x399 <= 14500 + x400 <= 14500 + x402 <= 14500 + x403 <= 14500 + x405 <= 1 + x406 <= 1 + x407 <= 1 + x408 <= 1 + x409 <= 1 + x410 <= 1 + x411 <= 1 + x412 <= 1 + x413 <= 1 + x414 <= 1 + x415 <= 1 + x416 <= 1 + x417 <= 1 + x418 <= 1 + x419 <= 1 + x420 <= 1 + x421 <= 1 + x422 <= 1 + x423 <= 1 + x424 <= 1 + x425 <= 1 + x426 <= 1 + x427 <= 1 + x428 <= 1 + x429 <= 1 + x430 <= 1 + x431 <= 1 + x540 <= 1 + x541 <= 1 + x542 <= 1 + x543 <= 1 + x544 <= 1 + x545 <= 1 + x546 <= 1 + x547 <= 1 + x548 <= 1 + x549 <= 1 + x550 <= 1 + x551 <= 1 + x552 <= 1 + x553 <= 1 + x554 <= 1 + x555 <= 1 + x556 <= 1 + x557 <= 1 + x558 <= 1 + x559 <= 1 + x560 <= 1 + x561 <= 1 + x562 <= 1 + x563 <= 1 + x564 <= 1 + x565 <= 1 + x566 <= 1 + x567 <= 29000 + x568 <= 29000 + x569 <= 29000 + x570 <= 29000 + x571 <= 29000 + x572 <= 29000 + x573 <= 29000 + x574 <= 29000 + x575 <= 29000 + x576 <= 29000 + x577 <= 29000 + x578 <= 29000 + x579 <= 29000 + x580 <= 29000 + x581 <= 29000 + x582 <= 29000 + x583 <= 29000 + x584 <= 29000 + x585 <= 29000 + x586 <= 29000 + x587 <= 29000 + x588 <= 29000 + x589 <= 29000 + x590 <= 29000 + x591 <= 29000 + x592 <= 29000 + x593 <= 29000 + x648 <= 8700 + x649 <= 14500 + x650 <= 14500 + x651 <= 14500 + x652 <= 14500 + x653 <= 14500 + x654 <= 14500 + x655 <= 14500 + x656 <= 14500 + x657 <= 14500 + x658 <= 14500 + x659 <= 14500 + x660 <= 14500 + x661 <= 14500 + x662 <= 14500 + x663 <= 14500 + x664 <= 14500 + x665 <= 14500 + x666 <= 14500 + x667 <= 14500 + x668 <= 14500 + x669 <= 14500 + x670 <= 14500 + x671 <= 14500 + x672 <= 14500 + x673 <= 14500 + x674 <= 14500 + x675 <= 1 + x676 <= 1 + x677 <= 1 + x678 <= 1 + x679 <= 1 + x680 <= 1 + x681 <= 1 + x682 <= 1 + x683 <= 1 + x684 <= 1 + x685 <= 1 + x686 <= 1 + x687 <= 1 + x688 <= 1 + x689 <= 1 + x690 <= 1 + x691 <= 1 + x692 <= 1 + x693 <= 1 + x694 <= 1 + x695 <= 1 + x696 <= 1 + x697 <= 1 + x698 <= 1 + x699 <= 1 + x700 <= 1 + x701 <= 1 + x748 <= 1 + x749 <= 1 + x750 <= 1 + x751 <= 1 + x752 <= 1 + x753 <= 1 + x754 <= 1 + x755 <= 1 + x756 <= 1 + x757 <= 1 + x758 <= 1 + x759 <= 1 + x760 <= 1 + x761 <= 1 + x762 <= 1 + x763 <= 1 + x764 <= 1 + x765 <= 1 + x766 <= 1 + x767 <= 1 + x768 <= 1 + x769 <= 1 + x770 <= 1 + x771 <= 1 + x772 <= 1 + x773 <= 1 + x774 <= 1 + x775 <= 1 + x776 <= 1 + x777 <= 1 + x778 <= 1 + x779 <= 1 + x780 <= 1 + x781 <= 1 + x782 <= 1 + x783 <= 1 + x784 <= 1 + x785 <= 1 + x786 <= 1 + x787 <= 1 + x788 <= 1 + x789 <= 1 + x790 <= 1 + x791 <= 1 + x792 <= 1 + x793 <= 1 + x794 <= 1 + x795 <= 1 + x796 <= 1 + x797 <= 1 + x798 <= 1 + x799 <= 1 + x800 <= 1 + x801 <= 1 + x802 <= 1 + x803 <= 1 + x804 <= 1 + x805 <= 1 + x806 <= 1 + x807 <= 1 + x808 <= 1 + x809 <= 1 + x810 <= 1 + x811 <= 1 + x812 <= 1 + x813 <= 1 + x814 <= 1 + x815 <= 1 + x816 <= 1 + x817 <= 1 + x818 <= 1 + x819 <= 1 + x820 <= 1 + x821 <= 1 + x822 <= 1 + x823 <= 1 + x824 <= 1 + x825 <= 1 + x826 <= 1 + x827 <= 1 + x828 <= 1 + x829 <= 1 + x830 <= 1 + x831 <= 1 + x832 <= 1 + x833 <= 1 + x834 <= 1 + x835 <= 1 + x836 <= 1 + x837 <= 1 + x838 <= 1 + x839 <= 1 + x840 <= 1 + x841 <= 1 + x842 <= 1 + x843 <= 1 + x844 <= 1 + x845 <= 1 + x846 <= 1 + x847 <= 1 + x848 <= 1 + x849 <= 1 + x850 <= 1 + x851 <= 1 + x852 <= 1 + x853 <= 1 + x854 <= 1 + x855 <= 1 +bin + x257 + x258 + x259 + x260 + x261 + x262 + x263 + x264 + x265 + x266 + x267 + x268 + x269 + x271 + x273 + x274 + x275 + x276 + x277 + x278 + x279 + x280 + x281 + x282 + x283 + x284 + x285 + x286 + x287 + x288 + x289 + x290 + x291 + x292 + x293 + x294 + x295 + x296 + x297 + x298 + x405 + x406 + x407 + x408 + x409 + x410 + x411 + x412 + x413 + x414 + x415 + x416 + x417 + x418 + x419 + x420 + x421 + x422 + x423 + x424 + x425 + x426 + x427 + x428 + x429 + x430 + x431 + x540 + x541 + x542 + x543 + x544 + x545 + x546 + x547 + x548 + x549 + x550 + x551 + x552 + x553 + x554 + x555 + x556 + x557 + x558 + x559 + x560 + x561 + x562 + x563 + x564 + x565 + x566 + x675 + x676 + x677 + x678 + x679 + x680 + x681 + x682 + x683 + x684 + x685 + x686 + x687 + x688 + x689 + x690 + x691 + x692 + x693 + x694 + x695 + x696 + x697 + x698 + x699 + x700 + x701 + x748 + x749 + x750 + x751 + x752 + x753 + x754 + x755 + x756 + x757 + x758 + x759 + x760 + x761 + x762 + x763 + x764 + x765 + x766 + x767 + x768 + x769 + x770 + x771 + x772 + x773 + x774 + x775 + x776 + x777 + x778 + x779 + x780 + x781 + x782 + x783 + x784 + x785 + x786 + x787 + x788 + x789 + x790 + x791 + x792 + x793 + x794 + x795 + x796 + x797 + x798 + x799 + x800 + x801 + x802 + x803 + x804 + x805 + x806 + x807 + x808 + x809 + x810 + x811 + x812 + x813 + x814 + x815 + x816 + x817 + x818 + x819 + x820 + x821 + x822 + x823 + x824 + x825 + x826 + x827 + x828 + x829 + x830 + x831 + x832 + x833 + x834 + x835 + x836 + x837 + x838 + x839 + x840 + x841 + x842 + x843 + x844 + x845 + x846 + x847 + x848 + x849 + x850 + x851 + x852 + x853 + x854 + x855 +gen + x299 + x300 + x301 + x302 + x303 + x304 + x305 + x306 + x307 + x308 + x309 + x310 + x311 + x312 + x313 + x314 + x315 + x316 + x317 + x318 + x319 + x320 + x321 + x322 + x323 + x324 + x325 + x326 +semi +end diff --git a/docs/src/options/definitions.md b/docs/src/options/definitions.md index 92ac80c889..5ff9199ac6 100644 --- a/docs/src/options/definitions.md +++ b/docs/src/options/definitions.md @@ -122,7 +122,7 @@ - Default: 0 ## [simplex\_strategy](@id option-simplex_strategy) -- Strategy for simplex solver 0 => Choose; 1 => Dual (serial); 2 => Dual (PAMI); 3 => Dual (SIP); 4 => Primal +- Strategy for simplex solver 0 => Choose; 1 => Dual (serial); 2 => Dual (SIP); 3 => Dual (PAMI); 4 => Primal - Type: integer - Range: {0, 4} - Default: 1 diff --git a/src/HConfig.h.bazel.in b/src/HConfig.h.bazel.in index d6cd6003fa..3f370785ef 100644 --- a/src/HConfig.h.bazel.in +++ b/src/HConfig.h.bazel.in @@ -11,9 +11,9 @@ #define HIGHS_HAVE_BUILTIN_CLZ /* #undef HIGHS_HAVE_BITSCAN_REVERSE */ -#define HIGHS_GITHASH "50670fd4c" +#define HIGHS_GITHASH "bdf95f2e0" #define HIGHS_VERSION_MAJOR 1 -#define HIGHS_VERSION_MINOR 7 +#define HIGHS_VERSION_MINOR 9 #define HIGHS_VERSION_PATCH 0 /* #undef HIGHS_DIR */ diff --git a/src/Highs.h b/src/Highs.h index a75760c0a8..8bebbd16c2 100644 --- a/src/Highs.h +++ b/src/Highs.h @@ -1471,7 +1471,7 @@ class Highs { bool called_return_from_run = true; HighsInt debug_run_call_num_ = 0; - bool written_log_header = false; + bool written_log_header_ = false; HighsStatus solve(); diff --git a/src/highs_bindings.cpp b/src/highs_bindings.cpp index 2ea1c35817..a650071503 100644 --- a/src/highs_bindings.cpp +++ b/src/highs_bindings.cpp @@ -947,7 +947,8 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) { .value("kContinuous", HighsVarType::kContinuous) .value("kInteger", HighsVarType::kInteger) .value("kSemiContinuous", HighsVarType::kSemiContinuous) - .value("kSemiInteger", HighsVarType::kSemiInteger); + .value("kSemiInteger", HighsVarType::kSemiInteger) + .value("kImplicitInteger", HighsVarType::kImplicitInteger); py::enum_(m, "HighsOptionType", py::module_local()) .value("kBool", HighsOptionType::kBool) .value("kInt", HighsOptionType::kInt) diff --git a/src/io/HMPSIO.cpp b/src/io/HMPSIO.cpp index 02d2c0c61f..ee38a36e31 100644 --- a/src/io/HMPSIO.cpp +++ b/src/io/HMPSIO.cpp @@ -913,6 +913,9 @@ HighsStatus writeMps( if (lb || highs_isInfinity(ub)) fprintf(file, " LI BOUND %-8s %.10g\n", col_names[c_n].c_str(), lb); + } else { + // Infinite lower bound + fprintf(file, " MI BOUND %-8s\n", col_names[c_n].c_str()); } if (!highs_isInfinity(ub)) { // Finite upper bound diff --git a/src/io/HMpsFF.cpp b/src/io/HMpsFF.cpp index 80bf0b897b..06ee0ea8f1 100644 --- a/src/io/HMpsFF.cpp +++ b/src/io/HMpsFF.cpp @@ -399,57 +399,63 @@ HMpsFF::Parsekey HMpsFF::checkFirstWord(std::string& strline, size_t& start, word = strline.substr(start, end - start); + // Create an upper-case version of WORD, so that keywords are + // read as if they were in lower or mixed case + std::string upper_word = word; + toupper(upper_word); + // store rest of strline for keywords that have arguments - if (word == "QCMATRIX" || word == "QSECTION" || word == "CSECTION") + if (upper_word == "QCMATRIX" || upper_word == "QSECTION" || + upper_word == "CSECTION") section_args = strline.substr(end, strline.length()); - if (word == "NAME") + if (upper_word == "NAME") return HMpsFF::Parsekey::kName; - else if (word == "OBJSENSE") + else if (upper_word == "OBJSENSE") return HMpsFF::Parsekey::kObjsense; - else if (word == "MAX") + else if (upper_word == "MAX") return HMpsFF::Parsekey::kMax; - else if (word == "MIN") + else if (upper_word == "MIN") return HMpsFF::Parsekey::kMin; - else if (word == "ROWS") + else if (upper_word == "ROWS") return HMpsFF::Parsekey::kRows; - else if (word == "COLUMNS") + else if (upper_word == "COLUMNS") return HMpsFF::Parsekey::kCols; - else if (word == "RHS") + else if (upper_word == "RHS") return HMpsFF::Parsekey::kRhs; - else if (word == "BOUNDS") + else if (upper_word == "BOUNDS") return HMpsFF::Parsekey::kBounds; - else if (word == "RANGES") + else if (upper_word == "RANGES") return HMpsFF::Parsekey::kRanges; - else if (word == "QSECTION") + else if (upper_word == "QSECTION") return HMpsFF::Parsekey::kQsection; - else if (word == "QMATRIX") + else if (upper_word == "QMATRIX") return HMpsFF::Parsekey::kQmatrix; - else if (word == "QUADOBJ") + else if (upper_word == "QUADOBJ") return HMpsFF::Parsekey::kQuadobj; - else if (word == "QCMATRIX") + else if (upper_word == "QCMATRIX") return HMpsFF::Parsekey::kQcmatrix; - else if (word == "CSECTION") + else if (upper_word == "CSECTION") return HMpsFF::Parsekey::kCsection; - else if (word == "DELAYEDROWS") + else if (upper_word == "DELAYEDROWS") return HMpsFF::Parsekey::kDelayedrows; - else if (word == "MODELCUTS") + else if (upper_word == "MODELCUTS") return HMpsFF::Parsekey::kModelcuts; - else if (word == "INDICATORS") + else if (upper_word == "INDICATORS") return HMpsFF::Parsekey::kIndicators; - else if (word == "SETS") + else if (upper_word == "SETS") return HMpsFF::Parsekey::kSets; - else if (word == "SOS") + else if (upper_word == "SOS") return HMpsFF::Parsekey::kSos; - else if (word == "GENCONS") + else if (upper_word == "GENCONS") return HMpsFF::Parsekey::kGencons; - else if (word == "PWLOBJ") + else if (upper_word == "PWLOBJ") return HMpsFF::Parsekey::kPwlobj; - else if (word == "PWLNAM") + else if (upper_word == "PWLNAM") return HMpsFF::Parsekey::kPwlnam; - else if (word == "PWLCON") + else if (upper_word == "PWLCON") return HMpsFF::Parsekey::kPwlcon; - else if (word == "ENDATA") + else if (upper_word == "ENDATA") return HMpsFF::Parsekey::kEnd; else return HMpsFF::Parsekey::kNone; @@ -496,6 +502,8 @@ HMpsFF::Parsekey HMpsFF::parseDefault(const HighsLogOptions& log_options, // Look for Gurobi-style definition of MAX/MIN on OBJSENSE line if (e < strline.length()) { std::string sense = first_word(strline, e); + // Convert to upper case + toupper(sense); if (sense.compare("MAX") == 0) { // Found MAX sense on OBJSENSE line obj_sense = ObjSense::kMaximize; diff --git a/src/ipm/IpxWrapper.cpp b/src/ipm/IpxWrapper.cpp index 37792e5152..51f84dec04 100644 --- a/src/ipm/IpxWrapper.cpp +++ b/src/ipm/IpxWrapper.cpp @@ -85,6 +85,7 @@ HighsStatus solveLpIpx(const HighsOptions& options, HighsTimer& timer, parameters.debug = 4; } parameters.highs_logging = true; + parameters.timeless_log = options.timeless_log; parameters.log_options = &options.log_options; // Just test feasibility and optimality tolerances for now // ToDo Set more parameters diff --git a/src/ipm/ipx/control.h b/src/ipm/ipx/control.h index d322b0d383..f234cec1ce 100644 --- a/src/ipm/ipx/control.h +++ b/src/ipm/ipx/control.h @@ -91,6 +91,7 @@ class Control { double centringRatioReduction() const {return parameters_.centring_ratio_reduction; } double centringAlphaScaling() const{return parameters_.centring_alpha_scaling; } ipxint badProductsTolerance() const{return parameters_.bad_products_tolerance; } + bool timelessLog() const{return parameters_.timeless_log; } const Parameters& parameters() const; void parameters(const Parameters& new_parameters); diff --git a/src/ipm/ipx/ipm.cc b/src/ipm/ipx/ipm.cc index 4a21364951..e1a9f2ec82 100644 --- a/src/ipm/ipx/ipm.cc +++ b/src/ipm/ipx/ipm.cc @@ -825,8 +825,9 @@ void IPM::PrintHeader() { << " " << Format("Iter", 4) << " " << Format("P.res", 8) << " " << Format("D.res", 8) << " " << Format("P.obj", 15) << " " << Format("D.obj", 15) - << " " << Format("mu", 8) - << " " << Format("Time", 7); + << " " << Format("mu", 8); + if (!control_.timelessLog()) + h_logging_stream << " " << Format("Time", 7); control_.hLog(h_logging_stream); control_.Debug() << " " << Format("stepsizes", 9) @@ -850,8 +851,9 @@ void IPM::PrintOutput() { << " " << Scientific(iterate_->dresidual(), 8, 2) << " " << Scientific(iterate_->pobjective_after_postproc(), 15, 8) << " " << Scientific(iterate_->dobjective_after_postproc(), 15, 8) - << " " << Scientific(iterate_->mu(), 8, 2) - << " " << Fixed(control_.Elapsed(), 6, 0) << "s"; + << " " << Scientific(iterate_->mu(), 8, 2); + if (!control_.timelessLog()) + h_logging_stream << " " << Fixed(control_.Elapsed(), 6, 0) << "s"; control_.hLog(h_logging_stream); control_.Debug() << " " << Fixed(step_primal_, 4, 2) << " " << Fixed(step_dual_, 4, 2) diff --git a/src/ipm/ipx/ipx_parameters.h b/src/ipm/ipx/ipx_parameters.h index 2f9db89186..7bffbc992b 100644 --- a/src/ipm/ipx/ipx_parameters.h +++ b/src/ipm/ipx/ipx_parameters.h @@ -64,6 +64,7 @@ struct ipx_parameters { /* HiGHS logging parameters */ bool highs_logging; + bool timeless_log; const HighsLogOptions* log_options; }; diff --git a/src/ipm/ipx/lp_solver.cc b/src/ipm/ipx/lp_solver.cc index 2276ec4e62..52b643a57a 100644 --- a/src/ipm/ipx/lp_solver.cc +++ b/src/ipm/ipx/lp_solver.cc @@ -649,9 +649,10 @@ void LpSolver::RunCrossover() { void LpSolver::PrintSummary() { std::stringstream h_logging_stream; h_logging_stream.str(std::string()); - h_logging_stream << "Summary\n" - << Textline("Runtime:") << fix2(control_.Elapsed()) << "s\n" - << Textline("Status interior point solve:") + h_logging_stream << "Summary\n"; + if (!control_.timelessLog()) + h_logging_stream << Textline("Runtime:") << fix2(control_.Elapsed()) << "s\n"; + h_logging_stream << Textline("Status interior point solve:") << StatusString(info_.status_ipm) << '\n' << Textline("Status crossover:") << StatusString(info_.status_crossover) << '\n'; diff --git a/src/lp_data/HConst.h b/src/lp_data/HConst.h index 178c84332a..d5fdf1ed60 100644 --- a/src/lp_data/HConst.h +++ b/src/lp_data/HConst.h @@ -316,4 +316,15 @@ const int8_t kPivotUnit = 1; const int8_t kPivotRowSingleton = 2; const int8_t kPivotColSingleton = 3; const int8_t kPivotMarkowitz = 4; + +// Mask for switching off PDLP features +enum PdlpFeaturesOff { + kPdlpAllFeaturesOn = 0, + kPdlpScalingOff = 1, + kPdlpRestartOff = 2, + kPdlpAdaptiveStepSizeOff = 4, + kPdlpAllFeaturesOff = + kPdlpScalingOff + kPdlpRestartOff + kPdlpAdaptiveStepSizeOff +}; + #endif /* LP_DATA_HCONST_H_ */ diff --git a/src/lp_data/Highs.cpp b/src/lp_data/Highs.cpp index 94ed199839..3da151d73a 100644 --- a/src/lp_data/Highs.cpp +++ b/src/lp_data/Highs.cpp @@ -1717,6 +1717,7 @@ HighsStatus Highs::getStandardFormLp(HighsInt& num_col, HighsInt& num_row, HighsInt& num_nz, double& offset, double* cost, double* rhs, HighsInt* start, HighsInt* index, double* value) { + this->logHeader(); if (!this->standard_form_valid_) { HighsStatus status = formStandardFormLp(); assert(status == HighsStatus::kOk); @@ -3874,10 +3875,13 @@ HighsStatus Highs::callSolveQp() { // Define the QP solver iteration logging function settings.iteration_log.subscribe([this](Statistics& stats) { int rep = stats.iteration.size() - 1; + std::string time_string = + options_.timeless_log ? "" + : highsFormatToString(" %9.2fs", stats.time[rep]); highsLogUser(options_.log_options, HighsLogType::kInfo, - "%11d %15.8g %6d %9.2fs\n", - int(stats.iteration[rep]), stats.objval[rep], - int(stats.nullspacedimension[rep]), stats.time[rep]); + "%11d %15.8g %6d%s\n", int(stats.iteration[rep]), + stats.objval[rep], int(stats.nullspacedimension[rep]), + time_string.c_str()); }); // Define the QP nullspace limit logging function @@ -4249,9 +4253,10 @@ HighsStatus Highs::callRunPostsolve(const HighsSolution& solution, // End of public methods void Highs::logHeader() { - if (written_log_header) return; + if (written_log_header_) return; + if (!*options_.log_options.output_flag) return; highsLogHeader(options_.log_options, options_.log_githash); - written_log_header = true; + written_log_header_ = true; return; } @@ -4611,9 +4616,11 @@ void Highs::reportSolvedLpQpStats() { highsLogUser(log_options, HighsLogType::kInfo, "Relative P-D gap : %17.10e\n", relative_primal_dual_gap); } - double run_time = timer_.read(); - highsLogUser(log_options, HighsLogType::kInfo, - "HiGHS run time : %13.2f\n", run_time); + if (!options_.timeless_log) { + double run_time = timer_.read(); + highsLogUser(log_options, HighsLogType::kInfo, + "HiGHS run time : %13.2f\n", run_time); + } } HighsStatus Highs::crossover(const HighsSolution& user_solution) { diff --git a/src/lp_data/HighsInterface.cpp b/src/lp_data/HighsInterface.cpp index 627338c7e1..4b0ea432e2 100644 --- a/src/lp_data/HighsInterface.cpp +++ b/src/lp_data/HighsInterface.cpp @@ -2009,6 +2009,7 @@ HighsStatus Highs::getIisInterface() { max_iterations = std::max(iterations, max_iterations); } highsLogUser(options_.log_options, HighsLogType::kInfo, + " %d cols, %d rows, %d LPs solved" " (min / average / max) iteration count (%6d / %6.2g / % 6d)" " and time (%6.2f / %6.2f / % 6.2f) \n", int(this->iis_.col_index_.size()), diff --git a/src/lp_data/HighsLpUtils.cpp b/src/lp_data/HighsLpUtils.cpp index 6b6042fc03..fd270dee49 100644 --- a/src/lp_data/HighsLpUtils.cpp +++ b/src/lp_data/HighsLpUtils.cpp @@ -477,11 +477,14 @@ HighsStatus assessSemiVariables(HighsLp& lp, const HighsOptions& options, assert((HighsInt)lp.integrality_.size() == lp.num_col_); HighsInt num_illegal_lower = 0; HighsInt num_illegal_upper = 0; - HighsInt num_modified_upper = 0; + HighsInt num_tightened_upper = 0; HighsInt num_inconsistent_semi = 0; HighsInt num_non_semi = 0; HighsInt num_non_continuous_variables = 0; const double kLowerBoundMu = 10.0; + + std::vector& save_non_semi_variable_index = + lp.mods_.save_non_semi_variable_index; std::vector& inconsistent_semi_variable_index = lp.mods_.save_inconsistent_semi_variable_index; std::vector& inconsistent_semi_variable_lower_bound_value = @@ -515,7 +518,7 @@ HighsStatus assessSemiVariables(HighsLp& lp, const HighsOptions& options, // Semi-variables with zero lower bound are not semi if (lp.col_lower_[iCol] == 0) { num_non_semi++; - lp.mods_.save_non_semi_variable_index.push_back(iCol); + save_non_semi_variable_index.push_back(iCol); // Semi-integer become integer so still have a non-continuous variable if (lp.integrality_[iCol] == HighsVarType::kSemiInteger) num_non_continuous_variables++; @@ -535,7 +538,7 @@ HighsStatus assessSemiVariables(HighsLp& lp, const HighsOptions& options, tightened_semi_variable_upper_bound_index.push_back(iCol); tightened_semi_variable_upper_bound_value.push_back( kMaxSemiVariableUpper); - num_modified_upper++; + num_tightened_upper++; } } num_non_continuous_variables++; @@ -567,12 +570,12 @@ HighsStatus assessSemiVariables(HighsLp& lp, const HighsOptions& options, return_status = HighsStatus::kWarning; } const bool has_illegal_bounds = num_illegal_lower || num_illegal_upper; - if (num_modified_upper) { + if (num_tightened_upper) { highsLogUser(options.log_options, HighsLogType::kWarning, "%" HIGHSINT_FORMAT " semi-continuous/integer variable(s) have upper bounds " - "exceeding %g that can be modified to %g > %g*lower)\n", - num_modified_upper, kMaxSemiVariableUpper, + "exceeding %g that can be tightened to %g > %g*lower)\n", + num_tightened_upper, kMaxSemiVariableUpper, kMaxSemiVariableUpper, kLowerBoundMu); return_status = HighsStatus::kWarning; if (has_illegal_bounds) { @@ -580,10 +583,11 @@ HighsStatus assessSemiVariables(HighsLp& lp, const HighsOptions& options, assert(num_illegal_lower || num_illegal_upper); tightened_semi_variable_upper_bound_index.clear(); tightened_semi_variable_upper_bound_value.clear(); + num_tightened_upper = 0; } else { // Apply the upper bound tightenings, saving the over-written // values - for (HighsInt k = 0; k < num_modified_upper; k++) { + for (HighsInt k = 0; k < num_tightened_upper; k++) { const double use_upper_bound = tightened_semi_variable_upper_bound_value[k]; const HighsInt iCol = tightened_semi_variable_upper_bound_index[k]; @@ -599,6 +603,7 @@ HighsStatus assessSemiVariables(HighsLp& lp, const HighsOptions& options, inconsistent_semi_variable_lower_bound_value.clear(); inconsistent_semi_variable_upper_bound_value.clear(); inconsistent_semi_variable_type.clear(); + num_inconsistent_semi = 0; } else { for (HighsInt k = 0; k < num_inconsistent_semi; k++) { const HighsInt iCol = inconsistent_semi_variable_index[k]; @@ -611,10 +616,10 @@ HighsStatus assessSemiVariables(HighsLp& lp, const HighsOptions& options, if (num_non_semi) { if (has_illegal_bounds) { // Don't apply type changes if there are illegal bounds - lp.mods_.save_non_semi_variable_index.clear(); + save_non_semi_variable_index.clear(); } else { for (HighsInt k = 0; k < num_non_semi; k++) { - const HighsInt iCol = lp.mods_.save_non_semi_variable_index[k]; + const HighsInt iCol = save_non_semi_variable_index[k]; if (lp.integrality_[iCol] == HighsVarType::kSemiContinuous) { // Semi-continuous become continuous lp.integrality_[iCol] = HighsVarType::kContinuous; @@ -643,9 +648,14 @@ HighsStatus assessSemiVariables(HighsLp& lp, const HighsOptions& options, return_status = HighsStatus::kError; } made_semi_variable_mods = - lp.mods_.save_non_semi_variable_index.size() > 0 || - inconsistent_semi_variable_index.size() > 0 || - tightened_semi_variable_upper_bound_index.size() > 0; + num_non_semi > 0 || num_inconsistent_semi > 0 || num_tightened_upper > 0; + assert(num_non_semi <= save_non_semi_variable_index.size()); + assert(num_inconsistent_semi <= inconsistent_semi_variable_index.size()); + assert(num_tightened_upper <= + tightened_semi_variable_upper_bound_index.size()); + // save_non_semi_variable_index.size() > 0 || + // inconsistent_semi_variable_index.size() > 0 || + // tightened_semi_variable_upper_bound_index.size() > 0; return return_status; } @@ -676,11 +686,11 @@ bool activeModifiedUpperBounds(const HighsOptions& options, const HighsLp& lp, const std::vector col_value) { const std::vector& tightened_semi_variable_upper_bound_index = lp.mods_.save_tightened_semi_variable_upper_bound_index; - const HighsInt num_modified_upper = + const HighsInt num_tightened_upper = tightened_semi_variable_upper_bound_index.size(); HighsInt num_active_modified_upper = 0; double min_semi_variable_margin = kHighsInf; - for (HighsInt k = 0; k < num_modified_upper; k++) { + for (HighsInt k = 0; k < num_tightened_upper; k++) { const double value = col_value[tightened_semi_variable_upper_bound_index[k]]; const double upper = @@ -699,7 +709,7 @@ bool activeModifiedUpperBounds(const HighsOptions& options, const HighsLp& lp, "%" HIGHSINT_FORMAT " semi-variables are active at modified upper bounds\n", num_active_modified_upper); - } else if (num_modified_upper) { + } else if (num_tightened_upper) { highsLogUser(options.log_options, HighsLogType::kWarning, "No semi-variables are active at modified upper bounds:" " a large minimum margin (%g) suggests optimality," diff --git a/src/lp_data/HighsOptions.h b/src/lp_data/HighsOptions.h index ceeabbb1cc..5797ba1cd7 100644 --- a/src/lp_data/HighsOptions.h +++ b/src/lp_data/HighsOptions.h @@ -335,14 +335,16 @@ struct HighsOptionsStruct { // Control of HiGHS log bool output_flag; bool log_to_console; + bool timeless_log; // Options for IPM solver HighsInt ipm_iteration_limit; // Options for PDLP solver + HighsInt pdlp_features_off; bool pdlp_native_termination; - bool pdlp_scaling; HighsInt pdlp_iteration_limit; + HighsInt pdlp_scaling_mode; HighsInt pdlp_e_restart_method; double pdlp_d_gap_tol; @@ -485,10 +487,12 @@ struct HighsOptionsStruct { write_presolved_model_file(""), output_flag(false), log_to_console(false), + timeless_log(false), ipm_iteration_limit(0), + pdlp_features_off(0), pdlp_native_termination(false), - pdlp_scaling(false), pdlp_iteration_limit(0), + pdlp_scaling_mode(0), pdlp_e_restart_method(0), pdlp_d_gap_tol(0.0), qp_iteration_limit(0), @@ -771,7 +775,7 @@ class HighsOptions : public HighsOptionsStruct { record_int = new OptionRecordInt( "simplex_strategy", "Strategy for simplex solver 0 => Choose; 1 => Dual (serial); 2 => " - "Dual (PAMI); 3 => Dual (SIP); 4 => Primal", + "Dual (SIP); 3 => Dual (PAMI); 4 => Primal", advanced, &simplex_strategy, kSimplexStrategyMin, kSimplexStrategyDual, kSimplexStrategyMax); records.push_back(record_int); @@ -847,6 +851,11 @@ class HighsOptions : public HighsOptionsStruct { advanced, &log_to_console, true); records.push_back(record_bool); + record_bool = new OptionRecordBool( + "timeless_log", "Suppression of time-based data in logging", true, + &timeless_log, false); + records.push_back(record_bool); + record_string = new OptionRecordString(kSolutionFileString, "Solution file", advanced, &solution_file, kHighsFilenameDefault); @@ -1084,26 +1093,35 @@ class HighsOptions : public HighsOptionsStruct { &ipm_iteration_limit, 0, kHighsIInf, kHighsIInf); records.push_back(record_int); + record_int = new OptionRecordInt( + "pdlp_features_off", + "Mask for switching PDLP features off: 1 => Scaling; 2 => Restart; 4 " + "=> AdaptiveStepSize", + advanced, &pdlp_features_off, kPdlpAllFeaturesOn, kPdlpAllFeaturesOn, + kPdlpAllFeaturesOff); + records.push_back(record_int); + record_bool = new OptionRecordBool( "pdlp_native_termination", "Use native termination for PDLP solver: Default = false", advanced, &pdlp_native_termination, false); records.push_back(record_bool); - record_bool = new OptionRecordBool( - "pdlp_scaling", "Scaling option for PDLP solver: Default = true", - advanced, &pdlp_scaling, true); - records.push_back(record_bool); - record_int = new OptionRecordInt( "pdlp_iteration_limit", "Iteration limit for PDLP solver", advanced, &pdlp_iteration_limit, 0, kHighsIInf, kHighsIInf); records.push_back(record_int); + record_int = new OptionRecordInt("pdlp_scaling_mode", + "Scaling mode for PDLP solver (default = " + "5): 1 => Ruiz; 2 => L2; 4 => PC", + advanced, &pdlp_scaling_mode, 0, 5, 7); + records.push_back(record_int); + record_int = new OptionRecordInt("pdlp_e_restart_method", "Restart mode for PDLP solver: 0 => none; " - "1 => GPU (default); 2 => CPU ", - advanced, &pdlp_e_restart_method, 0, 1, 2); + "1 => GPU", + advanced, &pdlp_e_restart_method, 0, 1, 1); records.push_back(record_int); record_double = new OptionRecordDouble( diff --git a/src/lp_data/HighsSolution.cpp b/src/lp_data/HighsSolution.cpp index a28060861a..9677e257b1 100644 --- a/src/lp_data/HighsSolution.cpp +++ b/src/lp_data/HighsSolution.cpp @@ -265,7 +265,6 @@ void getKktFailures(const HighsOptions& options, const HighsLp& lp, lower = lp.row_lower_[iRow]; upper = lp.row_upper_[iRow]; value = solution.row_value[iRow]; - // @FlipRowDual -solution.row_dual[iRow]; became solution.row_dual[iRow]; if (have_dual_solution) dual = solution.row_dual[iRow]; if (have_basis) status = basis.row_status[iRow]; integrality = HighsVarType::kContinuous; @@ -349,7 +348,6 @@ void getKktFailures(const HighsOptions& options, const HighsLp& lp, } else { primal_negative_sum[iRow] -= term; } - // @FlipRowDual += became -= if (have_dual_solution) { double term = -solution.row_dual[iRow] * Avalue; if (term > 0) { @@ -362,45 +360,10 @@ void getKktFailures(const HighsOptions& options, const HighsLp& lp, } } - if (have_dual_solution) { - // Determine the sum of complementarity violations - max_complementarity_violation = 0; - sum_complementarity_violations = 0; - double primal_residual = 0; - for (HighsInt iVar = 0; iVar < lp.num_col_ + lp.num_row_; iVar++) { - const bool is_col = iVar < lp.num_col_; - const HighsInt iRow = iVar - lp.num_col_; - const double primal = - is_col ? solution.col_value[iVar] : solution.row_value[iRow]; - const double dual = - is_col ? solution.col_dual[iVar] : solution.row_dual[iRow]; - const double lower = is_col ? lp.col_lower_[iVar] : lp.row_lower_[iRow]; - const double upper = is_col ? lp.col_upper_[iVar] : lp.row_upper_[iRow]; - if (lower <= -kHighsInf && upper >= kHighsInf) { - // Free - primal_residual = 1; - } else { - const double mid = (lower + upper) * 0.5; - primal_residual = primal < mid ? std::fabs(lower - primal) - : std::fabs(upper - primal); - } - const double dual_residual = std::fabs(dual); - const double complementarity_violation = primal_residual * dual_residual; - sum_complementarity_violations += complementarity_violation; - max_complementarity_violation = - std::max(complementarity_violation, max_complementarity_violation); - } - double check_max_complementarity_violation; - double check_sum_complementarity_violations; - const bool have_values = getComplementarityViolations( - lp, solution, check_max_complementarity_violation, - check_sum_complementarity_violations); - assert(have_values); - assert(check_max_complementarity_violation == - max_complementarity_violation); - assert(check_sum_complementarity_violations == - sum_complementarity_violations); - } + // Determine the sum of complementarity violations + if (have_dual_solution) + getComplementarityViolations(lp, solution, max_complementarity_violation, + sum_complementarity_violations); if (get_residuals) { const double large_residual_error = 1e-12; @@ -582,8 +545,7 @@ bool getComplementarityViolations(const HighsLp& lp, const HighsSolution& solution, double& max_complementarity_violation, double& sum_complementarity_violations) { - max_complementarity_violation = kHighsIllegalComplementarityViolation; - sum_complementarity_violations = kHighsIllegalComplementarityViolation; + assert(solution.dual_valid); if (!solution.dual_valid) return false; max_complementarity_violation = 0; @@ -840,10 +802,7 @@ HighsStatus ipxSolutionToHighsSolution( options.log_options, HighsLogType::kInfo, "ipxSolutionToHighsSolution: Norm of delta row values is %10.4g\n", delta_norm); - const bool force_dual_feasibility = false; // true; - const bool minimal_truncation = true; - if (model_status == HighsModelStatus::kOptimal && - (force_dual_feasibility || minimal_truncation)) { + if (model_status == HighsModelStatus::kOptimal) { double primal_truncation_norm = 0; double dual_truncation_norm = 0; double col_primal_truncation_norm = 0; @@ -914,7 +873,7 @@ HighsStatus ipxSolutionToHighsSolution( // Continue if no dual infeasibility if (dual_infeasibility <= dual_feasibility_tolerance) continue; - if (residual < dual_infeasibility && !force_dual_feasibility) { + if (residual < dual_infeasibility) { /* // Residual is less than dual infeasibility, or not forcing // dual feasibility, so truncate value @@ -1190,7 +1149,6 @@ HighsStatus ipxBasicSolutionToHighsBasicSolution( double slack_value = ipx_col_value[ipx_slack]; double slack_dual = ipx_col_dual[ipx_slack]; double value = slack_value; - // @FlipRowDual -slack_dual became slack_dual double dual = slack_dual; if (ipx_row_status[ipx_row] == ipx_basic) { // Row is basic @@ -1238,7 +1196,6 @@ HighsStatus ipxBasicSolutionToHighsBasicSolution( assert(ipx_row_status[ipx_row] == -1); // const ipx::Int ipx_nonbasic_row = -1; double value = rhs[ipx_row] - ipx_row_value[ipx_row]; - // @FlipRowDual -ipx_row_dual[ipx_row]; became ipx_row_dual[ipx_row]; double dual = ipx_row_dual[ipx_row]; if (constraint_type[ipx_row] == '>') { // Row is at its lower bound diff --git a/src/lp_data/HighsSolve.cpp b/src/lp_data/HighsSolve.cpp index acc81abf43..1838b751fb 100644 --- a/src/lp_data/HighsSolve.cpp +++ b/src/lp_data/HighsSolve.cpp @@ -84,10 +84,34 @@ HighsStatus solveLp(HighsLpSolverObject& solver_object, const string message) { solver_object.lp_.objectiveValue(solver_object.solution_.col_value); getLpKktFailures(options, solver_object.lp_, solver_object.solution_, solver_object.basis_, solver_object.highs_info_); - if (solver_object.model_status_ == HighsModelStatus::kOptimal && - (solver_object.highs_info_.num_primal_infeasibilities > 0 || - solver_object.highs_info_.num_dual_infeasibilities)) - solver_object.model_status_ = HighsModelStatus::kUnknown; + if (solver_object.model_status_ == HighsModelStatus::kOptimal) { + const HighsInfo& info = solver_object.highs_info_; + if (info.num_primal_infeasibilities || info.num_dual_infeasibilities) { + highsLogUser(options.log_options, HighsLogType::kWarning, + "Solver %s claims optimality, but with\n", + options.solver.c_str()); + if (info.num_primal_infeasibilities) + highsLogUser( + options.log_options, HighsLogType::kWarning, + " num/max/sum %6d / %9.4g / %9.4g primal infeasibilities\n", + int(info.num_primal_infeasibilities), + info.max_primal_infeasibility, info.sum_primal_infeasibilities); + if (info.num_dual_infeasibilities) + highsLogUser( + options.log_options, HighsLogType::kWarning, + " num/max/sum %6d / %9.4g / %9.4g dual infeasibilities\n", + int(info.num_dual_infeasibilities), info.max_dual_infeasibility, + info.sum_dual_infeasibilities); + highsLogUser(options.log_options, HighsLogType::kWarning, + " and max/sum %9.4g / %9.4g " + "complementarity violations\n", + info.max_complementarity_violation, + info.sum_complementarity_violations); + highsLogUser(options.log_options, HighsLogType::kWarning, + " so set model status to \"unknown\"\n"); + solver_object.model_status_ = HighsModelStatus::kUnknown; + } + } if (options.solver == kIpmString || options.run_centring) { // Setting the IPM-specific values of (highs_)info_ has been done in // solveLpIpx diff --git a/src/mip/HighsCutGeneration.cpp b/src/mip/HighsCutGeneration.cpp index 7149ea0362..d9552d418f 100644 --- a/src/mip/HighsCutGeneration.cpp +++ b/src/mip/HighsCutGeneration.cpp @@ -1388,6 +1388,8 @@ bool HighsCutGeneration::tryGenerateCut(std::vector& inds_, // the lifting functions have minimality of the cover as necessary facet // condition bool success = false; + bool saveIntegalSupport = false; + bool saveIntegralCoefficients = false; do { if (!determineCover(lpSol)) break; @@ -1409,6 +1411,11 @@ bool HighsCutGeneration::tryGenerateCut(std::vector& inds_, double minMirEfficacy = minEfficacy; if (success) { + // save data that might otherwise be overwritten when calling the cmir + // separator + saveIntegalSupport = integralSupport; + saveIntegralCoefficients = integralCoefficients; + // compute violation and squared norm double violation = -double(rhs); double sqrnorm = 0.0; @@ -1434,11 +1441,6 @@ bool HighsCutGeneration::tryGenerateCut(std::vector& inds_, inds = tmpInds.data(); vals = tmpVals.data(); - // save data that might otherwise be overwritten when calling the cmir - // separator - bool saveIntegalSupport = integralSupport; - bool saveIntegralCoefficients = integralCoefficients; - if (cmirCutGenerationHeuristic(minMirEfficacy, onlyInitialCMIRScale)) { // take the cmir cut as it is better inds_.swap(tmpInds); diff --git a/src/mip/HighsImplications.cpp b/src/mip/HighsImplications.cpp index a40ac8dddd..7e1c1d62bc 100644 --- a/src/mip/HighsImplications.cpp +++ b/src/mip/HighsImplications.cpp @@ -697,42 +697,11 @@ void HighsImplications::cleanupVarbounds(HighsInt col) { std::vector delVbds; vubs[col].for_each([&](HighsInt vubCol, VarBound& vub) { - mipsolver.mipdata_->debugSolution.checkVub(col, vubCol, vub.coef, - vub.constant); - - if (vub.coef > 0) { - double minub = vub.constant; - double maxub = vub.constant + vub.coef; - if (minub >= ub - mipsolver.mipdata_->feastol) - delVbds.push_back(vubCol); // variable bound is redundant - else if (maxub > ub + mipsolver.mipdata_->epsilon) { - vub.coef = ub - vub.constant; // coefficient can be tightened - mipsolver.mipdata_->debugSolution.checkVub(col, vubCol, vub.coef, - vub.constant); - } else if (maxub < ub - mipsolver.mipdata_->epsilon) { - mipsolver.mipdata_->domain.changeBound( - HighsBoundType::kUpper, col, maxub, - HighsDomain::Reason::unspecified()); - if (mipsolver.mipdata_->domain.infeasible()) return; - } - } else { - HighsCDouble minub = HighsCDouble(vub.constant) + vub.coef; - double maxub = vub.constant; - if (minub >= ub - mipsolver.mipdata_->feastol) - delVbds.push_back(vubCol); // variable bound is redundant - else if (maxub > ub + mipsolver.mipdata_->epsilon) { - // variable bound can be tightened - vub.constant = ub; - vub.coef = double(minub - ub); - mipsolver.mipdata_->debugSolution.checkVub(col, vubCol, vub.coef, - vub.constant); - } else if (maxub < ub - mipsolver.mipdata_->epsilon) { - mipsolver.mipdata_->domain.changeBound( - HighsBoundType::kUpper, col, maxub, - HighsDomain::Reason::unspecified()); - if (mipsolver.mipdata_->domain.infeasible()) return; - } - } + bool redundant = false; + bool infeasible = false; + cleanupVub(col, vubCol, vub, ub, redundant, infeasible); + if (redundant) delVbds.push_back(vubCol); + if (infeasible) return; }); if (!delVbds.empty()) { @@ -741,44 +710,94 @@ void HighsImplications::cleanupVarbounds(HighsInt col) { } vlbs[col].for_each([&](HighsInt vlbCol, VarBound& vlb) { - mipsolver.mipdata_->debugSolution.checkVlb(col, vlbCol, vlb.coef, - vlb.constant); + bool redundant = false; + bool infeasible = false; + cleanupVlb(col, vlbCol, vlb, lb, redundant, infeasible); + if (redundant) delVbds.push_back(vlbCol); + if (infeasible) return; + }); - if (vlb.coef > 0) { - HighsCDouble maxlb = HighsCDouble(vlb.constant) + vlb.coef; - double minlb = vlb.constant; - if (maxlb <= lb + mipsolver.mipdata_->feastol) - delVbds.push_back(vlbCol); // variable bound is redundant - else if (minlb < lb - mipsolver.mipdata_->epsilon) { - // variable bound can be tightened - vlb.constant = lb; - vlb.coef = double(maxlb - lb); - mipsolver.mipdata_->debugSolution.checkVlb(col, vlbCol, vlb.coef, - vlb.constant); - } else if (minlb > lb + mipsolver.mipdata_->epsilon) { - mipsolver.mipdata_->domain.changeBound( - HighsBoundType::kLower, col, minlb, - HighsDomain::Reason::unspecified()); - if (mipsolver.mipdata_->domain.infeasible()) return; - } + for (HighsInt vlbCol : delVbds) vlbs[col].erase(vlbCol); +} +void HighsImplications::cleanupVlb(HighsInt col, HighsInt vlbCol, + HighsImplications::VarBound& vlb, double lb, + bool& redundant, bool& infeasible, + bool allowBoundChanges) const { + // initialize + redundant = false; + infeasible = false; + + // return if there is no variable bound + if (vlbCol == -1) return; + + // check variable lower bound + mipsolver.mipdata_->debugSolution.checkVlb(col, vlbCol, vlb.coef, + vlb.constant); + + HighsCDouble maxlb = vlb.maxValue(); + HighsCDouble minlb = vlb.minValue(); + + if (maxlb <= lb + mipsolver.mipdata_->feastol) { + // variable bound is redundant + redundant = true; + } else if (minlb < lb - mipsolver.mipdata_->epsilon) { + // coefficient can be tightened + double newcoef = static_cast(lb - maxlb); + if (vlb.coef < 0) { + vlb.coef = newcoef; } else { - double maxlb = vlb.constant; - double minlb = vlb.constant + vlb.coef; - if (maxlb <= lb + mipsolver.mipdata_->feastol) - delVbds.push_back(vlbCol); // variable bound is redundant - else if (minlb < lb - mipsolver.mipdata_->epsilon) { - vlb.coef = lb - vlb.constant; // variable bound can be tightened - mipsolver.mipdata_->debugSolution.checkVlb(col, vlbCol, vlb.coef, - vlb.constant); - } else if (minlb > lb + mipsolver.mipdata_->epsilon) { - mipsolver.mipdata_->domain.changeBound( - HighsBoundType::kLower, col, minlb, - HighsDomain::Reason::unspecified()); - if (mipsolver.mipdata_->domain.infeasible()) return; - } + vlb.constant = lb; + vlb.coef = -newcoef; } - }); + // check tightened variable lower bound + mipsolver.mipdata_->debugSolution.checkVlb(col, vlbCol, vlb.coef, + vlb.constant); + } else if (allowBoundChanges && minlb > lb + mipsolver.mipdata_->epsilon) { + mipsolver.mipdata_->domain.changeBound(HighsBoundType::kLower, col, + static_cast(minlb), + HighsDomain::Reason::unspecified()); + infeasible = mipsolver.mipdata_->domain.infeasible(); + } +} - for (HighsInt vlbCol : delVbds) vlbs[col].erase(vlbCol); +void HighsImplications::cleanupVub(HighsInt col, HighsInt vubCol, + HighsImplications::VarBound& vub, double ub, + bool& redundant, bool& infeasible, + bool allowBoundChanges) const { + // initialize + redundant = false; + infeasible = false; + + // return if there is no variable bound + if (vubCol == -1) return; + + // check variable upper bound + mipsolver.mipdata_->debugSolution.checkVub(col, vubCol, vub.coef, + vub.constant); + + HighsCDouble maxub = vub.maxValue(); + HighsCDouble minub = vub.minValue(); + + if (minub >= ub - mipsolver.mipdata_->feastol) { + // variable bound is redundant + redundant = true; + } else if (maxub > ub + mipsolver.mipdata_->epsilon) { + // coefficient can be tightened + double newcoef = static_cast(ub - minub); + if (vub.coef > 0) { + vub.coef = newcoef; + } else { + vub.constant = ub; + vub.coef = -newcoef; + } + // check tightened variable upper bound + mipsolver.mipdata_->debugSolution.checkVub(col, vubCol, vub.coef, + vub.constant); + } else if (allowBoundChanges && maxub < ub - mipsolver.mipdata_->epsilon) { + mipsolver.mipdata_->domain.changeBound(HighsBoundType::kUpper, col, + static_cast(maxub), + HighsDomain::Reason::unspecified()); + infeasible = mipsolver.mipdata_->domain.infeasible(); + } } diff --git a/src/mip/HighsImplications.h b/src/mip/HighsImplications.h index 3fc3e61de3..9761b339c8 100644 --- a/src/mip/HighsImplications.h +++ b/src/mip/HighsImplications.h @@ -37,8 +37,14 @@ class HighsImplications { double coef; double constant; - double minValue() const { return constant + std::min(coef, 0.0); } - double maxValue() const { return constant + std::max(coef, 0.0); } + double minValue() const { + return static_cast(static_cast(constant) + + std::min(coef, 0.0)); + } + double maxValue() const { + return static_cast(static_cast(constant) + + std::max(coef, 0.0)); + } }; private: @@ -148,6 +154,14 @@ class HighsImplications { HighsCutPool& cutpool, double feastol); void cleanupVarbounds(HighsInt col); + + void cleanupVlb(HighsInt col, HighsInt vlbCol, + HighsImplications::VarBound& vlb, double lb, bool& redundant, + bool& infeasible, bool allowBoundChanges = true) const; + + void cleanupVub(HighsInt col, HighsInt vubCol, + HighsImplications::VarBound& vub, double ub, bool& redundant, + bool& infeasible, bool allowBoundChanges = true) const; }; #endif diff --git a/src/mip/HighsMipAnalysis.cpp b/src/mip/HighsMipAnalysis.cpp index cdd773960c..7a6ea2d486 100644 --- a/src/mip/HighsMipAnalysis.cpp +++ b/src/mip/HighsMipAnalysis.cpp @@ -13,6 +13,7 @@ #include #include "mip/MipTimer.h" +#include "util/HighsUtils.h" const HighsInt check_mip_clock = -4; @@ -153,4 +154,8 @@ void HighsMipAnalysis::reportMipTimer() { reportMipSolveLpClock(true); mip_timer.csvMipClock(this->model_name, mip_clocks, false, false); reportMipSolveLpClock(false); + analyseVectorValues(nullptr, "Node search time", + HighsInt(node_search_time.size()), node_search_time); + analyseVectorValues(nullptr, "Dive time", HighsInt(dive_time.size()), + dive_time); } diff --git a/src/mip/HighsMipAnalysis.h b/src/mip/HighsMipAnalysis.h index 9b6a098dc7..20ab0bd4d0 100644 --- a/src/mip/HighsMipAnalysis.h +++ b/src/mip/HighsMipAnalysis.h @@ -42,6 +42,8 @@ class HighsMipAnalysis { std::string model_name; HighsTimerClock mip_clocks; bool analyse_mip_time; + std::vector dive_time; + std::vector node_search_time; }; #endif /* MIP_HIGHSMIPANALYSIS_H_ */ diff --git a/src/mip/HighsMipSolver.cpp b/src/mip/HighsMipSolver.cpp index d8c03b471b..e1aa17c63d 100644 --- a/src/mip/HighsMipSolver.cpp +++ b/src/mip/HighsMipSolver.cpp @@ -129,7 +129,7 @@ void HighsMipSolver::run() { mipdata_->runPresolve(options_mip_->presolve_reduction_limit); analysis_.mipTimerStop(kMipClockRunPresolve); analysis_.mipTimerStop(kMipClockPresolve); - if (analysis_.analyse_mip_time & !submip) + if (analysis_.analyse_mip_time && !submip) highsLogUser(options_mip_->log_options, HighsLogType::kInfo, "MIP-Timing: %11.2g - completed presolve\n", timer_.read()); // Identify whether time limit has been reached (in presolve) @@ -153,13 +153,13 @@ void HighsMipSolver::run() { analysis_.mipTimerStart(kMipClockSolve); - if (analysis_.analyse_mip_time & !submip) + if (analysis_.analyse_mip_time && !submip) highsLogUser(options_mip_->log_options, HighsLogType::kInfo, "MIP-Timing: %11.2g - starting setup\n", timer_.read()); analysis_.mipTimerStart(kMipClockRunSetup); mipdata_->runSetup(); analysis_.mipTimerStop(kMipClockRunSetup); - if (analysis_.analyse_mip_time & !submip) + if (analysis_.analyse_mip_time && !submip) highsLogUser(options_mip_->log_options, HighsLogType::kInfo, "MIP-Timing: %11.2g - completed setup\n", timer_.read()); restart: @@ -180,7 +180,7 @@ void HighsMipSolver::run() { return; } analysis_.mipTimerStop(kMipClockTrivialHeuristics); - if (analysis_.analyse_mip_time & !submip) + if (analysis_.analyse_mip_time && !submip) highsLogUser(options_mip_->log_options, HighsLogType::kInfo, "MIP-Timing: %11.2g - starting evaluate root node\n", timer_.read()); @@ -192,7 +192,7 @@ void HighsMipSolver::run() { if (analysis_.analyse_mip_time && analysis_.mipTimerRunning(kMipClockIpmSolveLp)) analysis_.mipTimerStop(kMipClockIpmSolveLp); - if (analysis_.analyse_mip_time & !submip) + if (analysis_.analyse_mip_time && !submip) highsLogUser(options_mip_->log_options, HighsLogType::kInfo, "MIP-Timing: %11.2g - completed evaluate root node\n", timer_.read()); @@ -304,10 +304,14 @@ void HighsMipSolver::run() { if (mipdata_->domain.infeasible()) break; if (!search.currentNodePruned()) { + double this_dive_time = -analysis_.mipTimerRead(kMipClockTheDive); analysis_.mipTimerStart(kMipClockTheDive); const HighsSearch::NodeResult search_dive_result = search.dive(); analysis_.mipTimerStop(kMipClockTheDive); - + if (analysis_.analyse_mip_time) { + this_dive_time += analysis_.mipTimerRead(kMipClockNodeSearch); + analysis_.dive_time.push_back(this_dive_time); + } if (search_dive_result == HighsSearch::NodeResult::kSubOptimal) break; ++mipdata_->num_leaves; @@ -507,6 +511,7 @@ void HighsMipSolver::run() { // mipdata_->lp.setIterationLimit(); // loop to install the next node for the search + double this_node_search_time = -analysis_.mipTimerRead(kMipClockNodeSearch); analysis_.mipTimerStart(kMipClockNodeSearch); while (!mipdata_->nodequeue.empty()) { @@ -651,7 +656,10 @@ void HighsMipSolver::run() { break; } // while(!mipdata_->nodequeue.empty()) analysis_.mipTimerStop(kMipClockNodeSearch); - + if (analysis_.analyse_mip_time) { + this_node_search_time += analysis_.mipTimerRead(kMipClockNodeSearch); + analysis_.node_search_time.push_back(this_node_search_time); + } if (limit_reached) break; } // while(search.hasNode()) analysis_.mipTimerStop(kMipClockSearch); @@ -765,6 +773,7 @@ void HighsMipSolver::cleanupSolve() { gapValString.data()); } + bool timeless_log = options_mip_->timeless_log; highsLogUser(options_mip_->log_options, HighsLogType::kInfo, "\nSolving report\n"); if (this->orig_model_->model_name_.length()) @@ -775,12 +784,15 @@ void HighsMipSolver::cleanupSolve() { " Status %s\n" " Primal bound %.12g\n" " Dual bound %.12g\n" - " Gap %s\n" - " P-D integral %.12g\n" - " Solution status %s\n", + " Gap %s\n", utilModelStatusToString(modelstatus_).c_str(), primal_bound_, - dual_bound_, gapString.data(), - mipdata_->primal_dual_integral.value, solutionstatus.c_str()); + dual_bound_, gapString.data()); + if (!timeless_log) + highsLogUser(options_mip_->log_options, HighsLogType::kInfo, + " P-D integral %.12g\n", + mipdata_->primal_dual_integral.value); + highsLogUser(options_mip_->log_options, HighsLogType::kInfo, + " Solution status %s\n", solutionstatus.c_str()); if (solutionstatus != "-") highsLogUser(options_mip_->log_options, HighsLogType::kInfo, " %.12g (objective)\n" @@ -789,11 +801,16 @@ void HighsMipSolver::cleanupSolve() { " %.12g (row viol.)\n", solution_objective_, bound_violation_, integrality_violation_, row_violation_); + if (!timeless_log) + highsLogUser(options_mip_->log_options, HighsLogType::kInfo, + " Timing %.2f (total)\n" + " %.2f (presolve)\n" + " %.2f (solve)\n" + " %.2f (postsolve)\n", + timer_.read(), analysis_.mipTimerRead(kMipClockPresolve), + analysis_.mipTimerRead(kMipClockSolve), + analysis_.mipTimerRead(kMipClockPostsolve)); highsLogUser(options_mip_->log_options, HighsLogType::kInfo, - " Timing %.2f (total)\n" - " %.2f (presolve)\n" - " %.2f (solve)\n" - " %.2f (postsolve)\n" " Max sub-MIP depth %d\n" " Nodes %llu\n" " Repair LPs %llu (%llu feasible; %llu iterations)\n" @@ -801,9 +818,6 @@ void HighsMipSolver::cleanupSolve() { " %llu (strong br.)\n" " %llu (separation)\n" " %llu (heuristics)\n", - timer_.read(), analysis_.mipTimerRead(kMipClockPresolve), - analysis_.mipTimerRead(kMipClockSolve), - analysis_.mipTimerRead(kMipClockPostsolve), int(max_submip_level), (long long unsigned)mipdata_->num_nodes, (long long unsigned)mipdata_->total_repair_lp, (long long unsigned)mipdata_->total_repair_lp_feasible, @@ -813,7 +827,7 @@ void HighsMipSolver::cleanupSolve() { (long long unsigned)mipdata_->sepa_lp_iterations, (long long unsigned)mipdata_->heuristic_lp_iterations); - analysis_.reportMipTimer(); + if (!timeless_log) analysis_.reportMipTimer(); assert(modelstatus_ != HighsModelStatus::kNotset); } diff --git a/src/mip/HighsMipSolverData.cpp b/src/mip/HighsMipSolverData.cpp index 4c411f8ffc..26a15f0a4c 100644 --- a/src/mip/HighsMipSolverData.cpp +++ b/src/mip/HighsMipSolverData.cpp @@ -372,10 +372,9 @@ void HighsMipSolverData::finishAnalyticCenterComputation( } if (nfixed > 0) highsLogDev(mipsolver.options_mip_->log_options, HighsLogType::kInfo, - "Fixing %" HIGHSINT_FORMAT " columns (%" HIGHSINT_FORMAT - " integers) sitting at bound at " + "Fixing %d columns (%d integers) sitting at bound at " "analytic center\n", - nfixed, nintfixed); + int(nfixed), int(nintfixed)); mipsolver.mipdata_->domain.propagate(); if (mipsolver.mipdata_->domain.infeasible()) return; } @@ -406,9 +405,12 @@ void HighsMipSolverData::finishSymmetryDetection( taskGroup.sync(); symmetries = std::move(symData->symmetries); + std::string symmetry_time = + mipsolver.options_mip_->timeless_log + ? "" + : highsFormatToString(" %.1fs", symData->detectionTime); highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo, - "\nSymmetry detection completed in %.1fs\n", - symData->detectionTime); + "\nSymmetry detection completed in%s\n", symmetry_time.c_str()); if (symmetries.numGenerators == 0) { detectSymmetries = false; @@ -416,24 +418,20 @@ 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 " generator(s)\n\n", - symmetries.numGenerators); + "Found %d generator(s)\n\n", int(symmetries.numGenerators)); } else { if (symmetries.numPerms != 0) { - 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()); + highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo, + "Found %d generator(s) and %d full orbitope(s) acting on %d " + "columns\n\n", + int(symmetries.numPerms), int(symmetries.orbitopes.size()), + int(symmetries.columnToOrbitope.size())); } else { highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo, - "Found %" HIGHSINT_FORMAT - " full orbitope(s) acting on %" HIGHSINT_FORMAT - " columns\n\n", - (HighsInt)symmetries.orbitopes.size(), - (HighsInt)symmetries.columnToOrbitope.size()); + "Found %d full orbitope(s) acting on %d columns\n\n", + int(symmetries.orbitopes.size()), + int(symmetries.columnToOrbitope.size())); } } symData.reset(); @@ -678,6 +676,7 @@ void HighsMipSolverData::runSetup() { const HighsLp& model = *mipsolver.model_; last_disptime = -kHighsInf; + disptime = 0; // Transform the reference of the objective limit and lower/upper // bounds from the original model to the current model, undoing the @@ -759,8 +758,9 @@ void HighsMipSolverData::runSetup() { highsSparseTranspose(model.num_row_, model.num_col_, model.a_matrix_.start_, model.a_matrix_.index_, model.a_matrix_.value_, ARstart_, ARindex_, ARvalue_); - uplocks.resize(model.num_col_); - downlocks.resize(model.num_col_); + // (re-)initialize number of uplocks and downlocks + uplocks.assign(model.num_col_, 0); + downlocks.assign(model.num_col_, 0); for (HighsInt i = 0; i != model.num_col_; ++i) { HighsInt start = model.a_matrix_.start_[i]; HighsInt end = model.a_matrix_.start_[i + 1]; @@ -1598,21 +1598,26 @@ void HighsMipSolverData::printDisplayLine(const int solution_source) { bool output_flag = *mipsolver.options_mip_->log_options.output_flag; if (!output_flag) return; - double time = mipsolver.timer_.read(); + bool timeless_log = mipsolver.options_mip_->timeless_log; + disptime = timeless_log ? disptime + 1 : mipsolver.timer_.read(); if (solution_source == kSolutionSourceNone && - time - last_disptime < mipsolver.options_mip_->mip_min_logging_interval) + disptime - last_disptime < + mipsolver.options_mip_->mip_min_logging_interval) return; - last_disptime = time; + last_disptime = disptime; + std::string time_string = + timeless_log ? "" : highsFormatToString(" %7.1fs", disptime); if (num_disp_lines % 20 == 0) { if (num_disp_lines == 0) printSolutionSourceKey(); - highsLogUser( - mipsolver.options_mip_->log_options, HighsLogType::kInfo, - // clang-format off - "\n Nodes | B&B Tree | Objective Bounds | Dynamic Constraints | Work \n" - "Src Proc. InQueue | Leaves Expl. | BestBound BestSol Gap | Cuts InLp Confl. | LpIters Time\n\n" - // clang-format on - ); + std::string work_string0 = timeless_log ? " Work" : " Work "; + std::string work_string1 = timeless_log ? "LpIters" : "LpIters Time"; + highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo, + // clang-format off + "\n Nodes | B&B Tree | Objective Bounds | Dynamic Constraints | %s\n" + "Src Proc. InQueue | Leaves Expl. | BestBound BestSol Gap | Cuts InLp Confl. | %s\n\n", + // clang-format on + work_string0.c_str(), work_string1.c_str()); //" %7s | %10s | %10s | %10s | %10s | %-15s | %-15s | %7s | %7s " //"| %8s | %8s\n", @@ -1656,13 +1661,13 @@ void HighsMipSolverData::printDisplayLine(const int solution_source) { highsLogUser( mipsolver.options_mip_->log_options, HighsLogType::kInfo, // clang-format off - " %s %7s %7s %7s %6.2f%% %-15s %-15s %8s %6" HIGHSINT_FORMAT " %6" HIGHSINT_FORMAT " %6" HIGHSINT_FORMAT " %7s %7.1fs\n", + " %s %7s %7s %7s %6.2f%% %-15s %-15s %8s %6" HIGHSINT_FORMAT " %6" HIGHSINT_FORMAT " %6" HIGHSINT_FORMAT " %7s%s\n", // clang-format on solutionSourceToString(solution_source).c_str(), print_nodes.data(), queue_nodes.data(), print_leaves.data(), explored, lb_string.data(), ub_string.data(), gap_string.data(), cutpool.getNumCuts(), lp.numRows() - lp.getNumModelRows(), conflictPool.getNumConflicts(), - print_lp_iters.data(), time); + print_lp_iters.data(), time_string.c_str()); } else { std::array ub_string; if (mipsolver.options_mip_->objective_bound < ub) { @@ -1677,13 +1682,13 @@ void HighsMipSolverData::printDisplayLine(const int solution_source) { highsLogUser( mipsolver.options_mip_->log_options, HighsLogType::kInfo, // clang-format off - " %s %7s %7s %7s %6.2f%% %-15s %-15s %8.2f %6" HIGHSINT_FORMAT " %6" HIGHSINT_FORMAT " %6" HIGHSINT_FORMAT " %7s %7.1fs\n", + " %s %7s %7s %7s %6.2f%% %-15s %-15s %8.2f %6" HIGHSINT_FORMAT " %6" HIGHSINT_FORMAT " %6" HIGHSINT_FORMAT " %7s%s\n", // clang-format on solutionSourceToString(solution_source).c_str(), print_nodes.data(), queue_nodes.data(), print_leaves.data(), explored, lb_string.data(), ub_string.data(), gap, cutpool.getNumCuts(), lp.numRows() - lp.getNumModelRows(), conflictPool.getNumConflicts(), - print_lp_iters.data(), time); + print_lp_iters.data(), time_string.c_str()); } // Check that limitsToBounds yields the same values for the // dual_bound, primal_bound (modulo optimization sense) and @@ -1960,6 +1965,7 @@ void HighsMipSolverData::evaluateRootNode() { // make sure first line after solving root LP is printed last_disptime = -kHighsInf; + disptime = 0; mipsolver.analysis_.mipTimerStart(kMipClockRandomizedRounding1); heuristics.randomizedRounding(firstlpsol); diff --git a/src/mip/HighsMipSolverData.h b/src/mip/HighsMipSolverData.h index 080016b9a9..8678751e45 100644 --- a/src/mip/HighsMipSolverData.h +++ b/src/mip/HighsMipSolverData.h @@ -118,6 +118,7 @@ struct HighsMipSolverData { HighsCDouble pruned_treeweight; double avgrootlpiters; + double disptime; double last_disptime; int64_t firstrootlpiters; int64_t num_nodes; @@ -183,6 +184,7 @@ struct HighsMipSolverData { maxTreeSizeLog2(0), pruned_treeweight(0), avgrootlpiters(0.0), + disptime(0.0), last_disptime(0.0), firstrootlpiters(0), num_nodes(0), diff --git a/src/mip/HighsTransformedLp.cpp b/src/mip/HighsTransformedLp.cpp index 7960290227..703b377e09 100644 --- a/src/mip/HighsTransformedLp.cpp +++ b/src/mip/HighsTransformedLp.cpp @@ -175,6 +175,36 @@ bool HighsTransformedLp::transform(std::vector& vals, return false; } + // the code below uses the difference between the column upper and lower + // bounds as the upper bound for the slack from the variable upper bound + // constraint (upper[j] = ub - lb) and thus assumes that the variable upper + // bound constraints are tight. this assumption may not be satisfied when + // new bound changes were derived during cut generation and, therefore, we + // tighten the best variable upper bound. + if (bestVub[col].first != -1 && + bestVub[col].second.maxValue() > ub + mip.mipdata_->feastol) { + bool redundant = false; + bool infeasible = false; + mip.mipdata_->implications.cleanupVub(col, bestVub[col].first, + bestVub[col].second, ub, redundant, + infeasible, false); + } + + // the code below uses the difference between the column upper and lower + // bounds as the upper bound for the slack from the variable lower bound + // constraint (upper[j] = ub - lb) and thus assumes that the variable lower + // bound constraints are tight. this assumption may not be satisfied when + // new bound changes were derived during cut generation and, therefore, we + // tighten the best variable lower bound. + if (bestVlb[col].first != -1 && + bestVlb[col].second.minValue() < lb - mip.mipdata_->feastol) { + bool redundant = false; + bool infeasible = false; + mip.mipdata_->implications.cleanupVlb(col, bestVlb[col].first, + bestVlb[col].second, lb, redundant, + infeasible, false); + } + // store the old bound type so that we can restore it if the continuous // column is relaxed out anyways. This allows to correctly transform and // then untransform multiple base rows which is useful to compute cuts based @@ -190,10 +220,18 @@ bool HighsTransformedLp::transform(std::vector& vals, if (ub - lb <= 1.5 || boundDist[col] != 0.0 || simpleLbDist[col] == 0 || simpleUbDist[col] == 0) { // since we skip the handling of variable bound constraints for all - // binary and some general-integer variables, the bound type used should - // be a simple lower or upper bound - assert(oldBoundType == BoundType::kSimpleLb || - oldBoundType == BoundType::kSimpleUb); + // binary and some general-integer variables here, the bound type used + // should be a simple lower or upper bound + if (simpleLbDist[col] < simpleUbDist[col] - mip.mipdata_->feastol) { + boundTypes[col] = BoundType::kSimpleLb; + } else if (simpleUbDist[col] < + simpleLbDist[col] - mip.mipdata_->feastol) { + boundTypes[col] = BoundType::kSimpleUb; + } else if (vals[i] > 0) { + boundTypes[col] = BoundType::kSimpleLb; + } else { + boundTypes[col] = BoundType::kSimpleUb; + } i++; continue; } diff --git a/src/mip/MipTimer.h b/src/mip/MipTimer.h index 05d8cfca12..6b04972612 100644 --- a/src/mip/MipTimer.h +++ b/src/mip/MipTimer.h @@ -334,7 +334,7 @@ class MipTimer { const bool end_line) { const std::vector mip_clock_list{ kMipClockRunPresolve, kMipClockEvaluateRootNode, - kMipClockPrimalHeuristics, kMipClockTheDive}; + kMipClockPrimalHeuristics, kMipClockTheDive, kMipClockNodeSearch}; csvMipClockList(model_name, mip_clock_list, mip_timer_clock, kMipClockTotal, header, end_line); }; diff --git a/src/pdlp/CupdlpWrapper.cpp b/src/pdlp/CupdlpWrapper.cpp index f48fc9b89d..8ce4b12548 100644 --- a/src/pdlp/CupdlpWrapper.cpp +++ b/src/pdlp/CupdlpWrapper.cpp @@ -108,8 +108,9 @@ HighsStatus solveLpCupdlp(const HighsOptions& options, HighsTimer& timer, const cupdlp_int local_log_level = getCupdlpLogLevel(options); if (local_log_level) cupdlp_printf("Solving with cuPDLP-C\n"); - H_Init_Scaling(local_log_level, scaling, nCols, nRows, cost, rhs); - cupdlp_int ifScaling = 1; + H_Init_Scaling(local_log_level, options.pdlp_scaling_mode, scaling, nCols, + nRows, cost, rhs); + cupdlp_int ifScaling = intParam[IF_SCALING]; CUPDLPwork* w = cupdlp_NULL; cupdlp_init_work(w, 1); @@ -687,7 +688,25 @@ void getUserParamsFromOptions(const HighsOptions& options, intParam[N_LOG_LEVEL] = getCupdlpLogLevel(options); // ifChangeIntParam[IF_SCALING] = true; - intParam[IF_SCALING] = options.pdlp_scaling ? 1 : 0; + cupdlp_int scaling_on = + (options.pdlp_features_off & kPdlpScalingOff) == 0 ? 1 : 0; + intParam[IF_SCALING] = scaling_on; + if (scaling_on == 0) + highsLogUser(options.log_options, HighsLogType::kInfo, + "PDLP: Scaling off\n"); + // + ifChangeIntParam[E_LINE_SEARCH_METHOD] = true; + cupdlp_int adaptive_lineasearch = + (options.pdlp_features_off & kPdlpAdaptiveStepSizeOff) == 0 ? 1 : 0; + intParam[E_LINE_SEARCH_METHOD] = adaptive_lineasearch; + if (adaptive_lineasearch == 1) { + intParam[E_LINE_SEARCH_METHOD] = PDHG_ADAPTIVE_LINESEARCH; + } else { + intParam[E_LINE_SEARCH_METHOD] = PDHG_FIXED_LINESEARCH; + } + if (adaptive_lineasearch == 0) + highsLogUser(options.log_options, HighsLogType::kInfo, + "PDLP: Adaptive line search off\n"); // ifChangeFloatParam[D_PRIMAL_TOL] = true; floatParam[D_PRIMAL_TOL] = options.primal_feasibility_tolerance; @@ -702,7 +721,13 @@ void getUserParamsFromOptions(const HighsOptions& options, floatParam[D_TIME_LIM] = options.time_limit; // ifChangeIntParam[E_RESTART_METHOD] = true; - intParam[E_RESTART_METHOD] = int(options.pdlp_e_restart_method); + cupdlp_int restart_on = + (options.pdlp_features_off & kPdlpRestartOff) == 0 ? 1 : 0; + if (options.pdlp_e_restart_method == 0) restart_on = 0; + intParam[E_RESTART_METHOD] = restart_on; + if (restart_on == 0) + highsLogUser(options.log_options, HighsLogType::kInfo, + "PDLP: Restart off\n"); // // for the moment only native termination is allowed with GPU diff --git a/src/pdlp/cupdlp/cupdlp_scaling_cuda.c b/src/pdlp/cupdlp/cupdlp_scaling_cuda.c index cd1d66e4c2..3e030aa683 100644 --- a/src/pdlp/cupdlp/cupdlp_scaling_cuda.c +++ b/src/pdlp/cupdlp/cupdlp_scaling_cuda.c @@ -396,15 +396,27 @@ cupdlp_retcode H_PDHG_Scale_Data_cuda(cupdlp_int log_level, } cupdlp_retcode H_Init_Scaling(cupdlp_int log_level, + cupdlp_int scaling_mode, CUPDLPscaling *scaling, cupdlp_int ncols, cupdlp_int nrows, cupdlp_float *cost, cupdlp_float *rhs) { cupdlp_retcode retcode = RETCODE_OK; - scaling->ifRuizScaling = 1; - scaling->ifL2Scaling = 0; - scaling->ifPcScaling = 1; - + if (scaling_mode & 1) { + scaling->ifRuizScaling = 1; // Default + } else { + scaling->ifRuizScaling = 0; + } + if (scaling_mode & 2) { + scaling->ifL2Scaling = 1; + } else { + scaling->ifL2Scaling = 0; // Default + } + if (scaling_mode & 4) { + scaling->ifPcScaling = 1; // Default + } else { + scaling->ifPcScaling = 0; + } // todo, read these paras scaling->RuizTimes = 10; scaling->RuizNorm = INFINITY; diff --git a/src/pdlp/cupdlp/cupdlp_scaling_cuda.h b/src/pdlp/cupdlp/cupdlp_scaling_cuda.h index 920fce1976..5d33b30841 100644 --- a/src/pdlp/cupdlp/cupdlp_scaling_cuda.h +++ b/src/pdlp/cupdlp/cupdlp_scaling_cuda.h @@ -18,6 +18,7 @@ cupdlp_retcode H_PDHG_Scale_Data_cuda(cupdlp_int log_level, cupdlp_float *rhs); cupdlp_retcode H_Init_Scaling(cupdlp_int log_level, + cupdlp_int scaling_mode, CUPDLPscaling *scaling, cupdlp_int ncols, cupdlp_int nrows, cupdlp_float *cost, cupdlp_float *rhs); diff --git a/src/pdlp/cupdlp/cupdlp_solver.c b/src/pdlp/cupdlp/cupdlp_solver.c index 65db3183d6..68a51cfd96 100644 --- a/src/pdlp/cupdlp/cupdlp_solver.c +++ b/src/pdlp/cupdlp/cupdlp_solver.c @@ -11,6 +11,15 @@ #include "pdlp/cupdlp/cupdlp_utils.h" #include "pdlp/cupdlp/glbopts.h" +const cupdlp_int check_iter = -440; + +void debugPrintDouble(char* name, const cupdlp_int dim, const double* value) { + printf("%-50s = [", name); + for (cupdlp_int iCol = 0; iCol < dim; iCol++) + printf("%11.4g ", value[iCol]); + printf("]\n"); +} + void PDHG_Compute_Primal_Feasibility(CUPDLPwork *work, double *primalResidual, const double *ax, const double *x, double *dPrimalFeasibility, @@ -92,10 +101,18 @@ void PDHG_Compute_Dual_Feasibility(CUPDLPwork *work, double *dualResidual, // |max(-y, 0)| + |(I-\Pi)(c-Α'\nu)| // compute c - A'y + if (work->timers->nIter == check_iter) { + debugPrintDouble("PDHG_Compute_Dual_Feasibility 0: aty", problem->data->nCols, aty); + } + CUPDLP_COPY_VEC(dualResidual, aty, cupdlp_float, lp->nCols); cupdlp_float alpha = -1.0; cupdlp_scaleVector(work, alpha, dualResidual, lp->nCols); + if (work->timers->nIter == check_iter) { + debugPrintDouble("PDHG_Compute_Dual_Feasibility 0: dualResidual", problem->data->nCols, dualResidual); + } + alpha = 1.0; cupdlp_axpy(work, lp->nCols, &alpha, problem->cost, dualResidual); @@ -274,6 +291,10 @@ void PDHG_Compute_Dual_Infeasibility(CUPDLPwork *work, const cupdlp_float *x, cupdlp_float pBoundLbResSq = 0.0; cupdlp_float pBoundUbResSq = 0.0; + if (work->timers->nIter == check_iter) { + debugPrintDouble("dDualInfeasRes 0", problem->data->nCols, dDualInfeasRes); + } + // x ray CUPDLP_COPY_VEC(resobj->primalInfeasRay, x, cupdlp_float, problem->data->nCols); @@ -991,7 +1012,14 @@ cupdlp_retcode PDHG_Solve(CUPDLPwork *pdhg) { "Duality gap (abs/rel):", fabs(resobj->dDualityGap), resobj->dRelObjGap); } - cupdlp_printf("%27s %d\n", "Number of iterations:", timers->nIter); + cupdlp_printf("%27s %d\n", + "Number of iterations:", timers->nIter); + if (timers->nIter > 0) { + cupdlp_printf("%27s %d (%g/iter)\n", + "Number of Ax calls:", timers->nAxCalls, (1.0 * timers->nAxCalls)/ timers->nIter); + cupdlp_printf("%27s %d (%g/iter)\n", + "Number of A^Ty calls:", timers->nAtyCalls, (1.0 * timers->nAtyCalls)/ timers->nIter); + } cupdlp_printf("\n"); } diff --git a/src/pdlp/cupdlp/cupdlp_step.c b/src/pdlp/cupdlp/cupdlp_step.c index 4983e6ec29..2e4e6d4a09 100644 --- a/src/pdlp/cupdlp/cupdlp_step.c +++ b/src/pdlp/cupdlp/cupdlp_step.c @@ -337,6 +337,9 @@ cupdlp_retcode PDHG_Init_Step_Sizes(CUPDLPwork *pdhg) { iterates->dLastRestartBeta = stepsize->dBeta; } + // Whatever eLineSearchMethod, dual step is primal step times beta + assert((stepsize->dDualStep - stepsize->dPrimalStep * stepsize->dBeta)/stepsize->dDualStep < 1e-12); + iterates->iLastRestartIter = 0; stepsize->dSumPrimalStep = 0; stepsize->dSumDualStep = 0; diff --git a/src/presolve/HPresolve.cpp b/src/presolve/HPresolve.cpp index 6c72a06046..e74b0d4aaf 100644 --- a/src/presolve/HPresolve.cpp +++ b/src/presolve/HPresolve.cpp @@ -458,11 +458,6 @@ void HPresolve::unlink(HighsInt pos) { markChangedCol(Acol[pos]); impliedDualRowBounds.remove(Acol[pos], Arow[pos], Avalue[pos]); - if (colUpperSource[Acol[pos]] == Arow[pos]) - changeImplColUpper(Acol[pos], kHighsInf, -1); - - if (colLowerSource[Acol[pos]] == Arow[pos]) - changeImplColLower(Acol[pos], -kHighsInf, -1); } auto get_row_left = [&](HighsInt pos) -> HighsInt& { return ARleft[pos]; }; @@ -482,14 +477,16 @@ void HPresolve::unlink(HighsInt pos) { else markChangedRow(Arow[pos]); impliedRowBounds.remove(Arow[pos], Acol[pos], Avalue[pos]); + } - if (rowDualUpperSource[Arow[pos]] == Acol[pos]) - changeImplRowDualUpper(Arow[pos], kHighsInf, -1); + // remove implied bounds on row duals that where implied by this column's dual + // constraint + resetRowDualImpliedBoundsDerivedFromCol(Acol[pos]); - if (rowDualLowerSource[Arow[pos]] == Acol[pos]) - changeImplRowDualLower(Arow[pos], -kHighsInf, -1); - } + // remove implied bounds on columns that where implied by this row + resetColImpliedBoundsDerivedFromRow(Arow[pos]); + // remove non-zero Avalue[pos] = 0; freeslots.push_back(pos); @@ -666,43 +663,60 @@ void HPresolve::updateColImpliedBounds(HighsInt row, HighsInt col, double val) { HighsInt{-1}); } -void HPresolve::recomputeColImpliedBounds(HighsInt row) { - // recompute implied column bounds affected by a modification in a row +void HPresolve::resetColImpliedBounds(HighsInt col, HighsInt row) { + assert(row == -1 || colLowerSource[col] == row || colUpperSource[col] == row); + if (!colDeleted[col]) { + // set implied bounds to infinite values if (1) they were deduced from the + // given row or (2) no row was given + if (colLowerSource[col] != -1 && (row == -1 || colLowerSource[col] == row)) + changeImplColLower(col, -kHighsInf, -1); + if (colUpperSource[col] != -1 && (row == -1 || colUpperSource[col] == row)) + changeImplColUpper(col, kHighsInf, -1); + } else if (row != -1 && !rowDeleted[row]) { + // remove column from row-wise implied bound storage + colImplSourceByRow[row].erase(col); + } +} + +void HPresolve::resetRowDualImpliedBounds(HighsInt row, HighsInt col) { + assert(col == -1 || rowDualLowerSource[row] == col || + rowDualUpperSource[row] == col); + if (!rowDeleted[row]) { + // set implied bounds to infinite values if (1) they were deduced from the + // given column or (2) no column was given + if (rowDualLowerSource[row] != -1 && + (col == -1 || rowDualLowerSource[row] == col)) + changeImplRowDualLower(row, -kHighsInf, -1); + if (rowDualUpperSource[row] != -1 && + (col == -1 || rowDualUpperSource[row] == col)) + changeImplRowDualUpper(row, kHighsInf, -1); + } else if (col != -1 && !colDeleted[col]) { + // remove row from column-wise implied bound storage + implRowDualSourceByCol[col].erase(row); + } +} + +void HPresolve::resetColImpliedBoundsDerivedFromRow(HighsInt row) { + // reset implied column bounds affected by a modification in a row // (removed / added non-zeros, etc.) if (colImplSourceByRow[row].empty()) return; std::set affectedCols(colImplSourceByRow[row]); for (const HighsInt& col : affectedCols) { - // set implied bounds to infinite values if they were deduced from the given - // row - if (colLowerSource[col] == row) changeImplColLower(col, -kHighsInf, -1); - if (colUpperSource[col] == row) changeImplColUpper(col, kHighsInf, -1); - - // iterate over column and recompute the implied bounds - for (const HighsSliceNonzero& nonz : getColumnVector(col)) { - updateColImpliedBounds(nonz.index(), col, nonz.value()); - } + // set implied bounds to infinite values if they were deduced from the + // given row + resetColImpliedBounds(col, row); } } -void HPresolve::recomputeRowDualImpliedBounds(HighsInt col) { - // recompute implied row dual bounds affected by a modification in a column +void HPresolve::resetRowDualImpliedBoundsDerivedFromCol(HighsInt col) { + // reset implied row dual bounds affected by a modification in a column // (removed / added non-zeros, etc.) if (implRowDualSourceByCol[col].empty()) return; std::set affectedRows(implRowDualSourceByCol[col]); for (const HighsInt& row : affectedRows) { - // set implied bounds to infinite values if they were deduced from the given - // column - if (rowDualLowerSource[row] == col) - changeImplRowDualLower(row, -kHighsInf, -1); - if (rowDualUpperSource[row] == col) - changeImplRowDualUpper(row, kHighsInf, -1); - - // iterate over row and recompute the implied bounds - for (const HighsSliceNonzero& nonz : getRowVector(row)) { - // integer columns cannot be used to tighten bounds on dual multipliers - if (model->integrality_[nonz.index()] != HighsVarType::kInteger) - updateRowDualImpliedBounds(row, nonz.index(), nonz.value()); - } + // set implied bounds to infinite values if they were deduced from the + // given column + resetRowDualImpliedBounds(row, col); } } @@ -1652,23 +1666,25 @@ void HPresolve::addToMatrix(const HighsInt row, const HighsInt col, } link(pos); + + // remove implied bounds on row duals that where implied by this column's + // dual constraint + resetRowDualImpliedBoundsDerivedFromCol(col); + + // remove implied bounds on columns that where implied by this row + resetColImpliedBoundsDerivedFromRow(row); + } else { double sum = Avalue[pos] + val; if (std::abs(sum) <= options->small_matrix_value) { unlink(pos); } else { - // remove implied bounds on the row dual that where implied by this - // columns dual constraint - if (rowDualUpperSource[row] == col) - changeImplRowDualUpper(row, kHighsInf, -1); - - if (rowDualLowerSource[row] == col) - changeImplRowDualLower(row, -kHighsInf, -1); - - // remove implied bounds on the column that where implied by this row - if (colUpperSource[col] == row) changeImplColUpper(col, kHighsInf, -1); + // remove implied bounds on row duals that where implied by this column's + // dual constraint + resetRowDualImpliedBoundsDerivedFromCol(col); - if (colLowerSource[col] == row) changeImplColLower(col, -kHighsInf, -1); + // remove implied bounds on columns that where implied by this row + resetColImpliedBoundsDerivedFromRow(row); // remove the locks and contribution to implied (dual) row bounds, then // add then again @@ -1711,25 +1727,15 @@ void HPresolve::markRowDeleted(HighsInt row) { changedRowFlag[row] = true; rowDeleted[row] = true; ++numDeletedRows; - - // remove row from column-wise implied bound storage - if (rowDualLowerSource[row] != -1) - implRowDualSourceByCol[rowDualLowerSource[row]].erase(row); - if (rowDualUpperSource[row] != -1) - implRowDualSourceByCol[rowDualUpperSource[row]].erase(row); } void HPresolve::markColDeleted(HighsInt col) { assert(!colDeleted[col]); + // prevents col from being added to change vector changedColFlag[col] = true; colDeleted[col] = true; ++numDeletedCols; - // remove column from row-wise implied bound storage - if (colLowerSource[col] != -1) - colImplSourceByRow[colLowerSource[col]].erase(col); - if (colUpperSource[col] != -1) - colImplSourceByRow[colUpperSource[col]].erase(col); } void HPresolve::changeColUpper(HighsInt col, double newUpper) { @@ -1812,11 +1818,15 @@ void HPresolve::changeImplColUpper(HighsInt col, double newUpper, // remember the source of this upper bound, so that we can correctly identify // weak domination - if (oldUpperSource != -1 && oldUpperSource != colLowerSource[col]) - colImplSourceByRow[oldUpperSource].erase(col); - if (originRow != -1) colImplSourceByRow[originRow].emplace(col); + if (oldUpperSource != originRow) { + if (oldUpperSource != -1 && oldUpperSource != colLowerSource[col]) + colImplSourceByRow[oldUpperSource].erase(col); + if (originRow != -1) colImplSourceByRow[originRow].emplace(col); - colUpperSource[col] = originRow; + colUpperSource[col] = originRow; + } + + // update implied bound implColUpper[col] = newUpper; // if the old and the new implied bound are not better than the upper bound, @@ -1852,11 +1862,15 @@ void HPresolve::changeImplColLower(HighsInt col, double newLower, // remember the source of this lower bound, so that we can correctly identify // weak domination - if (oldLowerSource != -1 && oldLowerSource != colUpperSource[col]) - colImplSourceByRow[oldLowerSource].erase(col); - if (originRow != -1) colImplSourceByRow[originRow].emplace(col); + if (oldLowerSource != originRow) { + if (oldLowerSource != -1 && oldLowerSource != colUpperSource[col]) + colImplSourceByRow[oldLowerSource].erase(col); + if (originRow != -1) colImplSourceByRow[originRow].emplace(col); + + colLowerSource[col] = originRow; + } - colLowerSource[col] = originRow; + // update implied bound implColLower[col] = newLower; // if the old and the new implied bound are not better than the lower bound, @@ -1891,12 +1905,15 @@ void HPresolve::changeImplRowDualUpper(HighsInt row, double newUpper, // remember the source of this upper bound, so that we can correctly identify // weak domination - if (rowDualUpperSource[row] != -1 && - rowDualLowerSource[row] != rowDualUpperSource[row]) - implRowDualSourceByCol[rowDualUpperSource[row]].erase(row); - if (originCol != -1) implRowDualSourceByCol[originCol].emplace(row); + if (oldUpperSource != originCol) { + if (oldUpperSource != -1 && oldUpperSource != rowDualLowerSource[row]) + implRowDualSourceByCol[oldUpperSource].erase(row); + if (originCol != -1) implRowDualSourceByCol[originCol].emplace(row); - rowDualUpperSource[row] = originCol; + rowDualUpperSource[row] = originCol; + } + + // update implied bound implRowDualUpper[row] = newUpper; // nothing needs to be updated @@ -1929,12 +1946,15 @@ void HPresolve::changeImplRowDualLower(HighsInt row, double newLower, // remember the source of this lower bound, so that we can correctly identify // weak domination - if (rowDualLowerSource[row] != -1 && - rowDualLowerSource[row] != rowDualUpperSource[row]) - implRowDualSourceByCol[rowDualLowerSource[row]].erase(row); - if (originCol != -1) implRowDualSourceByCol[originCol].emplace(row); + if (oldLowerSource != originCol) { + if (oldLowerSource != -1 && oldLowerSource != rowDualUpperSource[row]) + implRowDualSourceByCol[oldLowerSource].erase(row); + if (originCol != -1) implRowDualSourceByCol[originCol].emplace(row); - rowDualLowerSource[row] = originCol; + rowDualLowerSource[row] = originCol; + } + + // update implied bound implRowDualLower[row] = newLower; // nothing needs to be updated @@ -2437,9 +2457,6 @@ void HPresolve::substitute(HighsInt row, HighsInt col, double rhs) { addToMatrix(colrow, Acol[rowiter], scale * Avalue[rowiter]); } - // recompute implied column bounds affected by the substitution - recomputeColImpliedBounds(colrow); - // check if this is an equation row and it now has a different size reinsertEquation(colrow); // printf("after substitution: "); @@ -2469,12 +2486,6 @@ void HPresolve::substitute(HighsInt row, HighsInt col, double rhs) { model->col_cost_[col] = 0.0; } - // recompute implied row dual bounds affected by substitution - for (HighsInt rowiter : rowpositions) { - if (Acol[rowiter] == col) continue; - recomputeRowDualImpliedBounds(Acol[rowiter]); - } - // finally remove the entries of the row that was used for substitution for (HighsInt rowiter : rowpositions) unlink(rowiter); } @@ -2973,15 +2984,13 @@ HPresolve::Result HPresolve::rowPresolve(HighsPostsolveStack& postsolve_stack, assert(model->col_cost_[col] != 0.0); if (colsize[col] != 1) return; if (model->col_cost_[col] > 0) { - assert(model->col_lower_[col] == -kHighsInf || - (model->col_lower_[col] <= implColLower[col] + primal_feastol && - colLowerSource[col] == row)); + assert(model->col_lower_[col] == -kHighsInf || !isLowerImplied(col) || + colLowerSource[col] == row); if (model->col_lower_[col] > implColLower[col] - primal_feastol) changeColLower(col, -kHighsInf); } else { - assert(model->col_upper_[col] == kHighsInf || - (model->col_upper_[col] >= implColUpper[col] - primal_feastol && - colUpperSource[col] == row)); + assert(model->col_upper_[col] == kHighsInf || !isUpperImplied(col) || + colUpperSource[col] == row); if (model->col_upper_[col] < implColUpper[col] + primal_feastol) changeColUpper(col, kHighsInf); } @@ -4098,6 +4107,7 @@ HPresolve::Result HPresolve::presolve(HighsPostsolveStack& postsolve_stack) { #else std::string time_str = " " + std::to_string(int(run_time)) + "s"; #endif + if (options->timeless_log) time_str = ""; highsLogUser(options->log_options, HighsLogType::kInfo, "%" HIGHSINT_FORMAT " rows, %" HIGHSINT_FORMAT " cols, %" HIGHSINT_FORMAT " nonzeros %s\n", @@ -5876,10 +5886,7 @@ HPresolve::Result HPresolve::detectParallelRowsAndCols( // remove implied bounds, since they might in general not be valid // anymore - if (colLowerSource[col] != -1) - changeImplColLower(col, -kHighsInf, -1); - - if (colUpperSource[col] != -1) changeImplColUpper(col, kHighsInf, -1); + resetColImpliedBounds(col); // if an implicit integer and an integer column were merged, check if // merged continuous column is implicit integer after merge @@ -6059,10 +6066,9 @@ HPresolve::Result HPresolve::detectParallelRowsAndCols( model->row_lower_[parallelRowCand] = newLower; } } - if (rowDualLowerSource[parallelRowCand] != -1) - changeImplRowDualLower(parallelRowCand, -kHighsInf, -1); - if (rowDualUpperSource[parallelRowCand] != -1) - changeImplRowDualUpper(parallelRowCand, kHighsInf, -1); + // remove implied bounds, since they might in general not be valid + // anymore + resetRowDualImpliedBounds(parallelRowCand); postsolve_stack.duplicateRow(parallelRowCand, rowUpperTightened, rowLowerTightened, i, rowScale); diff --git a/src/presolve/HPresolve.h b/src/presolve/HPresolve.h index 9781e2567b..13bf2f726f 100644 --- a/src/presolve/HPresolve.h +++ b/src/presolve/HPresolve.h @@ -154,11 +154,15 @@ class HPresolve { void updateColImpliedBounds(HighsInt row, HighsInt col, double val); - void recomputeColImpliedBounds(HighsInt row); + void updateRowDualImpliedBounds(HighsInt row, HighsInt col, double val); - void recomputeRowDualImpliedBounds(HighsInt col); + void resetColImpliedBounds(HighsInt col, HighsInt row = -1); - void updateRowDualImpliedBounds(HighsInt row, HighsInt col, double val); + void resetRowDualImpliedBounds(HighsInt row, HighsInt col = -1); + + void resetColImpliedBoundsDerivedFromRow(HighsInt row); + + void resetRowDualImpliedBoundsDerivedFromCol(HighsInt col); bool rowCoefficientsIntegral(HighsInt row, double scale) const; diff --git a/src/simplex/HEkk.cpp b/src/simplex/HEkk.cpp index ff70340069..95121d9536 100644 --- a/src/simplex/HEkk.cpp +++ b/src/simplex/HEkk.cpp @@ -1105,13 +1105,13 @@ HighsStatus HEkk::solve(const bool force_phase2) { if (simplex_strategy == kSimplexStrategyDualTasks) { highsLogUser(options_->log_options, HighsLogType::kInfo, "Using EKK parallel dual simplex solver - SIP with " - "concurrency of %" HIGHSINT_FORMAT "\n", - info_.num_concurrency); + "concurrency of %d\n", + int(info_.num_concurrency)); } else if (simplex_strategy == kSimplexStrategyDualMulti) { highsLogUser(options_->log_options, HighsLogType::kInfo, "Using EKK parallel dual simplex solver - PAMI with " - "concurrency of %" HIGHSINT_FORMAT "\n", - info_.num_concurrency); + "concurrency of %d\n", + int(info_.num_concurrency)); } else { highsLogUser(options_->log_options, HighsLogType::kInfo, "Using EKK dual simplex solver - serial\n"); diff --git a/src/simplex/HEkkPrimal.cpp b/src/simplex/HEkkPrimal.cpp index e077da8040..6c12ef3c77 100644 --- a/src/simplex/HEkkPrimal.cpp +++ b/src/simplex/HEkkPrimal.cpp @@ -1931,13 +1931,13 @@ void HEkkPrimal::considerInfeasibleValueIn() { // Perturb the upper bound to accommodate the infeasibility shiftBound(false, variable_in, value_in, info.numTotRandomValue_[variable_in], - info.workUpper_[variable_in], bound_shift, true); + info.workUpper_[variable_in], bound_shift); info.workUpperShift_[variable_in] += bound_shift; } else { // Perturb the lower bound to accommodate the infeasibility shiftBound(true, variable_in, value_in, info.numTotRandomValue_[variable_in], - info.workLower_[variable_in], bound_shift, true); + info.workLower_[variable_in], bound_shift); info.workLowerShift_[variable_in] += bound_shift; } info.bounds_perturbed = true; @@ -2010,14 +2010,14 @@ void HEkkPrimal::phase2UpdatePrimal(const bool initialise) { // Perturb the upper bound to accommodate the infeasibility shiftBound(false, iCol, info.baseValue_[iRow], info.numTotRandomValue_[iCol], info.workUpper_[iCol], - bound_shift, true); + bound_shift); info.baseUpper_[iRow] = info.workUpper_[iCol]; info.workUpperShift_[iCol] += bound_shift; } else { // Perturb the lower bound to accommodate the infeasibility shiftBound(true, iCol, info.baseValue_[iRow], info.numTotRandomValue_[iCol], info.workLower_[iCol], - bound_shift, true); + bound_shift); info.baseLower_[iRow] = info.workLower_[iCol]; info.workLowerShift_[iCol] += bound_shift; } @@ -2076,14 +2076,14 @@ bool HEkkPrimal::correctPrimal(const bool initialise) { // Perturb the upper bound to accommodate the infeasibility shiftBound(false, iCol, info.baseValue_[iRow], info.numTotRandomValue_[iCol], info.workUpper_[iCol], - bound_shift, true); + bound_shift); info.baseUpper_[iRow] = info.workUpper_[iCol]; info.workUpperShift_[iCol] += bound_shift; } else { // Perturb the lower bound to accommodate the infeasibility shiftBound(true, iCol, info.baseValue_[iRow], info.numTotRandomValue_[iCol], info.workLower_[iCol], - bound_shift, true); + bound_shift); info.baseLower_[iRow] = info.workLower_[iCol]; info.workLowerShift_[iCol] += bound_shift; } @@ -2792,7 +2792,16 @@ void HEkkPrimal::getBasicPrimalInfeasibility() { void HEkkPrimal::shiftBound(const bool lower, const HighsInt iVar, const double value, const double random_value, - double& bound, double& shift, const bool report) { + double& bound, double& shift) { + // If infeasibility is very large, then adding feasibility may not + // yield a new value (see #1144) so new_infeasibility < 0 is false, + // tripping the old assert + // + // Ambros proposed adding feasibility + // *(infeasibility/scale_threshold) when + // infeasibility/scale_threshold > 1, but this could lead to a large + // value for new_infeasibility. Sounds better to accept degeneracy + // in this edge case. double feasibility = (1 + random_value) * primal_feasibility_tolerance; double old_bound = bound; std::string type; @@ -2805,20 +2814,10 @@ void HEkkPrimal::shiftBound(const bool lower, const HighsInt iVar, infeasibility = bound - value; assert(infeasibility > 0); // Determine the amount by which value will be feasible - so that - // it's not degenerate + // (ideally) it's not degenerate shift = infeasibility + feasibility; bound -= shift; new_infeasibility = bound - value; - if (new_infeasibility >= 0) { - printf( - "HEkkPrimal::shiftBound LB = %g; random_value = %g; value = %g; " - "feasibility = %g; infeasibility = %g; shift = %g; bound = %g; " - "new_infeasibility = %g; \n", - old_bound, random_value, value, feasibility, infeasibility, shift, - bound, new_infeasibility); - fflush(stdout); - } - assert(new_infeasibility < 0); } else { // Bound to shift is upper type = "upper"; @@ -2826,20 +2825,26 @@ void HEkkPrimal::shiftBound(const bool lower, const HighsInt iVar, infeasibility = value - bound; assert(infeasibility > 0); // Determine the amount by which value will be feasible - so that - // it's not degenerate + // (ideally) it's not degenerate shift = infeasibility + feasibility; bound += shift; new_infeasibility = value - bound; - assert(new_infeasibility < 0); - } - double error = fabs(-new_infeasibility - feasibility); - if (report) - highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kVerbose, - "Value(%4" HIGHSINT_FORMAT - ") = %10.4g exceeds %s = %10.4g by %9.4g, so shift bound by " - "%9.4g to %10.4g: infeasibility %10.4g with error %g\n", - iVar, value, type.c_str(), old_bound, infeasibility, shift, - bound, new_infeasibility, error); + } + if (new_infeasibility > 0) { + // new_infeasibility should be non-positive, and negative unless + // bound is excessively large, whereas feasibility is positive + double error = std::fabs(new_infeasibility + feasibility); + highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo, + "HEkkPrimal::shiftBound Value(%4d) = %10.4g exceeds %s: " + "random_value = %g; value = %g; " + "feasibility = %g; infeasibility = %g; shift = %g; bound = %g; " + "new_infeasibility = %g with error %g\n", + int(iVar), value, type.c_str(), old_bound, random_value, value, + feasibility, infeasibility, shift, bound, new_infeasibility, + error); + fflush(stdout); + } + assert(new_infeasibility <= 0); } void HEkkPrimal::savePrimalRay() { diff --git a/src/simplex/HEkkPrimal.h b/src/simplex/HEkkPrimal.h index cf43716ccc..242e1643c2 100644 --- a/src/simplex/HEkkPrimal.h +++ b/src/simplex/HEkkPrimal.h @@ -101,8 +101,7 @@ class HEkkPrimal { void getBasicPrimalInfeasibility(); bool correctPrimal(const bool initialise = false); void shiftBound(const bool lower, const HighsInt iVar, const double value, - const double random_value, double& bound, double& shift, - const bool report = false); + const double random_value, double& bound, double& shift); void savePrimalRay(); HighsDebugStatus debugPrimalSimplex(const std::string message, const bool initialise = false); diff --git a/src/simplex/HighsSimplexAnalysis.cpp b/src/simplex/HighsSimplexAnalysis.cpp index 9b4a474ac0..e876194396 100644 --- a/src/simplex/HighsSimplexAnalysis.cpp +++ b/src/simplex/HighsSimplexAnalysis.cpp @@ -36,6 +36,7 @@ void HighsSimplexAnalysis::setup(const std::string lp_name, const HighsLp& lp, kHighsAnalysisLevelNlaData & options.highs_analysis_level; analyse_simplex_data = analyse_simplex_summary_data || analyse_simplex_runtime_data; + highs_run_time = 0; last_user_log_time = -kHighsInf; delta_user_log_time = 5e0; @@ -54,6 +55,7 @@ void HighsSimplexAnalysis::setup(const std::string lp_name, const HighsLp& lp, // AnIterNumCostlyDseIt = 0; // Copy messaging parameter from options messaging(options.log_options); + timeless_log = options.timeless_log; // Initialise the densities col_aq_density = 0; row_ep_density = 0; @@ -380,13 +382,13 @@ void HighsSimplexAnalysis::userInvertReport(const bool force) { void HighsSimplexAnalysis::userInvertReport(const bool header, const bool force) { - const double highs_run_time = timer_->read(); + highs_run_time = timeless_log ? highs_run_time + 1 : timer_->read(); if (!force && highs_run_time < last_user_log_time + delta_user_log_time) return; analysis_log = std::unique_ptr(new std::stringstream()); reportIterationObjective(header); reportInfeasibility(header); - reportRunTime(header, highs_run_time); + if (!timeless_log) reportRunTime(header, highs_run_time); highsLogUser(log_options, HighsLogType::kInfo, "%s\n", analysis_log->str().c_str()); if (!header) last_user_log_time = highs_run_time; diff --git a/src/simplex/HighsSimplexAnalysis.h b/src/simplex/HighsSimplexAnalysis.h index 34802614f3..94a0292a67 100644 --- a/src/simplex/HighsSimplexAnalysis.h +++ b/src/simplex/HighsSimplexAnalysis.h @@ -152,8 +152,10 @@ class HighsSimplexAnalysis { 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), + highs_run_time(0.0), last_user_log_time(-kHighsInf), delta_user_log_time(1e0), + timeless_log(false), average_concurrency(0.0), average_fraction_of_possible_minor_iterations_performed(0.0), sum_multi_chosen(0), @@ -428,8 +430,10 @@ class HighsSimplexAnalysis { HighsInt num_invert_report_since_last_header; HighsInt num_iteration_report_since_last_header; + double highs_run_time; double last_user_log_time; double delta_user_log_time; + bool timeless_log; double average_concurrency; double average_fraction_of_possible_minor_iterations_performed; diff --git a/src/util/HighsUtils.cpp b/src/util/HighsUtils.cpp index 7e0ab9051c..9dc4fa6a20 100644 --- a/src/util/HighsUtils.cpp +++ b/src/util/HighsUtils.cpp @@ -435,7 +435,7 @@ void analyseVectorValues(const HighsLogOptions* log_options, highsFormatToString("%12" HIGHSINT_FORMAT " values satisfy 10^(%3" HIGHSINT_FORMAT ") <= v < 10^(%3" HIGHSINT_FORMAT ")\n", - vK, k, k + 1)); + vK, k - 1, k)); } for (HighsInt k = 1; k <= nVK; k++) { HighsInt vK = negVK[k]; @@ -445,7 +445,7 @@ void analyseVectorValues(const HighsLogOptions* log_options, highsFormatToString("%12" HIGHSINT_FORMAT " values satisfy 10^(%3" HIGHSINT_FORMAT ") <= v < 10^(%3" HIGHSINT_FORMAT ")\n", - vK, -k, 1 - k)); + vK, -k - 1, -k)); } vK = vecDim - nNz; if (vK > 0) diff --git a/src/util/stringutil.cpp b/src/util/stringutil.cpp index 9d6e312d90..49bceaa0f1 100644 --- a/src/util/stringutil.cpp +++ b/src/util/stringutil.cpp @@ -72,6 +72,11 @@ void tolower(std::string& str) { [](unsigned char c) { return std::tolower(c); }); } +void toupper(std::string& str) { + std::transform(str.begin(), str.end(), str.begin(), + [](unsigned char c) { return std::toupper(c); }); +} + std::string& ltrim(std::string& str, const std::string& chars) { str.erase(0, str.find_first_not_of(chars)); return str; diff --git a/src/util/stringutil.h b/src/util/stringutil.h index 32132730ef..0e0b277738 100644 --- a/src/util/stringutil.h +++ b/src/util/stringutil.h @@ -23,6 +23,7 @@ void strTrim(char* str); // std::string& str_tolower(std::string s); void tolower(std::string& str); +void toupper(std::string& str); const std::string default_non_chars = "\t\n\v\f\r "; std::string& ltrim(std::string& str,