lpsolver 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/README.md +104 -26
- data/ext/lpsolver/Makefile +269 -0
- data/ext/lpsolver/ext.c +353 -0
- data/ext/lpsolver/ext.o +0 -0
- data/ext/lpsolver/extconf.rb +79 -0
- data/ext/lpsolver/native.so +0 -0
- data/ext/lpsolver-highs/AUTHORS +7 -0
- data/ext/lpsolver-highs/BUILD.bazel +243 -0
- data/ext/lpsolver-highs/CITATION.cff +29 -0
- data/ext/lpsolver-highs/CMakeCache.txt +406 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeCCompiler.cmake +81 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeCXXCompiler.cmake +101 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeDetermineCompilerABI_C.bin +0 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeDetermineCompilerABI_CXX.bin +0 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeSystem.cmake +15 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CompilerIdC/CMakeCCompilerId.c +904 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CompilerIdC/a.out +0 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CompilerIdCXX/CMakeCXXCompilerId.cpp +919 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CompilerIdCXX/a.out +0 -0
- data/ext/lpsolver-highs/CMakeFiles/CMakeConfigureLog.yaml +576 -0
- data/ext/lpsolver-highs/CMakeFiles/cmake.check_cache +1 -0
- data/ext/lpsolver-highs/CMakeLists.txt +983 -0
- data/ext/lpsolver-highs/CODE_OF_CONDUCT.md +128 -0
- data/ext/lpsolver-highs/CONTRIBUTING.md +31 -0
- data/ext/lpsolver-highs/FEATURES.md +61 -0
- data/ext/lpsolver-highs/LICENSE.txt +21 -0
- data/ext/lpsolver-highs/MODULE.bazel +38 -0
- data/ext/lpsolver-highs/README.md +281 -0
- data/ext/lpsolver-highs/THIRD_PARTY_NOTICES.md +78 -0
- data/ext/lpsolver-highs/Version.txt +4 -0
- data/ext/lpsolver-highs/WORKSPACE +33 -0
- data/ext/lpsolver-highs/app/CMakeLists.txt +110 -0
- data/ext/lpsolver-highs/app/HighsRuntimeOptions.h +292 -0
- data/ext/lpsolver-highs/app/RunHighs.cpp +147 -0
- data/ext/lpsolver-highs/app/highs_webdemo_shell.html +73 -0
- data/ext/lpsolver-highs/build/bin/highs +0 -0
- data/ext/lpsolver-highs/build/include/highs/HConfig.h +22 -0
- data/ext/lpsolver-highs/build/include/highs/Highs.h +1812 -0
- data/ext/lpsolver-highs/build/include/highs/interfaces/highs_c_api.h +2651 -0
- data/ext/lpsolver-highs/build/include/highs/io/Filereader.h +45 -0
- data/ext/lpsolver-highs/build/include/highs/io/FilereaderLp.h +49 -0
- data/ext/lpsolver-highs/build/include/highs/io/FilereaderMps.h +27 -0
- data/ext/lpsolver-highs/build/include/highs/io/HMPSIO.h +78 -0
- data/ext/lpsolver-highs/build/include/highs/io/HMpsFF.h +245 -0
- data/ext/lpsolver-highs/build/include/highs/io/HighsIO.h +118 -0
- data/ext/lpsolver-highs/build/include/highs/io/LoadOptions.h +24 -0
- data/ext/lpsolver-highs/build/include/highs/io/filereaderlp/builder.hpp +25 -0
- data/ext/lpsolver-highs/build/include/highs/io/filereaderlp/def.hpp +19 -0
- data/ext/lpsolver-highs/build/include/highs/io/filereaderlp/model.hpp +68 -0
- data/ext/lpsolver-highs/build/include/highs/io/filereaderlp/reader.hpp +10 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/IpxSolution.h +32 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/IpxWrapper.h +106 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu.h +161 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_factorize.h +247 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_get_factors.h +108 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_initialize.h +119 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_factorize.h +34 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_free.h +19 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_get_factors.h +34 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_initialize.h +46 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_solve_dense.h +29 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_solve_for_update.h +42 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_solve_sparse.h +32 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_update.h +31 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_object.h +30 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_solve_dense.h +75 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_solve_for_update.h +169 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_solve_sparse.h +112 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_update.h +125 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/lu_def.h +39 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/lu_file.h +21 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/lu_internal.h +220 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/lu_list.h +173 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/basiclu_kernel.h +20 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/basiclu_wrapper.h +47 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/basis.h +350 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/conjugate_residuals.h +74 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/control.h +167 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/crossover.h +157 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/diagonal_precond.h +45 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/forrest_tomlin.h +102 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/guess_basis.h +21 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/indexed_vector.h +113 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/info.h +27 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipm.h +94 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_c.h +47 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_config.h +9 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_info.h +111 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_internal.h +89 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_parameters.h +76 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_status.h +57 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/iterate.h +331 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/kkt_solver.h +70 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/kkt_solver_basis.h +66 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/kkt_solver_diag.h +48 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/linear_operator.h +26 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/lp_solver.h +204 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/lu_factorization.h +79 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/lu_update.h +129 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/maxvolume.h +54 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/model.h +413 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/multistream.h +52 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/normal_matrix.h +44 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/power_method.h +44 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/sparse_matrix.h +195 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/sparse_utils.h +58 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/splitted_normal_matrix.h +63 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/starting_basis.h +39 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/symbolic_invert.h +29 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/timer.h +25 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/utils.h +37 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HConst.h +430 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HStruct.h +213 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsAnalysis.h +23 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsCallback.h +104 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsCallbackStruct.h +70 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsDebug.h +34 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsIis.h +139 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsInfo.h +421 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsInfoDebug.h +27 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsLp.h +97 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsLpSolverObject.h +47 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsLpUtils.h +330 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsModelUtils.h +129 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsOptions.h +1715 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsRanging.h +43 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsSolution.h +179 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsSolutionDebug.h +87 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsSolve.h +29 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsStatus.h +29 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsCliqueTable.h +329 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsConflictPool.h +109 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsCutGeneration.h +108 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsCutPool.h +168 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsDebugSol.h +133 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsDomain.h +657 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsDomainChange.h +48 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsDynamicRowMatrix.h +104 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsGFkSolve.h +439 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsImplications.h +194 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsLpAggregator.h +50 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsLpRelaxation.h +361 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsMipAnalysis.h +71 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsMipSolver.h +159 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsMipSolverData.h +313 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsModkSeparator.h +60 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsNodeQueue.h +312 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsObjectiveFunction.h +71 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsPathSeparator.h +39 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsPrimalHeuristics.h +75 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsPseudocost.h +366 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsRedcostFixing.h +42 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsSearch.h +241 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsSeparation.h +41 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsSeparator.h +60 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsTableauSeparator.h +34 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsTransformedLp.h +63 -0
- data/ext/lpsolver-highs/build/include/highs/mip/MipTimer.h +544 -0
- data/ext/lpsolver-highs/build/include/highs/mip/feasibilityjump.hh +800 -0
- data/ext/lpsolver-highs/build/include/highs/model/HighsHessian.h +54 -0
- data/ext/lpsolver-highs/build/include/highs/model/HighsHessianUtils.h +47 -0
- data/ext/lpsolver-highs/build/include/highs/model/HighsModel.h +42 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsBinarySemaphore.h +108 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsCacheAlign.h +82 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsCombinable.h +116 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsMutex.h +124 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsParallel.h +128 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsRaceTimer.h +38 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsSchedulerConstants.h +19 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsSpinMutex.h +48 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsSplitDeque.h +606 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsTask.h +170 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsTaskExecutor.h +217 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/CupdlpWrapper.h +108 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/HiPdlpTimer.h +155 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/HiPdlpWrapper.h +26 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_cs.h +40 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_defs.h +447 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_linalg.h +189 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_proj.h +19 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_restart.h +31 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_scaling.h +26 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_solver.h +105 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_step.h +37 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_utils.c +1850 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/defs.hpp +222 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/linalg.hpp +61 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/logger.hpp +80 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/pdhg.hpp +358 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/restart.hpp +96 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/scaling.hpp +74 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/solver_results.hpp +65 -0
- data/ext/lpsolver-highs/build/include/highs/pdqsort/pdqsort.h +532 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/HPresolve.h +505 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/HPresolveAnalysis.h +52 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/HighsPostsolveStack.h +943 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/HighsSymmetry.h +284 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/ICrash.h +124 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/ICrashUtil.h +62 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/ICrashX.h +23 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/PresolveComponent.h +90 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/a_asm.hpp +77 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/a_quass.hpp +22 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/basis.hpp +159 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/crashsolution.hpp +20 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/dantzigpricing.hpp +80 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/devexpricing.hpp +108 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/eventhandler.hpp +30 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/factor.hpp +408 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/feasibility_bounded.hpp +114 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/feasibility_highs.hpp +301 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/gradient.hpp +46 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/instance.hpp +70 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/matrix.hpp +342 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/perturbation.hpp +15 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/pricing.hpp +22 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/qpconst.hpp +34 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/qpvector.hpp +242 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/quass.hpp +27 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/ratiotest.hpp +26 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/runtime.hpp +45 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/scaling.hpp +15 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/settings.hpp +84 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/snippets.hpp +36 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/statistics.hpp +30 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/steepestedgepricing.hpp +173 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HApp.h +550 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkk.h +419 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkkDual.h +513 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkkDualRHS.h +134 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkkDualRow.h +201 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkkPrimal.h +191 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HSimplex.h +42 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HSimplexDebug.h +48 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HSimplexNla.h +158 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HSimplexReport.h +21 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HighsSimplexAnalysis.h +500 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/SimplexConst.h +273 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/SimplexStruct.h +263 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/SimplexTimer.h +414 -0
- data/ext/lpsolver-highs/build/include/highs/test_kkt/DevKkt.h +143 -0
- data/ext/lpsolver-highs/build/include/highs/test_kkt/KktCh2.h +79 -0
- data/ext/lpsolver-highs/build/include/highs/util/FactorTimer.h +199 -0
- data/ext/lpsolver-highs/build/include/highs/util/HFactor.h +587 -0
- data/ext/lpsolver-highs/build/include/highs/util/HFactorConst.h +81 -0
- data/ext/lpsolver-highs/build/include/highs/util/HFactorDebug.h +55 -0
- data/ext/lpsolver-highs/build/include/highs/util/HSet.h +89 -0
- data/ext/lpsolver-highs/build/include/highs/util/HVector.h +22 -0
- data/ext/lpsolver-highs/build/include/highs/util/HVectorBase.h +102 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsCDouble.h +323 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsComponent.h +53 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsDataStack.h +83 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsDisjointSets.h +107 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsHash.h +1274 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsHashTree.h +1461 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsInt.h +36 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsIntegers.h +212 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsLinearSumBounds.h +203 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsMatrixPic.h +37 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsMatrixSlice.h +561 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsMatrixUtils.h +57 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsMemoryAllocation.h +63 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsRandom.h +242 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsRbTree.h +452 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsSort.h +131 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsSparseMatrix.h +151 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsSparseVectorSum.h +95 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsSplay.h +135 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsTimer.h +385 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsUtils.h +272 -0
- data/ext/lpsolver-highs/build/include/highs/util/stringutil.h +46 -0
- data/ext/lpsolver-highs/build/include/highs/zstr/strict_fstream.hpp +237 -0
- data/ext/lpsolver-highs/build/include/highs/zstr/zstr.hpp +473 -0
- data/ext/lpsolver-highs/build/include/highs_export.h +43 -0
- data/ext/lpsolver-highs/build/lib/cmake/highs/highs-config-version.cmake +65 -0
- data/ext/lpsolver-highs/build/lib/cmake/highs/highs-config.cmake +36 -0
- data/ext/lpsolver-highs/build/lib/cmake/highs/highs-targets-release.cmake +19 -0
- data/ext/lpsolver-highs/build/lib/cmake/highs/highs-targets.cmake +111 -0
- data/ext/lpsolver-highs/build/lib/libhighs.a +0 -0
- data/ext/lpsolver-highs/build/lib/pkgconfig/highs.pc +12 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/AUTHORS +7 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/CITATION.cff +29 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/CODE_OF_CONDUCT.md +128 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/CONTRIBUTING.md +31 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/FEATURES.md +61 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/LICENSE.txt +21 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/README.md +281 -0
- data/ext/lpsolver-highs/build_webdemo.sh +46 -0
- data/ext/lpsolver-highs/check/Avgas.cpp +245 -0
- data/ext/lpsolver-highs/check/Avgas.h +44 -0
- data/ext/lpsolver-highs/check/CMakeLists.txt +573 -0
- data/ext/lpsolver-highs/check/HCheckConfig.h.bazel.in +6 -0
- data/ext/lpsolver-highs/check/HCheckConfig.h.in +12 -0
- data/ext/lpsolver-highs/check/HCheckConfig.h.meson.in +6 -0
- data/ext/lpsolver-highs/check/SpecialLps.h +405 -0
- data/ext/lpsolver-highs/check/TestAlienBasis.cpp +720 -0
- data/ext/lpsolver-highs/check/TestBasis.cpp +359 -0
- data/ext/lpsolver-highs/check/TestBasisSolves.cpp +669 -0
- data/ext/lpsolver-highs/check/TestCAPI.c +2513 -0
- data/ext/lpsolver-highs/check/TestCallbacks.cpp +608 -0
- data/ext/lpsolver-highs/check/TestCheckSolution.cpp +740 -0
- data/ext/lpsolver-highs/check/TestCrossover.cpp +111 -0
- data/ext/lpsolver-highs/check/TestDualize.cpp +172 -0
- data/ext/lpsolver-highs/check/TestEkk.cpp +100 -0
- data/ext/lpsolver-highs/check/TestFactor.cpp +389 -0
- data/ext/lpsolver-highs/check/TestFilereader.cpp +568 -0
- data/ext/lpsolver-highs/check/TestFortranAPI.f90 +65 -0
- data/ext/lpsolver-highs/check/TestHSet.cpp +80 -0
- data/ext/lpsolver-highs/check/TestHighsCDouble.cpp +109 -0
- data/ext/lpsolver-highs/check/TestHighsGFkSolve.cpp +102 -0
- data/ext/lpsolver-highs/check/TestHighsHash.cpp +126 -0
- data/ext/lpsolver-highs/check/TestHighsHessian.cpp +329 -0
- data/ext/lpsolver-highs/check/TestHighsIntegers.cpp +42 -0
- data/ext/lpsolver-highs/check/TestHighsModel.cpp +134 -0
- data/ext/lpsolver-highs/check/TestHighsParallel.cpp +277 -0
- data/ext/lpsolver-highs/check/TestHighsRbTree.cpp +109 -0
- data/ext/lpsolver-highs/check/TestHighsSparseMatrix.cpp +126 -0
- data/ext/lpsolver-highs/check/TestHighsVersion.cpp +61 -0
- data/ext/lpsolver-highs/check/TestHipo.cpp +122 -0
- data/ext/lpsolver-highs/check/TestICrash.cpp +46 -0
- data/ext/lpsolver-highs/check/TestIO.cpp +163 -0
- data/ext/lpsolver-highs/check/TestIis.cpp +1063 -0
- data/ext/lpsolver-highs/check/TestInfo.cpp +116 -0
- data/ext/lpsolver-highs/check/TestIpm.cpp +226 -0
- data/ext/lpsolver-highs/check/TestIpx.cpp +96 -0
- data/ext/lpsolver-highs/check/TestLPFileFormat.cpp +22 -0
- data/ext/lpsolver-highs/check/TestLogging.cpp +69 -0
- data/ext/lpsolver-highs/check/TestLpModification.cpp +2497 -0
- data/ext/lpsolver-highs/check/TestLpOrientation.cpp +121 -0
- data/ext/lpsolver-highs/check/TestLpSolvers.cpp +555 -0
- data/ext/lpsolver-highs/check/TestLpValidation.cpp +689 -0
- data/ext/lpsolver-highs/check/TestMain.cpp +6 -0
- data/ext/lpsolver-highs/check/TestMipSolver.cpp +1406 -0
- data/ext/lpsolver-highs/check/TestModelProperties.cpp +143 -0
- data/ext/lpsolver-highs/check/TestMultiObjective.cpp +198 -0
- data/ext/lpsolver-highs/check/TestNames.cpp +187 -0
- data/ext/lpsolver-highs/check/TestOptions.cpp +544 -0
- data/ext/lpsolver-highs/check/TestPdlp.cpp +327 -0
- data/ext/lpsolver-highs/check/TestPdlpHi.cpp +40 -0
- data/ext/lpsolver-highs/check/TestPresolve.cpp +912 -0
- data/ext/lpsolver-highs/check/TestQpSolver.cpp +1345 -0
- data/ext/lpsolver-highs/check/TestRanging.cpp +558 -0
- data/ext/lpsolver-highs/check/TestRays.cpp +1010 -0
- data/ext/lpsolver-highs/check/TestSemiVariables.cpp +329 -0
- data/ext/lpsolver-highs/check/TestSetup.cpp +12 -0
- data/ext/lpsolver-highs/check/TestSort.cpp +247 -0
- data/ext/lpsolver-highs/check/TestSpecialLps.cpp +775 -0
- data/ext/lpsolver-highs/check/TestThrow.cpp +83 -0
- data/ext/lpsolver-highs/check/TestTspSolver.cpp +19 -0
- data/ext/lpsolver-highs/check/TestUserScale.cpp +444 -0
- data/ext/lpsolver-highs/check/cublas_example.cpp +76 -0
- data/ext/lpsolver-highs/check/cublas_gpu_start.cpp +88 -0
- data/ext/lpsolver-highs/check/hipo_test_option_files/hipo_options_0 +1 -0
- data/ext/lpsolver-highs/check/instances/1448.lp +1 -0
- data/ext/lpsolver-highs/check/instances/1449a.lp +1 -0
- data/ext/lpsolver-highs/check/instances/1449b.lp +1 -0
- data/ext/lpsolver-highs/check/instances/1451.lp +8 -0
- data/ext/lpsolver-highs/check/instances/2122.lp +1822 -0
- data/ext/lpsolver-highs/check/instances/2171.mps +717 -0
- data/ext/lpsolver-highs/check/instances/25fv47.mps +6919 -0
- data/ext/lpsolver-highs/check/instances/2821-duplicate.mps +31 -0
- data/ext/lpsolver-highs/check/instances/2821-qmatrix.mps +31 -0
- data/ext/lpsolver-highs/check/instances/2821-quadobj.mps +29 -0
- data/ext/lpsolver-highs/check/instances/2821-summation.mps +30 -0
- data/ext/lpsolver-highs/check/instances/2821.mps +29 -0
- data/ext/lpsolver-highs/check/instances/2894.mps +89 -0
- data/ext/lpsolver-highs/check/instances/80bau3b.mps +23732 -0
- data/ext/lpsolver-highs/check/instances/WithInf.set +3 -0
- data/ext/lpsolver-highs/check/instances/adlittle.mps +335 -0
- data/ext/lpsolver-highs/check/instances/afiro.mps +83 -0
- data/ext/lpsolver-highs/check/instances/avgas.mps +51 -0
- data/ext/lpsolver-highs/check/instances/bell5.mps +384 -0
- data/ext/lpsolver-highs/check/instances/bgetam.mps +2112 -0
- data/ext/lpsolver-highs/check/instances/blending.mps +13 -0
- data/ext/lpsolver-highs/check/instances/box1.mps +1085 -0
- data/ext/lpsolver-highs/check/instances/chip.mps +13 -0
- data/ext/lpsolver-highs/check/instances/comment.mps +23 -0
- data/ext/lpsolver-highs/check/instances/cplex1.mps +9674 -0
- data/ext/lpsolver-highs/check/instances/dD2e.mps +10 -0
- data/ext/lpsolver-highs/check/instances/dcmulti.mps +2310 -0
- data/ext/lpsolver-highs/check/instances/e226.mps +1733 -0
- data/ext/lpsolver-highs/check/instances/egout-ac.mps +473 -0
- data/ext/lpsolver-highs/check/instances/egout.mps +403 -0
- data/ext/lpsolver-highs/check/instances/etamacro.mps +2084 -0
- data/ext/lpsolver-highs/check/instances/ex72a.mps +849 -0
- data/ext/lpsolver-highs/check/instances/fixed-binary.lp +11 -0
- data/ext/lpsolver-highs/check/instances/flugpl.mps +111 -0
- data/ext/lpsolver-highs/check/instances/flugpl_illegal_integer.sol +24 -0
- data/ext/lpsolver-highs/check/instances/flugpl_integer.sol +25 -0
- data/ext/lpsolver-highs/check/instances/forest6.mps +261 -0
- data/ext/lpsolver-highs/check/instances/galenet.mps +34 -0
- data/ext/lpsolver-highs/check/instances/gams10am.mps +478 -0
- data/ext/lpsolver-highs/check/instances/garbage.ems +3 -0
- data/ext/lpsolver-highs/check/instances/garbage.lp +3 -0
- data/ext/lpsolver-highs/check/instances/garbage.mps +3 -0
- data/ext/lpsolver-highs/check/instances/gas11.mps +2924 -0
- data/ext/lpsolver-highs/check/instances/gesa2.mps +5459 -0
- data/ext/lpsolver-highs/check/instances/greenbea.mps +19215 -0
- data/ext/lpsolver-highs/check/instances/gt2.mps +534 -0
- data/ext/lpsolver-highs/check/instances/infeasible-mip0.mps +140 -0
- data/ext/lpsolver-highs/check/instances/infeasible-mip1.mps +371 -0
- data/ext/lpsolver-highs/check/instances/israel.mps +1490 -0
- data/ext/lpsolver-highs/check/instances/issue-2095.mps +836 -0
- data/ext/lpsolver-highs/check/instances/issue-2173.mps +3331 -0
- data/ext/lpsolver-highs/check/instances/issue-2204.mps +143 -0
- data/ext/lpsolver-highs/check/instances/issue-2290.mps +158 -0
- data/ext/lpsolver-highs/check/instances/issue-2388.lp +76 -0
- data/ext/lpsolver-highs/check/instances/issue-2402.mps +435 -0
- data/ext/lpsolver-highs/check/instances/issue-2446.mps +9154 -0
- data/ext/lpsolver-highs/check/instances/issue-2585.lp +16 -0
- data/ext/lpsolver-highs/check/instances/issue-2874-3.mps +97 -0
- data/ext/lpsolver-highs/check/instances/klein1.mps +422 -0
- data/ext/lpsolver-highs/check/instances/lseu.mps +371 -0
- data/ext/lpsolver-highs/check/instances/model.xyz +1 -0
- data/ext/lpsolver-highs/check/instances/nan0.mps +13 -0
- data/ext/lpsolver-highs/check/instances/nan1.mps +13 -0
- data/ext/lpsolver-highs/check/instances/nan2.mps +13 -0
- data/ext/lpsolver-highs/check/instances/no-newline-eof.lp +5 -0
- data/ext/lpsolver-highs/check/instances/p01.mps +909 -0
- data/ext/lpsolver-highs/check/instances/p0548.mps +1992 -0
- data/ext/lpsolver-highs/check/instances/primal1.mps +3909 -0
- data/ext/lpsolver-highs/check/instances/qap04.mps +606 -0
- data/ext/lpsolver-highs/check/instances/qcqp.lp +8 -0
- data/ext/lpsolver-highs/check/instances/qjh.lp +9 -0
- data/ext/lpsolver-highs/check/instances/qjh.mps +18 -0
- data/ext/lpsolver-highs/check/instances/qjh_qmatrix.mps +19 -0
- data/ext/lpsolver-highs/check/instances/qjh_quadobj.mps +18 -0
- data/ext/lpsolver-highs/check/instances/qjh_quadobj_qmatrix.mps +25 -0
- data/ext/lpsolver-highs/check/instances/qjh_uncon.lp +10 -0
- data/ext/lpsolver-highs/check/instances/qjh_uncon.mps +17 -0
- data/ext/lpsolver-highs/check/instances/qpinfeasible.lp +8 -0
- data/ext/lpsolver-highs/check/instances/qptestnw.lp +7 -0
- data/ext/lpsolver-highs/check/instances/qpunbounded.lp +5 -0
- data/ext/lpsolver-highs/check/instances/refinery.mps +1882 -0
- data/ext/lpsolver-highs/check/instances/rgn.mps +559 -0
- data/ext/lpsolver-highs/check/instances/scrs8.mps +2717 -0
- data/ext/lpsolver-highs/check/instances/sctest.mps +66 -0
- data/ext/lpsolver-highs/check/instances/semi-continuous.lp +13 -0
- data/ext/lpsolver-highs/check/instances/semi-continuous.mps +24 -0
- data/ext/lpsolver-highs/check/instances/semi-integer.lp +15 -0
- data/ext/lpsolver-highs/check/instances/semi-integer.mps +22 -0
- data/ext/lpsolver-highs/check/instances/shell.mps +4039 -0
- data/ext/lpsolver-highs/check/instances/silly-names.mps +14 -0
- data/ext/lpsolver-highs/check/instances/small_mip.mps +87 -0
- data/ext/lpsolver-highs/check/instances/smalllp.mps +21 -0
- data/ext/lpsolver-highs/check/instances/sp150x300d.mps +1983 -0
- data/ext/lpsolver-highs/check/instances/stair.mps +2499 -0
- data/ext/lpsolver-highs/check/instances/standata.mps +2317 -0
- data/ext/lpsolver-highs/check/instances/standgub.mps +2428 -0
- data/ext/lpsolver-highs/check/instances/standmps.mps +2695 -0
- data/ext/lpsolver-highs/check/instances/test.mps +53 -0
- data/ext/lpsolver-highs/check/instances/vol1.mps +1895 -0
- data/ext/lpsolver-highs/check/instances/warnings.mps +68 -0
- data/ext/lpsolver-highs/check/instances/woodinfe.mps +216 -0
- data/ext/lpsolver-highs/check/matrix_multiplication.hpp +49 -0
- data/ext/lpsolver-highs/check/meson.build +92 -0
- data/ext/lpsolver-highs/check/pythontest.py +11 -0
- data/ext/lpsolver-highs/check/sample_options_file +8 -0
- data/ext/lpsolver-highs/cmake/CheckAtomic.cmake +74 -0
- data/ext/lpsolver-highs/cmake/FindCUDAConf.cmake +44 -0
- data/ext/lpsolver-highs/cmake/FindHipoDeps.cmake +351 -0
- data/ext/lpsolver-highs/cmake/README.md +243 -0
- data/ext/lpsolver-highs/cmake/cpp-highs.cmake +243 -0
- data/ext/lpsolver-highs/cmake/dotnet.cmake +94 -0
- data/ext/lpsolver-highs/cmake/highs-config.cmake.in +22 -0
- data/ext/lpsolver-highs/cmake/python-highs.cmake +74 -0
- data/ext/lpsolver-highs/cmake/set-version.cmake +26 -0
- data/ext/lpsolver-highs/cmake/sources-python.cmake +461 -0
- data/ext/lpsolver-highs/cmake/sources.cmake +618 -0
- data/ext/lpsolver-highs/docs/HiGHS_CopyrightHeader.pl +78 -0
- data/ext/lpsolver-highs/docs/HiGHS_CopyrightHeaderUpdateAll +32 -0
- data/ext/lpsolver-highs/docs/Project.toml +7 -0
- data/ext/lpsolver-highs/docs/README.md +27 -0
- data/ext/lpsolver-highs/docs/c_api_gen/HConfig.h +1 -0
- data/ext/lpsolver-highs/docs/c_api_gen/build.jl +48 -0
- data/ext/lpsolver-highs/docs/make.jl +115 -0
- data/ext/lpsolver-highs/docs/src/assets/logo.png +0 -0
- data/ext/lpsolver-highs/docs/src/callbacks.md +171 -0
- data/ext/lpsolver-highs/docs/src/executable.md +88 -0
- data/ext/lpsolver-highs/docs/src/guide/advanced.md +66 -0
- data/ext/lpsolver-highs/docs/src/guide/basic.md +116 -0
- data/ext/lpsolver-highs/docs/src/guide/further.md +193 -0
- data/ext/lpsolver-highs/docs/src/guide/gpu.md +58 -0
- data/ext/lpsolver-highs/docs/src/guide/index.md +18 -0
- data/ext/lpsolver-highs/docs/src/guide/kkt.md +219 -0
- data/ext/lpsolver-highs/docs/src/guide/numerics.md +55 -0
- data/ext/lpsolver-highs/docs/src/index.md +86 -0
- data/ext/lpsolver-highs/docs/src/installation.md +130 -0
- data/ext/lpsolver-highs/docs/src/interfaces/c_api.md +6 -0
- data/ext/lpsolver-highs/docs/src/interfaces/cpp/examples.md +1 -0
- data/ext/lpsolver-highs/docs/src/interfaces/cpp/index.md +29 -0
- data/ext/lpsolver-highs/docs/src/interfaces/cpp/library.md +107 -0
- data/ext/lpsolver-highs/docs/src/interfaces/csharp.md +55 -0
- data/ext/lpsolver-highs/docs/src/interfaces/fortran.md +11 -0
- data/ext/lpsolver-highs/docs/src/interfaces/julia/index.md +130 -0
- data/ext/lpsolver-highs/docs/src/interfaces/other.md +41 -0
- data/ext/lpsolver-highs/docs/src/interfaces/python/example-py.md +275 -0
- data/ext/lpsolver-highs/docs/src/interfaces/python/index.md +91 -0
- data/ext/lpsolver-highs/docs/src/interfaces/python/model-py.md +90 -0
- data/ext/lpsolver-highs/docs/src/options/definitions.md +529 -0
- data/ext/lpsolver-highs/docs/src/options/intro.md +46 -0
- data/ext/lpsolver-highs/docs/src/parallel.md +88 -0
- data/ext/lpsolver-highs/docs/src/solvers.md +168 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsHessian.md +9 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsIis.md +16 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsLp.md +19 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsModel.md +6 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsSparseMatrix.md +10 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/index.md +11 -0
- data/ext/lpsolver-highs/docs/src/structures/enums.md +114 -0
- data/ext/lpsolver-highs/docs/src/structures/index.md +12 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/HighsBasis.md +8 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/HighsInfo.md +148 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/HighsLinearObjective.md +11 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/HighsSolution.md +10 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/index.md +10 -0
- data/ext/lpsolver-highs/docs/src/terminology.md +163 -0
- data/ext/lpsolver-highs/examples/CMakeLists.txt +26 -0
- data/ext/lpsolver-highs/examples/Docs.py +104 -0
- data/ext/lpsolver-highs/examples/branch-and-price.py +465 -0
- data/ext/lpsolver-highs/examples/call_highs_from_c.c +685 -0
- data/ext/lpsolver-highs/examples/call_highs_from_c_minimal.c +659 -0
- data/ext/lpsolver-highs/examples/call_highs_from_cpp.cpp +178 -0
- data/ext/lpsolver-highs/examples/call_highs_from_csharp.cs +83 -0
- data/ext/lpsolver-highs/examples/call_highs_from_fortran.f90 +579 -0
- data/ext/lpsolver-highs/examples/call_highs_from_python.py +448 -0
- data/ext/lpsolver-highs/examples/call_highs_from_python_highspy.py +71 -0
- data/ext/lpsolver-highs/examples/call_highs_from_python_mps.py +59 -0
- data/ext/lpsolver-highs/examples/callback_gap.py +71 -0
- data/ext/lpsolver-highs/examples/chip.py +43 -0
- data/ext/lpsolver-highs/examples/chip0.py +29 -0
- data/ext/lpsolver-highs/examples/distillation.py +77 -0
- data/ext/lpsolver-highs/examples/knapsack.py +43 -0
- data/ext/lpsolver-highs/examples/minimal.py +11 -0
- data/ext/lpsolver-highs/examples/multi_objective.py +139 -0
- data/ext/lpsolver-highs/examples/multiple_objective.py +120 -0
- data/ext/lpsolver-highs/examples/network_flow.py +37 -0
- data/ext/lpsolver-highs/examples/nqueens.py +29 -0
- data/ext/lpsolver-highs/examples/plot_highs_log.py +134 -0
- data/ext/lpsolver-highs/extern/CLI11.hpp +11546 -0
- data/ext/lpsolver-highs/extern/LICENCE_1_0.txt +23 -0
- data/ext/lpsolver-highs/extern/amd/License.txt +35 -0
- data/ext/lpsolver-highs/extern/amd/SuiteSparse_config.c +54 -0
- data/ext/lpsolver-highs/extern/amd/SuiteSparse_config.h +56 -0
- data/ext/lpsolver-highs/extern/amd/amd.h +357 -0
- data/ext/lpsolver-highs/extern/amd/amd_1.c +172 -0
- data/ext/lpsolver-highs/extern/amd/amd_2.c +1761 -0
- data/ext/lpsolver-highs/extern/amd/amd_aat.c +179 -0
- data/ext/lpsolver-highs/extern/amd/amd_control.c +65 -0
- data/ext/lpsolver-highs/extern/amd/amd_defaults.c +37 -0
- data/ext/lpsolver-highs/extern/amd/amd_info.c +120 -0
- data/ext/lpsolver-highs/extern/amd/amd_internal.h +137 -0
- data/ext/lpsolver-highs/extern/amd/amd_order.c +195 -0
- data/ext/lpsolver-highs/extern/amd/amd_post_tree.c +105 -0
- data/ext/lpsolver-highs/extern/amd/amd_postorder.c +140 -0
- data/ext/lpsolver-highs/extern/amd/amd_preprocess.c +107 -0
- data/ext/lpsolver-highs/extern/amd/amd_valid.c +93 -0
- data/ext/lpsolver-highs/extern/amd/changes.txt +8 -0
- data/ext/lpsolver-highs/extern/catch.hpp +18861 -0
- data/ext/lpsolver-highs/extern/metis/Changes.txt +31 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/GKlib.h +62 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/error.c +21 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_arch.h +64 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_defs.h +19 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_macros.h +50 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mkblas.h +51 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mkmemory.h +80 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mkpqueue.h +329 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mkrandom.h +89 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mksort.h +271 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_ms_inttypes.h +41 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_ms_stat.h +22 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_ms_stdint.h +41 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_proto.h +50 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_struct.h +66 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_types.h +15 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/mcore.c +176 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/memory.c +23 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/random.c +37 -0
- data/ext/lpsolver-highs/extern/metis/LICENSE.txt +18 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/auxapi.c +27 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/balance.c +491 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/bucketsort.c +44 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/coarsen.c +895 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/compress.c +231 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/contig.c +83 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/defs.h +39 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/fm.c +527 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/gklib.c +55 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/gklib_defs.h +33 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/graph.c +268 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/initpart.c +385 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/macros.h +59 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/mcutil.c +162 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/metislib.h +35 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/mmd.c +598 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/ometis.c +661 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/options.c +260 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/proto.h +172 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/refine.c +99 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/separator.c +57 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/sfm.c +581 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/srefine.c +152 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/stdheaders.h +29 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/struct.h +117 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/util.c +59 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/wspace.c +91 -0
- data/ext/lpsolver-highs/extern/metis/metis.h +271 -0
- data/ext/lpsolver-highs/extern/pdqsort/license.txt +16 -0
- data/ext/lpsolver-highs/extern/pdqsort/pdqsort.h +532 -0
- data/ext/lpsolver-highs/extern/rcm/LICENSE +19 -0
- data/ext/lpsolver-highs/extern/rcm/rcm.cpp +873 -0
- data/ext/lpsolver-highs/extern/rcm/rcm.h +22 -0
- data/ext/lpsolver-highs/extern/zstr/LICENSE +21 -0
- data/ext/lpsolver-highs/extern/zstr/strict_fstream.hpp +237 -0
- data/ext/lpsolver-highs/extern/zstr/zstr.hpp +473 -0
- data/ext/lpsolver-highs/flake.lock +61 -0
- data/ext/lpsolver-highs/flake.nix +73 -0
- data/ext/lpsolver-highs/highs/CMakeLists.txt +499 -0
- data/ext/lpsolver-highs/highs/HConfig.h.bazel.in +25 -0
- data/ext/lpsolver-highs/highs/HConfig.h.in +22 -0
- data/ext/lpsolver-highs/highs/HConfig.h.meson.in +17 -0
- data/ext/lpsolver-highs/highs/Highs.h +1812 -0
- data/ext/lpsolver-highs/highs/HighsRun.md +143 -0
- data/ext/lpsolver-highs/highs/highs_bindings.cpp +1826 -0
- data/ext/lpsolver-highs/highs/highspy/__init__.py +93 -0
- data/ext/lpsolver-highs/highs/highspy/__init__.pyi +91 -0
- data/ext/lpsolver-highs/highs/highspy/_core/__init__.pyi +1058 -0
- data/ext/lpsolver-highs/highs/highspy/_core/cb.pyi +118 -0
- data/ext/lpsolver-highs/highs/highspy/_core/simplex_constants.pyi +472 -0
- data/ext/lpsolver-highs/highs/highspy/highs.py +2430 -0
- data/ext/lpsolver-highs/highs/interfaces/highs_c_api.cpp +1812 -0
- data/ext/lpsolver-highs/highs/interfaces/highs_c_api.h +2651 -0
- data/ext/lpsolver-highs/highs/interfaces/highs_csharp_api.cs +1142 -0
- data/ext/lpsolver-highs/highs/interfaces/highs_fortran_api.f90 +873 -0
- data/ext/lpsolver-highs/highs/io/Filereader.cpp +87 -0
- data/ext/lpsolver-highs/highs/io/Filereader.h +45 -0
- data/ext/lpsolver-highs/highs/io/FilereaderLp.cpp +539 -0
- data/ext/lpsolver-highs/highs/io/FilereaderLp.h +49 -0
- data/ext/lpsolver-highs/highs/io/FilereaderMps.cpp +86 -0
- data/ext/lpsolver-highs/highs/io/FilereaderMps.h +27 -0
- data/ext/lpsolver-highs/highs/io/HMPSIO.cpp +1001 -0
- data/ext/lpsolver-highs/highs/io/HMPSIO.h +78 -0
- data/ext/lpsolver-highs/highs/io/HMpsFF.cpp +2113 -0
- data/ext/lpsolver-highs/highs/io/HMpsFF.h +245 -0
- data/ext/lpsolver-highs/highs/io/HighsIO.cpp +371 -0
- data/ext/lpsolver-highs/highs/io/HighsIO.h +118 -0
- data/ext/lpsolver-highs/highs/io/LoadOptions.cpp +60 -0
- data/ext/lpsolver-highs/highs/io/LoadOptions.h +24 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/LICENSE +19 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/builder.hpp +25 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/def.hpp +19 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/model.hpp +68 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/reader.cpp +1375 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/reader.hpp +10 -0
- data/ext/lpsolver-highs/highs/ipm/IpxSolution.h +32 -0
- data/ext/lpsolver-highs/highs/ipm/IpxWrapper.cpp +1526 -0
- data/ext/lpsolver-highs/highs/ipm/IpxWrapper.h +106 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu.h +161 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_factorize.c +132 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_factorize.h +247 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_get_factors.c +148 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_get_factors.h +108 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_initialize.c +24 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_initialize.h +119 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_factorize.h +34 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_free.h +19 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_get_factors.h +34 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_initialize.h +46 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_solve_dense.h +29 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_solve_for_update.h +42 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_solve_sparse.h +32 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_update.h +31 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_object.c +325 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_object.h +30 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_dense.c +46 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_dense.h +75 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_for_update.c +79 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_for_update.h +169 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_sparse.c +63 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_sparse.h +112 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_update.c +44 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_update.h +125 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_build_factors.c +441 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_condest.c +124 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_def.h +39 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_dfs.c +141 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_factorize_bump.c +56 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_file.c +184 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_file.h +21 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_garbage_perm.c +53 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_initialize.c +56 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_internal.c +352 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_internal.h +220 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_list.h +173 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_markowitz.c +188 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_matrix_norm.c +51 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_pivot.c +1247 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_residual_test.c +155 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_setup_bump.c +198 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_singletons.c +511 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_dense.c +129 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_for_update.c +360 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_sparse.c +284 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_symbolic.c +48 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_triangular.c +140 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_update.c +908 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/Auxiliary.cpp +301 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/Auxiliary.h +104 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/IntConfig.h +27 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/KrylovMethods.cpp +193 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/KrylovMethods.h +30 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/Log.cpp +60 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/Log.h +62 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/OrderingPrint.h +10 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/VectorOperations.cpp +117 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/VectorOperations.h +59 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/mycblas.h +85 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Analyse.cpp +1367 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Analyse.h +122 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/CallAndTimeBlas.cpp +114 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/CallAndTimeBlas.h +46 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/CliqueStack.cpp +82 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/CliqueStack.h +83 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DataCollector.cpp +326 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DataCollector.h +86 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DenseFact.h +48 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DenseFactHybrid.cpp +279 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DenseFactKernel.cpp +284 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DgemmParallel.cpp +38 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DgemmParallel.h +32 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FactorHiGHS.cpp +57 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FactorHiGHS.h +112 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FactorHiGHSSettings.h +63 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Factorise.cpp +405 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Factorise.h +85 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FormatHandler.cpp +46 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FormatHandler.h +95 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/HybridHybridFormatHandler.cpp +238 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/HybridHybridFormatHandler.h +31 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/HybridSolveHandler.cpp +272 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/HybridSolveHandler.h +26 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/KrylovMethodsIpm.cpp +83 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/KrylovMethodsIpm.h +45 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Numeric.cpp +54 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Numeric.h +46 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/ReturnValues.h +19 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/SolveHandler.cpp +10 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/SolveHandler.h +48 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Swaps.cpp +70 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Swaps.h +19 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Symbolic.cpp +101 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Symbolic.h +220 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Timing.h +114 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Control.cpp +38 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Control.h +41 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/FactorHiGHSSolver.cpp +887 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/FactorHiGHSSolver.h +92 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Info.h +58 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/IpmData.cpp +8 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/IpmData.h +37 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Iterate.cpp +640 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Iterate.h +172 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/LinearSolver.h +81 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/LogHighs.cpp +71 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/LogHighs.h +33 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Model.cpp +403 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Model.h +136 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Options.h +35 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Parameters.h +63 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/PreProcess.cpp +646 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/PreProcess.h +94 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Refine.cpp +214 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Solver.cpp +1346 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Solver.h +338 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Status.h +88 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basiclu_kernel.cc +71 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basiclu_kernel.h +20 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basiclu_wrapper.cc +299 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basiclu_wrapper.h +47 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basis.cc +966 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basis.h +350 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/conjugate_residuals.cc +217 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/conjugate_residuals.h +74 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/control.cc +151 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/control.h +167 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/crossover.cc +479 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/crossover.h +157 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/diagonal_precond.cc +70 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/diagonal_precond.h +45 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/forrest_tomlin.cc +360 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/forrest_tomlin.h +102 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/guess_basis.cc +233 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/guess_basis.h +21 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/indexed_vector.cc +30 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/indexed_vector.h +113 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/info.cc +124 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/info.h +27 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipm.cc +897 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipm.h +94 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_c.cc +83 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_c.h +47 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_config.h +9 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_info.h +111 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_internal.h +89 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_parameters.h +76 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_status.h +57 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/iterate.cc +683 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/iterate.h +331 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver.cc +23 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver.h +70 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver_basis.cc +387 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver_basis.h +66 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver_diag.cc +120 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver_diag.h +48 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/linear_operator.cc +10 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/linear_operator.h +26 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lp_solver.cc +686 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lp_solver.h +204 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lu_factorization.cc +131 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lu_factorization.h +79 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lu_update.cc +62 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lu_update.h +129 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/maxvolume.cc +337 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/maxvolume.h +54 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/model.cc +1528 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/model.h +413 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/multistream.h +52 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/normal_matrix.cc +126 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/normal_matrix.h +44 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/power_method.h +44 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/sparse_matrix.cc +382 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/sparse_matrix.h +195 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/sparse_utils.cc +92 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/sparse_utils.h +58 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/splitted_normal_matrix.cc +117 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/splitted_normal_matrix.h +63 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/starting_basis.cc +182 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/starting_basis.h +39 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/symbolic_invert.cc +183 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/symbolic_invert.h +29 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/timer.cc +16 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/timer.h +25 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/utils.cc +95 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/utils.h +37 -0
- data/ext/lpsolver-highs/highs/lp_data/HConst.h +430 -0
- data/ext/lpsolver-highs/highs/lp_data/HStruct.h +213 -0
- data/ext/lpsolver-highs/highs/lp_data/Highs.cpp +4949 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsAnalysis.h +23 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsCallback.cpp +323 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsCallback.h +104 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsCallbackStruct.h +70 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsDebug.cpp +54 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsDebug.h +34 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsDeprecated.cpp +181 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsIis.cpp +1290 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsIis.h +139 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInfo.cpp +426 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInfo.h +421 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInfoDebug.cpp +175 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInfoDebug.h +27 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInterface.cpp +4344 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLp.cpp +564 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLp.h +97 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLpSolverObject.h +47 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLpUtils.cpp +3794 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLpUtils.h +330 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsModelUtils.cpp +1650 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsModelUtils.h +129 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsOptions.cpp +1176 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsOptions.h +1715 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsRanging.cpp +733 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsRanging.h +43 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolution.cpp +2194 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolution.h +179 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolutionDebug.cpp +490 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolutionDebug.h +87 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolve.cpp +747 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolve.h +29 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsStatus.cpp +48 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsStatus.h +29 -0
- data/ext/lpsolver-highs/highs/lp_data/Iis.md +113 -0
- data/ext/lpsolver-highs/highs/meson.build +433 -0
- data/ext/lpsolver-highs/highs/mip/HighsCliqueTable.cpp +2236 -0
- data/ext/lpsolver-highs/highs/mip/HighsCliqueTable.h +329 -0
- data/ext/lpsolver-highs/highs/mip/HighsConflictPool.cpp +201 -0
- data/ext/lpsolver-highs/highs/mip/HighsConflictPool.h +109 -0
- data/ext/lpsolver-highs/highs/mip/HighsCutGeneration.cpp +1491 -0
- data/ext/lpsolver-highs/highs/mip/HighsCutGeneration.h +108 -0
- data/ext/lpsolver-highs/highs/mip/HighsCutPool.cpp +526 -0
- data/ext/lpsolver-highs/highs/mip/HighsCutPool.h +168 -0
- data/ext/lpsolver-highs/highs/mip/HighsDebugSol.cpp +313 -0
- data/ext/lpsolver-highs/highs/mip/HighsDebugSol.h +133 -0
- data/ext/lpsolver-highs/highs/mip/HighsDomain.cpp +3861 -0
- data/ext/lpsolver-highs/highs/mip/HighsDomain.h +657 -0
- data/ext/lpsolver-highs/highs/mip/HighsDomainChange.h +48 -0
- data/ext/lpsolver-highs/highs/mip/HighsDynamicRowMatrix.cpp +199 -0
- data/ext/lpsolver-highs/highs/mip/HighsDynamicRowMatrix.h +104 -0
- data/ext/lpsolver-highs/highs/mip/HighsFeasibilityJump.cpp +139 -0
- data/ext/lpsolver-highs/highs/mip/HighsGFkSolve.cpp +106 -0
- data/ext/lpsolver-highs/highs/mip/HighsGFkSolve.h +439 -0
- data/ext/lpsolver-highs/highs/mip/HighsImplications.cpp +915 -0
- data/ext/lpsolver-highs/highs/mip/HighsImplications.h +194 -0
- data/ext/lpsolver-highs/highs/mip/HighsLpAggregator.cpp +56 -0
- data/ext/lpsolver-highs/highs/mip/HighsLpAggregator.h +50 -0
- data/ext/lpsolver-highs/highs/mip/HighsLpRelaxation.cpp +1609 -0
- data/ext/lpsolver-highs/highs/mip/HighsLpRelaxation.h +361 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipAnalysis.cpp +313 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipAnalysis.h +71 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipSolver.cpp +1002 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipSolver.h +159 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipSolverData.cpp +2936 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipSolverData.h +313 -0
- data/ext/lpsolver-highs/highs/mip/HighsModkSeparator.cpp +267 -0
- data/ext/lpsolver-highs/highs/mip/HighsModkSeparator.h +60 -0
- data/ext/lpsolver-highs/highs/mip/HighsNodeQueue.cpp +443 -0
- data/ext/lpsolver-highs/highs/mip/HighsNodeQueue.h +312 -0
- data/ext/lpsolver-highs/highs/mip/HighsObjectiveFunction.cpp +124 -0
- data/ext/lpsolver-highs/highs/mip/HighsObjectiveFunction.h +71 -0
- data/ext/lpsolver-highs/highs/mip/HighsPathSeparator.cpp +549 -0
- data/ext/lpsolver-highs/highs/mip/HighsPathSeparator.h +39 -0
- data/ext/lpsolver-highs/highs/mip/HighsPrimalHeuristics.cpp +1673 -0
- data/ext/lpsolver-highs/highs/mip/HighsPrimalHeuristics.h +75 -0
- data/ext/lpsolver-highs/highs/mip/HighsPseudocost.cpp +129 -0
- data/ext/lpsolver-highs/highs/mip/HighsPseudocost.h +366 -0
- data/ext/lpsolver-highs/highs/mip/HighsRedcostFixing.cpp +316 -0
- data/ext/lpsolver-highs/highs/mip/HighsRedcostFixing.h +42 -0
- data/ext/lpsolver-highs/highs/mip/HighsSearch.cpp +1881 -0
- data/ext/lpsolver-highs/highs/mip/HighsSearch.h +241 -0
- data/ext/lpsolver-highs/highs/mip/HighsSeparation.cpp +186 -0
- data/ext/lpsolver-highs/highs/mip/HighsSeparation.h +41 -0
- data/ext/lpsolver-highs/highs/mip/HighsSeparator.cpp +39 -0
- data/ext/lpsolver-highs/highs/mip/HighsSeparator.h +60 -0
- data/ext/lpsolver-highs/highs/mip/HighsTableauSeparator.cpp +244 -0
- data/ext/lpsolver-highs/highs/mip/HighsTableauSeparator.h +34 -0
- data/ext/lpsolver-highs/highs/mip/HighsTransformedLp.cpp +563 -0
- data/ext/lpsolver-highs/highs/mip/HighsTransformedLp.h +63 -0
- data/ext/lpsolver-highs/highs/mip/MipTimer.h +544 -0
- data/ext/lpsolver-highs/highs/mip/feasibilityjump.hh +800 -0
- data/ext/lpsolver-highs/highs/model/HighsHessian.cpp +263 -0
- data/ext/lpsolver-highs/highs/model/HighsHessian.h +54 -0
- data/ext/lpsolver-highs/highs/model/HighsHessianUtils.cpp +584 -0
- data/ext/lpsolver-highs/highs/model/HighsHessianUtils.h +47 -0
- data/ext/lpsolver-highs/highs/model/HighsModel.cpp +46 -0
- data/ext/lpsolver-highs/highs/model/HighsModel.h +42 -0
- data/ext/lpsolver-highs/highs/parallel/HighsBinarySemaphore.h +108 -0
- data/ext/lpsolver-highs/highs/parallel/HighsCacheAlign.h +82 -0
- data/ext/lpsolver-highs/highs/parallel/HighsCombinable.h +116 -0
- data/ext/lpsolver-highs/highs/parallel/HighsMutex.h +124 -0
- data/ext/lpsolver-highs/highs/parallel/HighsParallel.h +128 -0
- data/ext/lpsolver-highs/highs/parallel/HighsRaceTimer.h +38 -0
- data/ext/lpsolver-highs/highs/parallel/HighsSchedulerConstants.h +19 -0
- data/ext/lpsolver-highs/highs/parallel/HighsSpinMutex.h +48 -0
- data/ext/lpsolver-highs/highs/parallel/HighsSplitDeque.h +606 -0
- data/ext/lpsolver-highs/highs/parallel/HighsTask.h +170 -0
- data/ext/lpsolver-highs/highs/parallel/HighsTaskExecutor.cpp +43 -0
- data/ext/lpsolver-highs/highs/parallel/HighsTaskExecutor.h +217 -0
- data/ext/lpsolver-highs/highs/pdlp/CupdlpWrapper.cpp +848 -0
- data/ext/lpsolver-highs/highs/pdlp/CupdlpWrapper.h +108 -0
- data/ext/lpsolver-highs/highs/pdlp/HiPdlpTimer.h +155 -0
- data/ext/lpsolver-highs/highs/pdlp/HiPdlpWrapper.cpp +141 -0
- data/ext/lpsolver-highs/highs/pdlp/HiPdlpWrapper.h +26 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/Diff +12 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/Meld +7 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/Merge +2 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/README.md +95 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/CMakeLists.txt +58 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/cupdlp_cuda_kernels.cu +338 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/cupdlp_cuda_kernels.cuh +319 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/cupdlp_cudalinalg.cu +386 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/cupdlp_cudalinalg.cuh +149 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/test_cublas.c +154 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/test_cuda_linalg.c +79 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp.h +16 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_cs.c +214 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_cs.h +40 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_defs.h +447 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_linalg.c +802 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_linalg.h +189 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_proj.c +148 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_proj.h +19 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_restart.c +124 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_restart.h +31 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_scaling.c +425 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_scaling.h +26 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_solver.c +1498 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_solver.h +105 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_step.c +478 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_step.h +37 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_utils.c +1850 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_utils.h +212 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/glbopts.h +342 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/defs.hpp +222 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/linalg.cc +231 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/linalg.hpp +61 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/logger.cc +225 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/logger.hpp +80 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdhg.cc +2798 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdhg.cu +497 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdhg.hpp +358 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdhg_kernels.hpp +77 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdlp_gpu_debug.hpp +62 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/restart.cc +132 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/restart.hpp +96 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/scaling.cc +307 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/scaling.hpp +74 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/solver_results.hpp +65 -0
- data/ext/lpsolver-highs/highs/presolve/HPresolve.cpp +8511 -0
- data/ext/lpsolver-highs/highs/presolve/HPresolve.h +505 -0
- data/ext/lpsolver-highs/highs/presolve/HPresolveAnalysis.cpp +239 -0
- data/ext/lpsolver-highs/highs/presolve/HPresolveAnalysis.h +52 -0
- data/ext/lpsolver-highs/highs/presolve/HighsPostsolveStack.cpp +1368 -0
- data/ext/lpsolver-highs/highs/presolve/HighsPostsolveStack.h +943 -0
- data/ext/lpsolver-highs/highs/presolve/HighsSymmetry.cpp +1921 -0
- data/ext/lpsolver-highs/highs/presolve/HighsSymmetry.h +284 -0
- data/ext/lpsolver-highs/highs/presolve/ICrash.cpp +474 -0
- data/ext/lpsolver-highs/highs/presolve/ICrash.h +124 -0
- data/ext/lpsolver-highs/highs/presolve/ICrashUtil.cpp +267 -0
- data/ext/lpsolver-highs/highs/presolve/ICrashUtil.h +62 -0
- data/ext/lpsolver-highs/highs/presolve/ICrashX.cpp +173 -0
- data/ext/lpsolver-highs/highs/presolve/ICrashX.h +23 -0
- data/ext/lpsolver-highs/highs/presolve/PresolveComponent.cpp +45 -0
- data/ext/lpsolver-highs/highs/presolve/PresolveComponent.h +90 -0
- data/ext/lpsolver-highs/highs/qpsolver/README.md +185 -0
- data/ext/lpsolver-highs/highs/qpsolver/a_asm.cpp +139 -0
- data/ext/lpsolver-highs/highs/qpsolver/a_asm.hpp +77 -0
- data/ext/lpsolver-highs/highs/qpsolver/a_quass.cpp +194 -0
- data/ext/lpsolver-highs/highs/qpsolver/a_quass.hpp +22 -0
- data/ext/lpsolver-highs/highs/qpsolver/basis.cpp +443 -0
- data/ext/lpsolver-highs/highs/qpsolver/basis.hpp +159 -0
- data/ext/lpsolver-highs/highs/qpsolver/crashsolution.hpp +20 -0
- data/ext/lpsolver-highs/highs/qpsolver/dantzigpricing.hpp +80 -0
- data/ext/lpsolver-highs/highs/qpsolver/devexharrispricing.hpp +98 -0
- data/ext/lpsolver-highs/highs/qpsolver/devexpricing.hpp +108 -0
- data/ext/lpsolver-highs/highs/qpsolver/eventhandler.hpp +30 -0
- data/ext/lpsolver-highs/highs/qpsolver/factor.hpp +408 -0
- data/ext/lpsolver-highs/highs/qpsolver/feasibility_bounded.hpp +114 -0
- data/ext/lpsolver-highs/highs/qpsolver/feasibility_highs.hpp +301 -0
- data/ext/lpsolver-highs/highs/qpsolver/gradient.hpp +46 -0
- data/ext/lpsolver-highs/highs/qpsolver/instance.hpp +70 -0
- data/ext/lpsolver-highs/highs/qpsolver/matrix.hpp +342 -0
- data/ext/lpsolver-highs/highs/qpsolver/perturbation.cpp +41 -0
- data/ext/lpsolver-highs/highs/qpsolver/perturbation.hpp +15 -0
- data/ext/lpsolver-highs/highs/qpsolver/pricing.hpp +22 -0
- data/ext/lpsolver-highs/highs/qpsolver/qpconst.hpp +34 -0
- data/ext/lpsolver-highs/highs/qpsolver/qpvector.hpp +242 -0
- data/ext/lpsolver-highs/highs/qpsolver/quass.cpp +551 -0
- data/ext/lpsolver-highs/highs/qpsolver/quass.hpp +27 -0
- data/ext/lpsolver-highs/highs/qpsolver/ratiotest.cpp +146 -0
- data/ext/lpsolver-highs/highs/qpsolver/ratiotest.hpp +26 -0
- data/ext/lpsolver-highs/highs/qpsolver/reducedcosts.hpp +46 -0
- data/ext/lpsolver-highs/highs/qpsolver/reducedgradient.hpp +95 -0
- data/ext/lpsolver-highs/highs/qpsolver/runtime.hpp +45 -0
- data/ext/lpsolver-highs/highs/qpsolver/scaling.cpp +123 -0
- data/ext/lpsolver-highs/highs/qpsolver/scaling.hpp +15 -0
- data/ext/lpsolver-highs/highs/qpsolver/settings.hpp +84 -0
- data/ext/lpsolver-highs/highs/qpsolver/snippets.hpp +36 -0
- data/ext/lpsolver-highs/highs/qpsolver/statistics.hpp +30 -0
- data/ext/lpsolver-highs/highs/qpsolver/steepestedgepricing.hpp +173 -0
- data/ext/lpsolver-highs/highs/simplex/HApp.h +550 -0
- data/ext/lpsolver-highs/highs/simplex/HEkk.cpp +4404 -0
- data/ext/lpsolver-highs/highs/simplex/HEkk.h +419 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkControl.cpp +146 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDebug.cpp +1722 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDual.cpp +3003 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDual.h +513 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualMulti.cpp +1020 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualRHS.cpp +535 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualRHS.h +134 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualRow.cpp +697 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualRow.h +201 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkInterface.cpp +26 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkPrimal.cpp +2984 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkPrimal.h +191 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplex.cpp +330 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplex.h +42 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexDebug.cpp +145 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexDebug.h +48 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNla.cpp +517 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNla.h +158 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNlaDebug.cpp +373 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNlaFreeze.cpp +28 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNlaProductForm.cpp +113 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexReport.cpp +77 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexReport.h +21 -0
- data/ext/lpsolver-highs/highs/simplex/HighsSimplexAnalysis.cpp +1495 -0
- data/ext/lpsolver-highs/highs/simplex/HighsSimplexAnalysis.h +500 -0
- data/ext/lpsolver-highs/highs/simplex/SimplexConst.h +273 -0
- data/ext/lpsolver-highs/highs/simplex/SimplexStruct.h +263 -0
- data/ext/lpsolver-highs/highs/simplex/SimplexTimer.h +414 -0
- data/ext/lpsolver-highs/highs/test_kkt/DevKkt.cpp +469 -0
- data/ext/lpsolver-highs/highs/test_kkt/DevKkt.h +143 -0
- data/ext/lpsolver-highs/highs/test_kkt/KktCh2.cpp +305 -0
- data/ext/lpsolver-highs/highs/test_kkt/KktCh2.h +79 -0
- data/ext/lpsolver-highs/highs/util/FactorTimer.h +199 -0
- data/ext/lpsolver-highs/highs/util/HFactor.cpp +2597 -0
- data/ext/lpsolver-highs/highs/util/HFactor.h +587 -0
- data/ext/lpsolver-highs/highs/util/HFactorConst.h +81 -0
- data/ext/lpsolver-highs/highs/util/HFactorDebug.cpp +231 -0
- data/ext/lpsolver-highs/highs/util/HFactorDebug.h +55 -0
- data/ext/lpsolver-highs/highs/util/HFactorExtend.cpp +229 -0
- data/ext/lpsolver-highs/highs/util/HFactorRefactor.cpp +304 -0
- data/ext/lpsolver-highs/highs/util/HFactorUtils.cpp +122 -0
- data/ext/lpsolver-highs/highs/util/HSet.cpp +197 -0
- data/ext/lpsolver-highs/highs/util/HSet.h +89 -0
- data/ext/lpsolver-highs/highs/util/HVector.h +22 -0
- data/ext/lpsolver-highs/highs/util/HVectorBase.cpp +271 -0
- data/ext/lpsolver-highs/highs/util/HVectorBase.h +102 -0
- data/ext/lpsolver-highs/highs/util/HighsCDouble.h +323 -0
- data/ext/lpsolver-highs/highs/util/HighsComponent.h +53 -0
- data/ext/lpsolver-highs/highs/util/HighsDataStack.h +83 -0
- data/ext/lpsolver-highs/highs/util/HighsDisjointSets.h +107 -0
- data/ext/lpsolver-highs/highs/util/HighsHash.cpp +10 -0
- data/ext/lpsolver-highs/highs/util/HighsHash.h +1274 -0
- data/ext/lpsolver-highs/highs/util/HighsHashTree.h +1461 -0
- data/ext/lpsolver-highs/highs/util/HighsInt.h +36 -0
- data/ext/lpsolver-highs/highs/util/HighsIntegers.h +212 -0
- data/ext/lpsolver-highs/highs/util/HighsLinearSumBounds.cpp +267 -0
- data/ext/lpsolver-highs/highs/util/HighsLinearSumBounds.h +203 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixPic.cpp +146 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixPic.h +37 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixSlice.h +561 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixUtils.cpp +407 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixUtils.h +57 -0
- data/ext/lpsolver-highs/highs/util/HighsMemoryAllocation.h +63 -0
- data/ext/lpsolver-highs/highs/util/HighsRandom.h +242 -0
- data/ext/lpsolver-highs/highs/util/HighsRbTree.h +452 -0
- data/ext/lpsolver-highs/highs/util/HighsSort.cpp +364 -0
- data/ext/lpsolver-highs/highs/util/HighsSort.h +131 -0
- data/ext/lpsolver-highs/highs/util/HighsSparseMatrix.cpp +1746 -0
- data/ext/lpsolver-highs/highs/util/HighsSparseMatrix.h +151 -0
- data/ext/lpsolver-highs/highs/util/HighsSparseVectorSum.h +95 -0
- data/ext/lpsolver-highs/highs/util/HighsSplay.h +135 -0
- data/ext/lpsolver-highs/highs/util/HighsTimer.h +385 -0
- data/ext/lpsolver-highs/highs/util/HighsUtils.cpp +1259 -0
- data/ext/lpsolver-highs/highs/util/HighsUtils.h +272 -0
- data/ext/lpsolver-highs/highs/util/stringutil.cpp +131 -0
- data/ext/lpsolver-highs/highs/util/stringutil.h +46 -0
- data/ext/lpsolver-highs/highs.pc.in +12 -0
- data/ext/lpsolver-highs/meson.build +198 -0
- data/ext/lpsolver-highs/meson_options.txt +31 -0
- data/ext/lpsolver-highs/nuget/HiGHS_Logo.png +0 -0
- data/ext/lpsolver-highs/nuget/Highs.csproj +25 -0
- data/ext/lpsolver-highs/nuget/Highs.csproj.in +36 -0
- data/ext/lpsolver-highs/nuget/HowToAlternative.md +77 -0
- data/ext/lpsolver-highs/nuget/README.md +38 -0
- data/ext/lpsolver-highs/nuget/arm-toolchain.cmake +15 -0
- data/ext/lpsolver-highs/nuget/build_linux-arm.sh +13 -0
- data/ext/lpsolver-highs/nuget/build_linux.sh +10 -0
- data/ext/lpsolver-highs/nuget/build_windows.ps1 +27 -0
- data/ext/lpsolver-highs/nuget/generatePackage.ps1 +28 -0
- data/ext/lpsolver-highs/pyproject.toml +221 -0
- data/ext/lpsolver-highs/subprojects/pybind11.wrap +13 -0
- data/ext/lpsolver-highs/tests/test_highspy.py +2310 -0
- data/ext/lpsolver-highs/version.rc.in +50 -0
- data/lib/lpsolver/highs +0 -0
- data/lib/lpsolver/model.rb +35 -7
- data/lib/lpsolver/native.so +0 -0
- data/lib/lpsolver/native_model.rb +261 -0
- data/lib/lpsolver/solution.rb +93 -8
- data/lib/lpsolver/version.rb +1 -1
- data/lpsolver.gemspec +4 -1
- metadata +1176 -4
|
@@ -0,0 +1,2936 @@
|
|
|
1
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
2
|
+
/* */
|
|
3
|
+
/* This file is part of the HiGHS linear optimization suite */
|
|
4
|
+
/* */
|
|
5
|
+
/* Available as open-source under the MIT License */
|
|
6
|
+
/* */
|
|
7
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
8
|
+
#include "mip/HighsMipSolverData.h"
|
|
9
|
+
|
|
10
|
+
#include <random>
|
|
11
|
+
#include <sstream>
|
|
12
|
+
|
|
13
|
+
#include "../extern/pdqsort/pdqsort.h"
|
|
14
|
+
#include "lp_data/HighsModelUtils.h"
|
|
15
|
+
#include "mip/HighsPseudocost.h"
|
|
16
|
+
#include "mip/HighsRedcostFixing.h"
|
|
17
|
+
#include "mip/MipTimer.h"
|
|
18
|
+
#include "parallel/HighsParallel.h"
|
|
19
|
+
#include "presolve/HPresolve.h"
|
|
20
|
+
#include "util/HighsIntegers.h"
|
|
21
|
+
|
|
22
|
+
std::string HighsMipSolverData::solutionSourceToString(
|
|
23
|
+
const int solution_source, const bool code) const {
|
|
24
|
+
if (solution_source == kSolutionSourceNone) {
|
|
25
|
+
if (code) return " ";
|
|
26
|
+
return "None";
|
|
27
|
+
// } else if (solution_source == kSolutionSourceInitial) {
|
|
28
|
+
// if (code) return "0";
|
|
29
|
+
// return "Initial";
|
|
30
|
+
} else if (solution_source == kSolutionSourceBranching) {
|
|
31
|
+
if (code) return "B";
|
|
32
|
+
return "Branching";
|
|
33
|
+
} else if (solution_source == kSolutionSourceCentralRounding) {
|
|
34
|
+
if (code) return "C";
|
|
35
|
+
return "Central rounding";
|
|
36
|
+
} else if (solution_source == kSolutionSourceFeasibilityPump) {
|
|
37
|
+
if (code) return "F";
|
|
38
|
+
return "Feasibility pump";
|
|
39
|
+
} else if (solution_source == kSolutionSourceHeuristic) {
|
|
40
|
+
if (code) return "H";
|
|
41
|
+
return "Heuristic";
|
|
42
|
+
} else if (solution_source == kSolutionSourceShifting) {
|
|
43
|
+
if (code) return "I";
|
|
44
|
+
return "Shifting";
|
|
45
|
+
} else if (solution_source == kSolutionSourceFeasibilityJump) {
|
|
46
|
+
if (code) return "J";
|
|
47
|
+
return "Feasibility jump";
|
|
48
|
+
} else if (solution_source == kSolutionSourceSubMip) {
|
|
49
|
+
if (code) return "L";
|
|
50
|
+
return "Sub-MIP";
|
|
51
|
+
} else if (solution_source == kSolutionSourceEmptyMip) {
|
|
52
|
+
if (code) return "P";
|
|
53
|
+
return "Empty MIP";
|
|
54
|
+
} else if (solution_source == kSolutionSourceRandomizedRounding) {
|
|
55
|
+
if (code) return "R";
|
|
56
|
+
return "Randomized rounding";
|
|
57
|
+
} else if (solution_source == kSolutionSourceSolveLp) {
|
|
58
|
+
if (code) return "S";
|
|
59
|
+
return "Solve LP";
|
|
60
|
+
} else if (solution_source == kSolutionSourceEvaluateNode) {
|
|
61
|
+
if (code) return "T";
|
|
62
|
+
return "Evaluate node";
|
|
63
|
+
} else if (solution_source == kSolutionSourceUnbounded) {
|
|
64
|
+
if (code) return "U";
|
|
65
|
+
return "Unbounded";
|
|
66
|
+
} else if (solution_source == kSolutionSourceUserSolution) {
|
|
67
|
+
if (code) return "X";
|
|
68
|
+
return "User solution";
|
|
69
|
+
} else if (solution_source == kSolutionSourceHighsSolution) {
|
|
70
|
+
if (code) return "Y";
|
|
71
|
+
return "HiGHS solution";
|
|
72
|
+
} else if (solution_source == kSolutionSourceZiRound) {
|
|
73
|
+
if (code) return "Z";
|
|
74
|
+
return "ZI Round";
|
|
75
|
+
} else if (solution_source == kSolutionSourceTrivialZ) {
|
|
76
|
+
if (code) return "z";
|
|
77
|
+
return "Trivial zero";
|
|
78
|
+
} else if (solution_source == kSolutionSourceTrivialL) {
|
|
79
|
+
if (code) return "l";
|
|
80
|
+
return "Trivial lower";
|
|
81
|
+
} else if (solution_source == kSolutionSourceTrivialU) {
|
|
82
|
+
if (code) return "u";
|
|
83
|
+
return "Trivial upper";
|
|
84
|
+
} else if (solution_source == kSolutionSourceTrivialP) {
|
|
85
|
+
if (code) return "p";
|
|
86
|
+
return "Trivial point";
|
|
87
|
+
} else if (solution_source == kSolutionSourceCleanup) {
|
|
88
|
+
if (code) return " ";
|
|
89
|
+
return "";
|
|
90
|
+
} else {
|
|
91
|
+
printf("HighsMipSolverData::solutionSourceToString: Unknown source = %d\n",
|
|
92
|
+
solution_source);
|
|
93
|
+
assert(0 == 111);
|
|
94
|
+
if (code) return "*";
|
|
95
|
+
return "None";
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
bool HighsMipSolverData::checkSolution(
|
|
100
|
+
const std::vector<double>& solution) const {
|
|
101
|
+
for (HighsInt i = 0; i != mipsolver.numCol(); ++i) {
|
|
102
|
+
if (solution[i] < mipsolver.model_->col_lower_[i] - feastol) return false;
|
|
103
|
+
if (solution[i] > mipsolver.model_->col_upper_[i] + feastol) return false;
|
|
104
|
+
if (mipsolver.isColInteger(i) && fractionality(solution[i]) > feastol)
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
for (HighsInt i = 0; i != mipsolver.numRow(); ++i) {
|
|
109
|
+
double rowactivity = 0.0;
|
|
110
|
+
|
|
111
|
+
HighsInt start = ARstart_[i];
|
|
112
|
+
HighsInt end = ARstart_[i + 1];
|
|
113
|
+
|
|
114
|
+
for (HighsInt j = start; j != end; ++j)
|
|
115
|
+
rowactivity += solution[ARindex_[j]] * ARvalue_[j];
|
|
116
|
+
|
|
117
|
+
if (rowactivity > mipsolver.rowUpper(i) + feastol) return false;
|
|
118
|
+
if (rowactivity < mipsolver.rowLower(i) - feastol) return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
std::vector<std::tuple<HighsInt, HighsInt, double>>
|
|
125
|
+
HighsMipSolverData::getInfeasibleRows(
|
|
126
|
+
const std::vector<double>& solution) const {
|
|
127
|
+
std::vector<std::tuple<HighsInt, HighsInt, double>> infeasibleRows;
|
|
128
|
+
for (HighsInt i = 0; i != mipsolver.numRow(); ++i) {
|
|
129
|
+
HighsInt start = ARstart_[i];
|
|
130
|
+
HighsInt end = ARstart_[i + 1];
|
|
131
|
+
|
|
132
|
+
HighsCDouble row_activity_quad = 0.0;
|
|
133
|
+
for (HighsInt j = start; j != end; ++j)
|
|
134
|
+
row_activity_quad +=
|
|
135
|
+
static_cast<HighsCDouble>(solution[ARindex_[j]]) * ARvalue_[j];
|
|
136
|
+
|
|
137
|
+
double row_activity = static_cast<double>(row_activity_quad);
|
|
138
|
+
if (row_activity > mipsolver.rowUpper(i) + feastol) {
|
|
139
|
+
double difference = std::abs(row_activity - mipsolver.rowUpper(i));
|
|
140
|
+
infeasibleRows.push_back({i, +1, difference});
|
|
141
|
+
}
|
|
142
|
+
if (row_activity < mipsolver.rowLower(i) - feastol) {
|
|
143
|
+
double difference = std::abs(mipsolver.rowLower(i) - row_activity);
|
|
144
|
+
infeasibleRows.push_back({i, -1, difference});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return infeasibleRows;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
bool HighsMipSolverData::trySolution(const std::vector<double>& solution,
|
|
151
|
+
const int solution_source) {
|
|
152
|
+
if (int(solution.size()) != mipsolver.numCol()) return false;
|
|
153
|
+
|
|
154
|
+
HighsCDouble obj = 0;
|
|
155
|
+
|
|
156
|
+
for (HighsInt i = 0; i != mipsolver.numCol(); ++i) {
|
|
157
|
+
if (solution[i] < mipsolver.model_->col_lower_[i] - feastol) return false;
|
|
158
|
+
if (solution[i] > mipsolver.model_->col_upper_[i] + feastol) return false;
|
|
159
|
+
if (mipsolver.isColInteger(i) && fractionality(solution[i]) > feastol)
|
|
160
|
+
return false;
|
|
161
|
+
|
|
162
|
+
obj += mipsolver.colCost(i) * solution[i];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
for (HighsInt i = 0; i != mipsolver.numRow(); ++i) {
|
|
166
|
+
double rowactivity = 0.0;
|
|
167
|
+
|
|
168
|
+
HighsInt start = ARstart_[i];
|
|
169
|
+
HighsInt end = ARstart_[i + 1];
|
|
170
|
+
|
|
171
|
+
for (HighsInt j = start; j != end; ++j)
|
|
172
|
+
rowactivity += solution[ARindex_[j]] * ARvalue_[j];
|
|
173
|
+
|
|
174
|
+
if (rowactivity > mipsolver.rowUpper(i) + feastol) return false;
|
|
175
|
+
if (rowactivity < mipsolver.rowLower(i) - feastol) return false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return addIncumbent(solution, double(obj), solution_source);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
bool HighsMipSolverData::solutionRowFeasible(
|
|
182
|
+
const std::vector<double>& solution) const {
|
|
183
|
+
for (HighsInt i = 0; i != mipsolver.numRow(); ++i) {
|
|
184
|
+
HighsCDouble c_double_rowactivity = HighsCDouble(0.0);
|
|
185
|
+
|
|
186
|
+
HighsInt start = ARstart_[i];
|
|
187
|
+
HighsInt end = ARstart_[i + 1];
|
|
188
|
+
|
|
189
|
+
for (HighsInt j = start; j != end; ++j)
|
|
190
|
+
c_double_rowactivity += HighsCDouble(solution[ARindex_[j]] * ARvalue_[j]);
|
|
191
|
+
|
|
192
|
+
double rowactivity = double(c_double_rowactivity);
|
|
193
|
+
if (rowactivity > mipsolver.rowUpper(i) + feastol) return false;
|
|
194
|
+
if (rowactivity < mipsolver.rowLower(i) - feastol) return false;
|
|
195
|
+
}
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
HighsModelStatus HighsMipSolverData::trivialHeuristics() {
|
|
200
|
+
// printf("\nHighsMipSolverData::trivialHeuristics() Number of continuous
|
|
201
|
+
// columns is %d\n",
|
|
202
|
+
// int(continuous_cols.size()));
|
|
203
|
+
if (continuous_cols.size() > 0) return HighsModelStatus::kNotset;
|
|
204
|
+
const HighsInt num_try_heuristic = 4;
|
|
205
|
+
const std::vector<int> heuristic_source = {
|
|
206
|
+
kSolutionSourceTrivialZ, kSolutionSourceTrivialL, kSolutionSourceTrivialU,
|
|
207
|
+
kSolutionSourceTrivialP};
|
|
208
|
+
|
|
209
|
+
std::vector<double> col_lower = mipsolver.model_->col_lower_;
|
|
210
|
+
std::vector<double> col_upper = mipsolver.model_->col_upper_;
|
|
211
|
+
const std::vector<double>& row_lower = mipsolver.model_->row_lower_;
|
|
212
|
+
const std::vector<double>& row_upper = mipsolver.model_->row_upper_;
|
|
213
|
+
const HighsSparseMatrix& matrix = mipsolver.model_->a_matrix_;
|
|
214
|
+
// Determine the following properties, according to which some
|
|
215
|
+
// trivial heuristics are duplicated or fail immediately
|
|
216
|
+
bool all_integer_lower_non_positive = true;
|
|
217
|
+
bool all_integer_lower_zero = true;
|
|
218
|
+
bool all_integer_lower_finite = true;
|
|
219
|
+
bool all_integer_upper_finite = true;
|
|
220
|
+
for (HighsInt integer_col = 0; integer_col < numintegercols; integer_col++) {
|
|
221
|
+
HighsInt iCol = integer_cols[integer_col];
|
|
222
|
+
// Round bounds in to nearest integer
|
|
223
|
+
col_lower[iCol] = std::ceil(col_lower[iCol]);
|
|
224
|
+
col_upper[iCol] = std::floor(col_upper[iCol]);
|
|
225
|
+
const bool legal_bounds =
|
|
226
|
+
col_lower[iCol] <= col_upper[iCol] && col_lower[iCol] < kHighsInf &&
|
|
227
|
+
col_upper[iCol] > -kHighsInf && !std::isnan(col_lower[iCol]) &&
|
|
228
|
+
!std::isnan(col_upper[iCol]);
|
|
229
|
+
if (!legal_bounds) {
|
|
230
|
+
assert(legal_bounds);
|
|
231
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
232
|
+
"HighsMipSolverData::trivialHeuristics() has detected "
|
|
233
|
+
"infeasible/illegal bounds [%g, %g] for column %d: MIP is "
|
|
234
|
+
"infeasible\n",
|
|
235
|
+
col_lower[iCol], col_upper[iCol], int(iCol));
|
|
236
|
+
return HighsModelStatus::kInfeasible;
|
|
237
|
+
}
|
|
238
|
+
// If bounds are inconsistent then MIP is infeasible
|
|
239
|
+
if (col_lower[iCol] > col_upper[iCol]) return HighsModelStatus::kInfeasible;
|
|
240
|
+
|
|
241
|
+
if (col_lower[iCol] > 0) all_integer_lower_non_positive = false;
|
|
242
|
+
if (col_lower[iCol]) all_integer_lower_zero = false;
|
|
243
|
+
if (col_lower[iCol] <= -kHighsInf) all_integer_lower_finite = false;
|
|
244
|
+
if (col_upper[iCol] >= kHighsInf) all_integer_upper_finite = false;
|
|
245
|
+
// Only continue if one of the properties still holds
|
|
246
|
+
if (!(all_integer_lower_non_positive || all_integer_lower_zero ||
|
|
247
|
+
all_integer_upper_finite))
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
const bool all_integer_boxed =
|
|
251
|
+
all_integer_lower_finite && all_integer_upper_finite;
|
|
252
|
+
// printf(
|
|
253
|
+
// "Trying trivial heuristics\n"
|
|
254
|
+
// " all_integer_lower_non_positive = %d\n"
|
|
255
|
+
// " all_integer_lower_zero = %d\n"
|
|
256
|
+
// " all_integer_upper_finite = %d\n"
|
|
257
|
+
// " all_integer_boxed = %d\n",
|
|
258
|
+
// all_integer_lower_non_positive, all_integer_lower_zero,
|
|
259
|
+
// all_integer_upper_finite, all_integer_boxed);
|
|
260
|
+
const double feasibility_tolerance =
|
|
261
|
+
mipsolver.options_mip_->mip_feasibility_tolerance;
|
|
262
|
+
// Loop through the trivial heuristics
|
|
263
|
+
std::vector<double> solution(mipsolver.numCol());
|
|
264
|
+
for (HighsInt try_heuristic = 0; try_heuristic < num_try_heuristic;
|
|
265
|
+
try_heuristic++) {
|
|
266
|
+
if (try_heuristic == 0) {
|
|
267
|
+
// First heuristic is to see whether all-zero for integer
|
|
268
|
+
// variables is feasible
|
|
269
|
+
//
|
|
270
|
+
// If there is a positive lower bound then the heuristic fails
|
|
271
|
+
if (!all_integer_lower_non_positive) continue;
|
|
272
|
+
// Determine whether a zero row activity is feasible
|
|
273
|
+
bool heuristic_failed = false;
|
|
274
|
+
for (HighsInt iRow = 0; iRow < mipsolver.numRow(); iRow++) {
|
|
275
|
+
if (row_lower[iRow] > feasibility_tolerance ||
|
|
276
|
+
row_upper[iRow] < -feasibility_tolerance) {
|
|
277
|
+
heuristic_failed = true;
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (heuristic_failed) continue;
|
|
282
|
+
solution.assign(mipsolver.numCol(), 0);
|
|
283
|
+
} else if (try_heuristic == 1) {
|
|
284
|
+
// Second heuristic is to see whether all-lower for integer
|
|
285
|
+
// variables (if distinct from all-zero) is feasible
|
|
286
|
+
if (all_integer_lower_zero) continue;
|
|
287
|
+
// Trivially feasible for columns
|
|
288
|
+
if (!solutionRowFeasible(col_lower)) continue;
|
|
289
|
+
solution = col_lower;
|
|
290
|
+
} else if (try_heuristic == 2) {
|
|
291
|
+
// Third heuristic is to see whether all-upper for integer
|
|
292
|
+
// variables is feasible
|
|
293
|
+
//
|
|
294
|
+
// If there is an infinite upper bound then the heuristic fails
|
|
295
|
+
if (!all_integer_upper_finite) continue;
|
|
296
|
+
// Trivially feasible for columns
|
|
297
|
+
if (!solutionRowFeasible(col_upper)) continue;
|
|
298
|
+
solution = col_upper;
|
|
299
|
+
} else if (try_heuristic == 3) {
|
|
300
|
+
// Fourth heuristic is to see whether the "lock point" is feasible
|
|
301
|
+
if (!all_integer_boxed) continue;
|
|
302
|
+
for (HighsInt integer_col = 0; integer_col < numintegercols;
|
|
303
|
+
integer_col++) {
|
|
304
|
+
HighsInt iCol = integer_cols[integer_col];
|
|
305
|
+
HighsInt num_positive_values = 0;
|
|
306
|
+
HighsInt num_negative_values = 0;
|
|
307
|
+
for (HighsInt iEl = matrix.start_[iCol]; iEl < matrix.start_[iCol + 1];
|
|
308
|
+
iEl++) {
|
|
309
|
+
if (matrix.value_[iEl] > 0)
|
|
310
|
+
num_positive_values++;
|
|
311
|
+
else
|
|
312
|
+
num_negative_values++;
|
|
313
|
+
}
|
|
314
|
+
solution[iCol] = num_positive_values > num_negative_values
|
|
315
|
+
? col_lower[iCol]
|
|
316
|
+
: col_upper[iCol];
|
|
317
|
+
}
|
|
318
|
+
// Trivially feasible for columns
|
|
319
|
+
if (!solutionRowFeasible(solution)) continue;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
HighsCDouble cdouble_obj = 0.0;
|
|
323
|
+
for (HighsInt iCol = 0; iCol < mipsolver.numCol(); iCol++)
|
|
324
|
+
cdouble_obj += mipsolver.colCost(iCol) * solution[iCol];
|
|
325
|
+
double obj = double(cdouble_obj);
|
|
326
|
+
const double save_upper_bound = upper_bound;
|
|
327
|
+
const bool new_incumbent =
|
|
328
|
+
addIncumbent(solution, obj, heuristic_source[try_heuristic]);
|
|
329
|
+
const bool lc_report = false;
|
|
330
|
+
if (lc_report) {
|
|
331
|
+
printf("Trivial heuristic %d has succeeded: objective = %g",
|
|
332
|
+
int(try_heuristic), obj);
|
|
333
|
+
if (new_incumbent) {
|
|
334
|
+
printf("; upper bound from %g to %g\n", save_upper_bound, upper_bound);
|
|
335
|
+
} else {
|
|
336
|
+
printf("\n");
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return HighsModelStatus::kNotset;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
void HighsMipSolverData::startAnalyticCenterComputation(
|
|
344
|
+
const highs::parallel::TaskGroup& taskGroup) {
|
|
345
|
+
taskGroup.spawn([&]() {
|
|
346
|
+
// first check if the analytic centre computation should be cancelled, e.g.
|
|
347
|
+
// due to early return in the root node evaluation
|
|
348
|
+
Highs ipm;
|
|
349
|
+
ipm.setOptionValue("output_flag", false);
|
|
350
|
+
const std::vector<double>& sol = ipm.getSolution().col_value;
|
|
351
|
+
// Don't use presolve - because this can lead to postsolve putting
|
|
352
|
+
// integer variables onto bounds. This is not just a "less good"
|
|
353
|
+
// AC. It can have implications leading to erroneous fixing of
|
|
354
|
+
// variables and a suboptimal solution declared as optimal.
|
|
355
|
+
ipm.setOptionValue("presolve", kHighsOffString);
|
|
356
|
+
// Determine the solver
|
|
357
|
+
const std::string mip_ipm_solver = mipsolver.options_mip_->mip_ipm_solver;
|
|
358
|
+
// Currently use IPX by default and take action on failure here if
|
|
359
|
+
// using HiPO.
|
|
360
|
+
bool use_hipo =
|
|
361
|
+
/*
|
|
362
|
+
#ifdef HIPO
|
|
363
|
+
// Later use HiPO by default
|
|
364
|
+
mip_ipm_solver == kHighsChooseString ||
|
|
365
|
+
#endif
|
|
366
|
+
*/
|
|
367
|
+
mip_ipm_solver == kHipoString;
|
|
368
|
+
// Later still, pass mip_ipm_solver and take action on failure in
|
|
369
|
+
// solveLp
|
|
370
|
+
#ifndef HIPO
|
|
371
|
+
// Shouldn't be possible to choose HiPO if it's not in the build
|
|
372
|
+
assert(!use_hipo);
|
|
373
|
+
use_hipo = false;
|
|
374
|
+
#endif
|
|
375
|
+
const std::string ipm_solver = use_hipo ? kHipoString : kIpxString;
|
|
376
|
+
ipm.setOptionValue("solver", ipm_solver);
|
|
377
|
+
ipm.setOptionValue("ipm_iteration_limit", 200);
|
|
378
|
+
ipm.setOptionValue("run_crossover", kHighsOffString);
|
|
379
|
+
ipm.setOptionValue("run_centring", true);
|
|
380
|
+
HighsLp lpmodel(*mipsolver.model_);
|
|
381
|
+
lpmodel.col_cost_.assign(lpmodel.num_col_, 0.0);
|
|
382
|
+
lpmodel.integrality_.clear();
|
|
383
|
+
ipm.passModel(std::move(lpmodel));
|
|
384
|
+
const bool dump_ipm_lp = false;
|
|
385
|
+
if (dump_ipm_lp && !mipsolver.submip) {
|
|
386
|
+
const std::string file_name = mipsolver.model_->model_name_ + "_ac.mps";
|
|
387
|
+
printf(
|
|
388
|
+
"HighsMipSolverData::startAnalyticCenterComputation: Calling "
|
|
389
|
+
"ipm.writeModel(%s)\n",
|
|
390
|
+
file_name.c_str());
|
|
391
|
+
ipm.writeModel(file_name);
|
|
392
|
+
fflush(stdout);
|
|
393
|
+
exit(1);
|
|
394
|
+
}
|
|
395
|
+
const bool ipm_logging = false;
|
|
396
|
+
if (ipm_logging) {
|
|
397
|
+
bool output_flag;
|
|
398
|
+
ipm.getOptionValue("output_flag", output_flag);
|
|
399
|
+
assert(output_flag == false);
|
|
400
|
+
(void)output_flag;
|
|
401
|
+
ipm.setOptionValue("output_flag", !mipsolver.submip);
|
|
402
|
+
}
|
|
403
|
+
ipm.optimizeLp();
|
|
404
|
+
if (ipm_logging) ipm.setOptionValue("output_flag", false);
|
|
405
|
+
if (use_hipo && mip_ipm_solver == kHighsChooseString &&
|
|
406
|
+
HighsInt(sol.size()) != mipsolver.numCol()) {
|
|
407
|
+
printf(
|
|
408
|
+
"In HighsMipSolverData::startAnalyticCenterComputation HiPO has "
|
|
409
|
+
"failed to get a solution: status = %s Try IPX\n",
|
|
410
|
+
ipm.modelStatusToString(ipm.getModelStatus()).c_str());
|
|
411
|
+
// HiPO has failed to get a solution, so try IPX
|
|
412
|
+
ipm.setOptionValue("solver", kIpxString);
|
|
413
|
+
ipm.optimizeLp();
|
|
414
|
+
}
|
|
415
|
+
if (!mipsolver.submip) {
|
|
416
|
+
const HighsSubSolverCallTime& sub_solver_call_time =
|
|
417
|
+
ipm.getSubSolverCallTime();
|
|
418
|
+
const bool analytic_centre = true;
|
|
419
|
+
mipsolver.analysis_.addSubSolverCallTime(sub_solver_call_time,
|
|
420
|
+
analytic_centre);
|
|
421
|
+
// Go through sub_solver_call_time to update any MIP clocks
|
|
422
|
+
const bool valid_basis = false;
|
|
423
|
+
const bool use_presolve = false;
|
|
424
|
+
mipsolver.analysis_.mipTimerUpdate(sub_solver_call_time, valid_basis,
|
|
425
|
+
use_presolve, analytic_centre);
|
|
426
|
+
}
|
|
427
|
+
if (HighsInt(sol.size()) != mipsolver.numCol()) return;
|
|
428
|
+
analyticCenterStatus = ipm.getModelStatus();
|
|
429
|
+
analyticCenter = sol;
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
void HighsMipSolverData::finishAnalyticCenterComputation(
|
|
434
|
+
const highs::parallel::TaskGroup& taskGroup) {
|
|
435
|
+
if (mipsolver.analysis_.analyse_mip_time) {
|
|
436
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
437
|
+
"MIP-Timing: %11.2g - starting analytic centre synch\n",
|
|
438
|
+
mipsolver.analysis_.mipTimerRead());
|
|
439
|
+
fflush(stdout);
|
|
440
|
+
}
|
|
441
|
+
taskGroup.sync();
|
|
442
|
+
if (mipsolver.analysis_.analyse_mip_time) {
|
|
443
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
444
|
+
"MIP-Timing: %11.2g - completed analytic centre synch\n",
|
|
445
|
+
mipsolver.analysis_.mipTimerRead());
|
|
446
|
+
fflush(stdout);
|
|
447
|
+
}
|
|
448
|
+
analyticCenterComputed = true;
|
|
449
|
+
if (analyticCenterStatus == HighsModelStatus::kOptimal) {
|
|
450
|
+
HighsInt nfixed = 0;
|
|
451
|
+
HighsInt nintfixed = 0;
|
|
452
|
+
for (HighsInt i = 0; i != mipsolver.numCol(); ++i) {
|
|
453
|
+
double boundRange = mipsolver.mipdata_->domain.col_upper_[i] -
|
|
454
|
+
mipsolver.mipdata_->domain.col_lower_[i];
|
|
455
|
+
if (boundRange == 0.0) continue;
|
|
456
|
+
|
|
457
|
+
double tolerance =
|
|
458
|
+
mipsolver.mipdata_->feastol * std::min(boundRange, 1.0);
|
|
459
|
+
|
|
460
|
+
if (analyticCenter[i] <= mipsolver.model_->col_lower_[i] + tolerance) {
|
|
461
|
+
mipsolver.mipdata_->domain.changeBound(
|
|
462
|
+
HighsBoundType::kUpper, i, mipsolver.model_->col_lower_[i],
|
|
463
|
+
HighsDomain::Reason::unspecified());
|
|
464
|
+
if (mipsolver.mipdata_->domain.infeasible()) return;
|
|
465
|
+
++nfixed;
|
|
466
|
+
if (mipsolver.isColInteger(i)) ++nintfixed;
|
|
467
|
+
} else if (analyticCenter[i] >=
|
|
468
|
+
mipsolver.model_->col_upper_[i] - tolerance) {
|
|
469
|
+
mipsolver.mipdata_->domain.changeBound(
|
|
470
|
+
HighsBoundType::kLower, i, mipsolver.model_->col_upper_[i],
|
|
471
|
+
HighsDomain::Reason::unspecified());
|
|
472
|
+
if (mipsolver.mipdata_->domain.infeasible()) return;
|
|
473
|
+
++nfixed;
|
|
474
|
+
if (mipsolver.isColInteger(i)) ++nintfixed;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
if (nfixed > 0)
|
|
478
|
+
highsLogDev(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
479
|
+
"Fixing %d columns (%d integers) sitting at bound at "
|
|
480
|
+
"analytic center\n",
|
|
481
|
+
int(nfixed), int(nintfixed));
|
|
482
|
+
mipsolver.mipdata_->domain.propagate();
|
|
483
|
+
if (mipsolver.mipdata_->domain.infeasible()) return;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
void HighsMipSolverData::startSymmetryDetection(
|
|
488
|
+
const highs::parallel::TaskGroup& taskGroup,
|
|
489
|
+
std::unique_ptr<SymmetryDetectionData>& symData) {
|
|
490
|
+
symData = std::unique_ptr<SymmetryDetectionData>(new SymmetryDetectionData());
|
|
491
|
+
symData->symDetection.loadModelAsGraph(
|
|
492
|
+
mipsolver.mipdata_->presolvedModel,
|
|
493
|
+
mipsolver.options_mip_->small_matrix_value);
|
|
494
|
+
detectSymmetries = symData->symDetection.initializeDetection();
|
|
495
|
+
|
|
496
|
+
if (detectSymmetries) {
|
|
497
|
+
taskGroup.spawn([&]() {
|
|
498
|
+
double startTime = mipsolver.timer_.getWallTime();
|
|
499
|
+
symData->symDetection.run(symData->symmetries);
|
|
500
|
+
symData->detectionTime = mipsolver.timer_.getWallTime() - startTime;
|
|
501
|
+
});
|
|
502
|
+
} else
|
|
503
|
+
symData.reset();
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
void HighsMipSolverData::finishSymmetryDetection(
|
|
507
|
+
const highs::parallel::TaskGroup& taskGroup,
|
|
508
|
+
std::unique_ptr<SymmetryDetectionData>& symData) {
|
|
509
|
+
taskGroup.sync();
|
|
510
|
+
|
|
511
|
+
symmetries = std::move(symData->symmetries);
|
|
512
|
+
std::string symmetry_time =
|
|
513
|
+
mipsolver.options_mip_->timeless_log
|
|
514
|
+
? ""
|
|
515
|
+
: highsFormatToString(" %.1fs", symData->detectionTime);
|
|
516
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
517
|
+
"\nSymmetry detection completed in%s\n", symmetry_time.c_str());
|
|
518
|
+
|
|
519
|
+
if (symmetries.numGenerators == 0) {
|
|
520
|
+
detectSymmetries = false;
|
|
521
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
522
|
+
"No symmetry present\n\n");
|
|
523
|
+
} else if (symmetries.orbitopes.size() == 0) {
|
|
524
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
525
|
+
"Found %d generator(s)\n\n", int(symmetries.numGenerators));
|
|
526
|
+
|
|
527
|
+
} else {
|
|
528
|
+
if (symmetries.numPerms != 0) {
|
|
529
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
530
|
+
"Found %d generator(s) and %d full orbitope(s) acting on %d "
|
|
531
|
+
"columns\n\n",
|
|
532
|
+
int(symmetries.numPerms), int(symmetries.orbitopes.size()),
|
|
533
|
+
int(symmetries.columnToOrbitope.size()));
|
|
534
|
+
} else {
|
|
535
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
536
|
+
"Found %d full orbitope(s) acting on %d columns\n\n",
|
|
537
|
+
int(symmetries.orbitopes.size()),
|
|
538
|
+
int(symmetries.columnToOrbitope.size()));
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
symData.reset();
|
|
542
|
+
|
|
543
|
+
for (HighsOrbitopeMatrix& orbitope : symmetries.orbitopes)
|
|
544
|
+
orbitope.determineOrbitopeType(cliquetable);
|
|
545
|
+
|
|
546
|
+
if (symmetries.numPerms != 0)
|
|
547
|
+
globalOrbits = symmetries.computeStabilizerOrbits(domain);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
double HighsMipSolverData::limitsToGap(const double use_lower_bound,
|
|
551
|
+
const double use_upper_bound, double& lb,
|
|
552
|
+
double& ub) const {
|
|
553
|
+
double offset = mipsolver.model_->offset_;
|
|
554
|
+
lb = use_lower_bound + offset;
|
|
555
|
+
if (std::abs(lb) <= epsilon) lb = 0;
|
|
556
|
+
ub = kHighsInf;
|
|
557
|
+
double gap = kHighsInf;
|
|
558
|
+
if (use_upper_bound != kHighsInf) {
|
|
559
|
+
ub = use_upper_bound + offset;
|
|
560
|
+
if (std::fabs(ub) <= epsilon) ub = 0;
|
|
561
|
+
lb = std::min(ub, lb);
|
|
562
|
+
if (ub == 0.0)
|
|
563
|
+
gap = lb == 0.0 ? 0.0 : kHighsInf;
|
|
564
|
+
else
|
|
565
|
+
gap = (ub - lb) / fabs(ub);
|
|
566
|
+
}
|
|
567
|
+
return gap;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
double HighsMipSolverData::computeNewUpperLimit(double ub, double mip_abs_gap,
|
|
571
|
+
double mip_rel_gap) const {
|
|
572
|
+
double new_upper_limit;
|
|
573
|
+
if (objectiveFunction.isIntegral()) {
|
|
574
|
+
new_upper_limit =
|
|
575
|
+
(std::floor(objectiveFunction.integralScale() * ub - 0.5) /
|
|
576
|
+
objectiveFunction.integralScale());
|
|
577
|
+
|
|
578
|
+
if (mip_rel_gap != 0.0)
|
|
579
|
+
new_upper_limit = std::min(
|
|
580
|
+
new_upper_limit,
|
|
581
|
+
ub - std::ceil(mip_rel_gap * fabs(ub + mipsolver.model_->offset_) *
|
|
582
|
+
objectiveFunction.integralScale() -
|
|
583
|
+
mipsolver.mipdata_->epsilon) /
|
|
584
|
+
objectiveFunction.integralScale());
|
|
585
|
+
|
|
586
|
+
if (mip_abs_gap != 0.0)
|
|
587
|
+
new_upper_limit = std::min(
|
|
588
|
+
new_upper_limit,
|
|
589
|
+
ub - std::ceil(mip_abs_gap * objectiveFunction.integralScale() -
|
|
590
|
+
mipsolver.mipdata_->epsilon) /
|
|
591
|
+
objectiveFunction.integralScale());
|
|
592
|
+
|
|
593
|
+
// add feasibility tolerance so that the next best integer feasible solution
|
|
594
|
+
// is definitely included in the remaining search
|
|
595
|
+
new_upper_limit += feastol;
|
|
596
|
+
} else {
|
|
597
|
+
new_upper_limit = std::min(ub - feastol, std::nextafter(ub, -kHighsInf));
|
|
598
|
+
|
|
599
|
+
if (mip_rel_gap != 0.0)
|
|
600
|
+
new_upper_limit =
|
|
601
|
+
std::min(new_upper_limit,
|
|
602
|
+
ub - mip_rel_gap * fabs(ub + mipsolver.model_->offset_));
|
|
603
|
+
|
|
604
|
+
if (mip_abs_gap != 0.0)
|
|
605
|
+
new_upper_limit = std::min(new_upper_limit, ub - mip_abs_gap);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
return new_upper_limit;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
bool HighsMipSolverData::moreHeuristicsAllowed() const {
|
|
612
|
+
// in the beginning of the search and in sub-MIP heuristics we only allow
|
|
613
|
+
// what is proportionally for the currently spent effort plus an initial
|
|
614
|
+
// offset. This is because in a sub-MIP we usually do a truncated search and
|
|
615
|
+
// therefore should not extrapolate the time we spent for heuristics as in
|
|
616
|
+
// the other case. Moreover, since we estimate the total effort for
|
|
617
|
+
// exploring the tree based on the weight of the already pruned nodes, the
|
|
618
|
+
// estimated effort the is not expected to be a good prediction in the
|
|
619
|
+
// beginning.
|
|
620
|
+
if (mipsolver.submip) {
|
|
621
|
+
return heuristic_lp_iterations < total_lp_iterations * heuristic_effort;
|
|
622
|
+
} else if (pruned_treeweight < 1e-3 &&
|
|
623
|
+
num_leaves - num_leaves_before_run < 10 &&
|
|
624
|
+
num_nodes - num_nodes_before_run < 1000) {
|
|
625
|
+
// in the main MIP solver allow an initial offset of 10000 heuristic LP
|
|
626
|
+
// iterations
|
|
627
|
+
if (heuristic_lp_iterations <
|
|
628
|
+
total_lp_iterations * heuristic_effort + 10000)
|
|
629
|
+
return true;
|
|
630
|
+
} else if (heuristic_lp_iterations <
|
|
631
|
+
100000 + ((total_lp_iterations - heuristic_lp_iterations -
|
|
632
|
+
sb_lp_iterations) >>
|
|
633
|
+
1)) {
|
|
634
|
+
// compute the node LP iterations in the current run as only those should be
|
|
635
|
+
// used when estimating the total required LP iterations to complete the
|
|
636
|
+
// search
|
|
637
|
+
int64_t heur_iters_curr_run =
|
|
638
|
+
heuristic_lp_iterations - heuristic_lp_iterations_before_run;
|
|
639
|
+
int64_t sb_iters_curr_run = sb_lp_iterations - sb_lp_iterations_before_run;
|
|
640
|
+
int64_t node_iters_curr_run = total_lp_iterations -
|
|
641
|
+
total_lp_iterations_before_run -
|
|
642
|
+
heur_iters_curr_run - sb_iters_curr_run;
|
|
643
|
+
// now estimate the total fraction of LP iterations that we have spent on
|
|
644
|
+
// heuristics by assuming the node iterations of the current run will
|
|
645
|
+
// grow proportional to the pruned weight of the current tree and the
|
|
646
|
+
// iterations spent for anything else are just added as an offset
|
|
647
|
+
double total_heuristic_effort_estim =
|
|
648
|
+
heuristic_lp_iterations /
|
|
649
|
+
((total_lp_iterations - node_iters_curr_run) +
|
|
650
|
+
node_iters_curr_run / std::max(0.01, double(pruned_treeweight)));
|
|
651
|
+
// since heuristics help most in the beginning of the search, we want to
|
|
652
|
+
// spent the time we have for heuristics in the first 80% of the tree
|
|
653
|
+
// exploration. Additionally we want to spent the proportional effort
|
|
654
|
+
// of heuristics that is allowed in the first 30% of tree exploration as
|
|
655
|
+
// fast as possible, which is why we have the max(0.3/0.8,...).
|
|
656
|
+
// Hence, in the first 30% of the tree exploration we allow to spent all
|
|
657
|
+
// effort available for heuristics in that part of the search as early as
|
|
658
|
+
// possible, whereas after that we allow the part that is proportionally
|
|
659
|
+
// adequate when we want to spent all available time in the first 80%.
|
|
660
|
+
if (total_heuristic_effort_estim <
|
|
661
|
+
std::max(0.3 / 0.8, std::min(double(pruned_treeweight), 0.8) / 0.8) *
|
|
662
|
+
heuristic_effort) {
|
|
663
|
+
// printf(
|
|
664
|
+
// "heuristic lp iterations: %ld, total_lp_iterations: %ld, "
|
|
665
|
+
// "total_heur_effort_estim = %.3f%%\n",
|
|
666
|
+
// heuristic_lp_iterations, total_lp_iterations,
|
|
667
|
+
// total_heuristic_effort_estim);
|
|
668
|
+
return true;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
return false;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
void HighsMipSolverData::removeFixedIndices() {
|
|
676
|
+
integral_cols.erase(
|
|
677
|
+
std::remove_if(integral_cols.begin(), integral_cols.end(),
|
|
678
|
+
[&](HighsInt col) { return domain.isFixed(col); }),
|
|
679
|
+
integral_cols.end());
|
|
680
|
+
integer_cols.erase(
|
|
681
|
+
std::remove_if(integer_cols.begin(), integer_cols.end(),
|
|
682
|
+
[&](HighsInt col) { return domain.isFixed(col); }),
|
|
683
|
+
integer_cols.end());
|
|
684
|
+
implint_cols.erase(
|
|
685
|
+
std::remove_if(implint_cols.begin(), implint_cols.end(),
|
|
686
|
+
[&](HighsInt col) { return domain.isFixed(col); }),
|
|
687
|
+
implint_cols.end());
|
|
688
|
+
continuous_cols.erase(
|
|
689
|
+
std::remove_if(continuous_cols.begin(), continuous_cols.end(),
|
|
690
|
+
[&](HighsInt col) { return domain.isFixed(col); }),
|
|
691
|
+
continuous_cols.end());
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
void HighsMipSolverData::init() {
|
|
695
|
+
postSolveStack.initializeIndexMaps(mipsolver.numRow(), mipsolver.numCol());
|
|
696
|
+
mipsolver.orig_model_ = mipsolver.model_;
|
|
697
|
+
feastol = mipsolver.options_mip_->mip_feasibility_tolerance;
|
|
698
|
+
epsilon = mipsolver.options_mip_->small_matrix_value;
|
|
699
|
+
if (mipsolver.clqtableinit)
|
|
700
|
+
cliquetable.buildFrom(mipsolver.orig_model_, *mipsolver.clqtableinit);
|
|
701
|
+
cliquetable.setMinEntriesForParallelism(
|
|
702
|
+
highs::parallel::num_threads() > 1
|
|
703
|
+
? mipsolver.options_mip_->mip_min_cliquetable_entries_for_parallelism
|
|
704
|
+
: kHighsIInf);
|
|
705
|
+
if (mipsolver.implicinit) implications.buildFrom(*mipsolver.implicinit);
|
|
706
|
+
heuristic_effort = mipsolver.options_mip_->mip_heuristic_effort;
|
|
707
|
+
detectSymmetries = mipsolver.options_mip_->mip_detect_symmetry;
|
|
708
|
+
|
|
709
|
+
firstlpsolobj = -kHighsInf;
|
|
710
|
+
rootlpsolobj = -kHighsInf;
|
|
711
|
+
analyticCenterComputed = false;
|
|
712
|
+
analyticCenterStatus = HighsModelStatus::kNotset;
|
|
713
|
+
maxTreeSizeLog2 = 0;
|
|
714
|
+
numRestarts = 0;
|
|
715
|
+
numRestartsRoot = 0;
|
|
716
|
+
numImprovingSols = 0;
|
|
717
|
+
pruned_treeweight = 0;
|
|
718
|
+
avgrootlpiters = 0;
|
|
719
|
+
num_nodes = 0;
|
|
720
|
+
num_nodes_before_run = 0;
|
|
721
|
+
num_leaves = 0;
|
|
722
|
+
num_leaves_before_run = 0;
|
|
723
|
+
total_repair_lp = 0;
|
|
724
|
+
total_repair_lp_feasible = 0;
|
|
725
|
+
total_repair_lp_iterations = 0;
|
|
726
|
+
total_lp_iterations = 0;
|
|
727
|
+
heuristic_lp_iterations = 0;
|
|
728
|
+
sepa_lp_iterations = 0;
|
|
729
|
+
sb_lp_iterations = 0;
|
|
730
|
+
total_lp_iterations_before_run = 0;
|
|
731
|
+
heuristic_lp_iterations_before_run = 0;
|
|
732
|
+
sepa_lp_iterations_before_run = 0;
|
|
733
|
+
sb_lp_iterations_before_run = 0;
|
|
734
|
+
num_disp_lines = 0;
|
|
735
|
+
numCliqueEntriesAfterPresolve = 0;
|
|
736
|
+
numCliqueEntriesAfterFirstPresolve = 0;
|
|
737
|
+
cliquesExtracted = false;
|
|
738
|
+
rowMatrixSet = false;
|
|
739
|
+
lower_bound = -kHighsInf;
|
|
740
|
+
upper_bound = kHighsInf;
|
|
741
|
+
upper_limit = mipsolver.options_mip_->objective_bound;
|
|
742
|
+
optimality_limit = mipsolver.options_mip_->objective_bound;
|
|
743
|
+
primal_dual_integral.initialise();
|
|
744
|
+
|
|
745
|
+
if (mipsolver.options_mip_->mip_report_level == 0)
|
|
746
|
+
dispfreq = 0;
|
|
747
|
+
else if (mipsolver.options_mip_->mip_report_level == 1)
|
|
748
|
+
dispfreq = 2000;
|
|
749
|
+
else
|
|
750
|
+
dispfreq = 100;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
void HighsMipSolverData::runMipPresolve(
|
|
754
|
+
const HighsInt presolve_reduction_limit) {
|
|
755
|
+
mipsolver.timer_.start(mipsolver.timer_.presolve_clock);
|
|
756
|
+
presolve::HPresolve presolve;
|
|
757
|
+
if (!presolve.okSetInput(mipsolver, presolve_reduction_limit)) {
|
|
758
|
+
mipsolver.modelstatus_ = HighsModelStatus::kMemoryLimit;
|
|
759
|
+
presolve_status = HighsPresolveStatus::kOutOfMemory;
|
|
760
|
+
} else {
|
|
761
|
+
mipsolver.modelstatus_ = presolve.run(postSolveStack);
|
|
762
|
+
presolve_status = presolve.getPresolveStatus();
|
|
763
|
+
}
|
|
764
|
+
mipsolver.timer_.stop(mipsolver.timer_.presolve_clock);
|
|
765
|
+
|
|
766
|
+
// Report the final presolve reductions unless this is a restart
|
|
767
|
+
if (mipsolver.options_mip_->presolve != kHighsOffString && numRestarts == 0)
|
|
768
|
+
reportPresolveReductions(mipsolver.options_mip_->log_options,
|
|
769
|
+
presolve_status, *mipsolver.orig_model_,
|
|
770
|
+
*mipsolver.model_);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
void HighsMipSolverData::runSetup() {
|
|
774
|
+
const HighsLp& model = *mipsolver.model_;
|
|
775
|
+
|
|
776
|
+
// Indicate that the first LP has not been solved
|
|
777
|
+
this->lp.setSolvedFirstLp(false);
|
|
778
|
+
|
|
779
|
+
last_disptime = -kHighsInf;
|
|
780
|
+
disptime = 0;
|
|
781
|
+
|
|
782
|
+
// Transform the reference of the objective limit and lower/upper
|
|
783
|
+
// bounds from the original model to the current model, undoing the
|
|
784
|
+
// transformation done before restart so that the offset change due
|
|
785
|
+
// to presolve is incorporated. Bound changes are transitory, so no
|
|
786
|
+
// real gap change, and no update to P-D integral is necessary
|
|
787
|
+
upper_limit -= mipsolver.model_->offset_;
|
|
788
|
+
optimality_limit -= mipsolver.model_->offset_;
|
|
789
|
+
|
|
790
|
+
lower_bound -= mipsolver.model_->offset_;
|
|
791
|
+
upper_bound -= mipsolver.model_->offset_;
|
|
792
|
+
|
|
793
|
+
if (mipsolver.solution_objective_ != kHighsInf) {
|
|
794
|
+
// Assigning new incumbent
|
|
795
|
+
incumbent = postSolveStack.getReducedPrimalSolution(mipsolver.solution_);
|
|
796
|
+
// return the objective value in the transformed space
|
|
797
|
+
double solobj =
|
|
798
|
+
mipsolver.solution_objective_ * (int)mipsolver.orig_model_->sense_ -
|
|
799
|
+
mipsolver.model_->offset_;
|
|
800
|
+
bool feasible = mipsolver.bound_violation_ <=
|
|
801
|
+
mipsolver.options_mip_->mip_feasibility_tolerance &&
|
|
802
|
+
mipsolver.integrality_violation_ <=
|
|
803
|
+
mipsolver.options_mip_->mip_feasibility_tolerance &&
|
|
804
|
+
mipsolver.row_violation_ <=
|
|
805
|
+
mipsolver.options_mip_->mip_feasibility_tolerance;
|
|
806
|
+
if (numRestarts == 0) {
|
|
807
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
808
|
+
"\nMIP start solution is %s, objective value is %.12g\n",
|
|
809
|
+
feasible ? "feasible" : "infeasible",
|
|
810
|
+
mipsolver.solution_objective_);
|
|
811
|
+
}
|
|
812
|
+
if (feasible && solobj < upper_bound) {
|
|
813
|
+
double prev_upper_bound = upper_bound;
|
|
814
|
+
|
|
815
|
+
upper_bound = solobj;
|
|
816
|
+
|
|
817
|
+
bool bound_change = upper_bound != prev_upper_bound;
|
|
818
|
+
if (!mipsolver.submip && bound_change)
|
|
819
|
+
updatePrimalDualIntegral(lower_bound, lower_bound, prev_upper_bound,
|
|
820
|
+
upper_bound);
|
|
821
|
+
|
|
822
|
+
double new_upper_limit = computeNewUpperLimit(solobj, 0.0, 0.0);
|
|
823
|
+
|
|
824
|
+
saveReportMipSolution(new_upper_limit);
|
|
825
|
+
if (new_upper_limit < upper_limit) {
|
|
826
|
+
upper_limit = new_upper_limit;
|
|
827
|
+
optimality_limit =
|
|
828
|
+
computeNewUpperLimit(solobj, mipsolver.options_mip_->mip_abs_gap,
|
|
829
|
+
mipsolver.options_mip_->mip_rel_gap);
|
|
830
|
+
nodequeue.setOptimalityLimit(optimality_limit);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
if (!mipsolver.submip && feasible && mipsolver.callback_->user_callback &&
|
|
834
|
+
mipsolver.callback_->active[kCallbackMipSolution]) {
|
|
835
|
+
assert(!mipsolver.submip);
|
|
836
|
+
mipsolver.callback_->clearHighsCallbackOutput();
|
|
837
|
+
mipsolver.callback_->data_out.mip_solution = mipsolver.solution_;
|
|
838
|
+
const bool interrupt = interruptFromCallbackWithData(
|
|
839
|
+
kCallbackMipSolution, mipsolver.solution_objective_,
|
|
840
|
+
"Feasible solution");
|
|
841
|
+
assert(!interrupt);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
if (mipsolver.numCol() == 0)
|
|
846
|
+
addIncumbent(std::vector<double>(), 0, kSolutionSourceEmptyMip);
|
|
847
|
+
|
|
848
|
+
redcostfixing = HighsRedcostFixing();
|
|
849
|
+
pseudocost = HighsPseudocost(mipsolver);
|
|
850
|
+
nodequeue.setNumCol(mipsolver.numCol());
|
|
851
|
+
nodequeue.setOptimalityLimit(optimality_limit);
|
|
852
|
+
|
|
853
|
+
continuous_cols.clear();
|
|
854
|
+
integer_cols.clear();
|
|
855
|
+
implint_cols.clear();
|
|
856
|
+
integral_cols.clear();
|
|
857
|
+
|
|
858
|
+
rowMatrixSet = false;
|
|
859
|
+
if (!rowMatrixSet) {
|
|
860
|
+
rowMatrixSet = true;
|
|
861
|
+
highsSparseTranspose(model.num_row_, model.num_col_, model.a_matrix_.start_,
|
|
862
|
+
model.a_matrix_.index_, model.a_matrix_.value_,
|
|
863
|
+
ARstart_, ARindex_, ARvalue_);
|
|
864
|
+
// (re-)initialize number of uplocks and downlocks
|
|
865
|
+
uplocks.assign(model.num_col_, 0);
|
|
866
|
+
downlocks.assign(model.num_col_, 0);
|
|
867
|
+
for (HighsInt i = 0; i != model.num_col_; ++i) {
|
|
868
|
+
HighsInt start = model.a_matrix_.start_[i];
|
|
869
|
+
HighsInt end = model.a_matrix_.start_[i + 1];
|
|
870
|
+
for (HighsInt j = start; j != end; ++j) {
|
|
871
|
+
HighsInt row = model.a_matrix_.index_[j];
|
|
872
|
+
|
|
873
|
+
if (model.row_lower_[row] != -kHighsInf) {
|
|
874
|
+
if (model.a_matrix_.value_[j] < 0)
|
|
875
|
+
++uplocks[i];
|
|
876
|
+
else
|
|
877
|
+
++downlocks[i];
|
|
878
|
+
}
|
|
879
|
+
if (model.row_upper_[row] != kHighsInf) {
|
|
880
|
+
if (model.a_matrix_.value_[j] < 0)
|
|
881
|
+
++downlocks[i];
|
|
882
|
+
else
|
|
883
|
+
++uplocks[i];
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
rowintegral.resize(mipsolver.numRow());
|
|
890
|
+
|
|
891
|
+
// compute the maximal absolute coefficients to filter propagation
|
|
892
|
+
maxAbsRowCoef.resize(mipsolver.numRow());
|
|
893
|
+
for (HighsInt i = 0; i != mipsolver.numRow(); ++i) {
|
|
894
|
+
double maxabsval = 0.0;
|
|
895
|
+
|
|
896
|
+
HighsInt start = ARstart_[i];
|
|
897
|
+
HighsInt end = ARstart_[i + 1];
|
|
898
|
+
bool integral = true;
|
|
899
|
+
for (HighsInt j = start; j != end; ++j) {
|
|
900
|
+
integral = integral && mipsolver.isColIntegral(ARindex_[j]) &&
|
|
901
|
+
fractionality(ARvalue_[j]) <= epsilon;
|
|
902
|
+
|
|
903
|
+
maxabsval = std::max(maxabsval, std::abs(ARvalue_[j]));
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
if (integral) {
|
|
907
|
+
if (presolvedModel.row_lower_[i] != -kHighsInf)
|
|
908
|
+
presolvedModel.row_lower_[i] =
|
|
909
|
+
std::ceil(presolvedModel.row_lower_[i] - feastol);
|
|
910
|
+
|
|
911
|
+
if (presolvedModel.row_upper_[i] != kHighsInf)
|
|
912
|
+
presolvedModel.row_upper_[i] =
|
|
913
|
+
std::floor(presolvedModel.row_upper_[i] + feastol);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
rowintegral[i] = integral;
|
|
917
|
+
maxAbsRowCoef[i] = maxabsval;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// compute row activities and propagate all rows once
|
|
921
|
+
objectiveFunction.setupCliquePartition(domain, cliquetable);
|
|
922
|
+
domain.setupObjectivePropagation();
|
|
923
|
+
domain.computeRowActivities();
|
|
924
|
+
domain.propagate();
|
|
925
|
+
if (domain.infeasible()) {
|
|
926
|
+
mipsolver.modelstatus_ = HighsModelStatus::kInfeasible;
|
|
927
|
+
|
|
928
|
+
updateLowerBound(kHighsInf);
|
|
929
|
+
|
|
930
|
+
pruned_treeweight = 1.0;
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
if (model.num_col_ == 0) {
|
|
935
|
+
mipsolver.modelstatus_ = HighsModelStatus::kOptimal;
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
if (checkLimits()) return;
|
|
940
|
+
// extract cliques if they have not been extracted before
|
|
941
|
+
|
|
942
|
+
for (HighsInt col : domain.getChangedCols())
|
|
943
|
+
implications.cleanupVarbounds(col);
|
|
944
|
+
domain.clearChangedCols();
|
|
945
|
+
|
|
946
|
+
lp.getLpSolver().setOptionValue("presolve", kHighsOffString);
|
|
947
|
+
// lp.getLpSolver().setOptionValue("dual_simplex_cost_perturbation_multiplier",
|
|
948
|
+
// 0.0); lp.getLpSolver().setOptionValue("parallel", kHighsOnString);
|
|
949
|
+
lp.getLpSolver().setOptionValue("simplex_initial_condition_check", false);
|
|
950
|
+
|
|
951
|
+
checkObjIntegrality();
|
|
952
|
+
rootlpsol.clear();
|
|
953
|
+
firstlpsol.clear();
|
|
954
|
+
HighsInt num_binary = 0;
|
|
955
|
+
HighsInt num_domain_fixed = 0;
|
|
956
|
+
maxTreeSizeLog2 = 0;
|
|
957
|
+
for (HighsInt i = 0; i != mipsolver.numCol(); ++i) {
|
|
958
|
+
switch (mipsolver.variableType(i)) {
|
|
959
|
+
case HighsVarType::kContinuous:
|
|
960
|
+
if (domain.isFixed(i)) {
|
|
961
|
+
num_domain_fixed++;
|
|
962
|
+
continue;
|
|
963
|
+
}
|
|
964
|
+
continuous_cols.push_back(i);
|
|
965
|
+
break;
|
|
966
|
+
case HighsVarType::kImplicitInteger:
|
|
967
|
+
if (domain.isFixed(i)) {
|
|
968
|
+
num_domain_fixed++;
|
|
969
|
+
continue;
|
|
970
|
+
}
|
|
971
|
+
implint_cols.push_back(i);
|
|
972
|
+
integral_cols.push_back(i);
|
|
973
|
+
break;
|
|
974
|
+
case HighsVarType::kInteger:
|
|
975
|
+
if (domain.isFixed(i)) {
|
|
976
|
+
num_domain_fixed++;
|
|
977
|
+
if (fractionality(domain.col_lower_[i]) > feastol) {
|
|
978
|
+
// integer variable is fixed to a fractional value -> infeasible
|
|
979
|
+
mipsolver.modelstatus_ = HighsModelStatus::kInfeasible;
|
|
980
|
+
|
|
981
|
+
updateLowerBound(kHighsInf);
|
|
982
|
+
|
|
983
|
+
pruned_treeweight = 1.0;
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
continue;
|
|
987
|
+
}
|
|
988
|
+
integer_cols.push_back(i);
|
|
989
|
+
integral_cols.push_back(i);
|
|
990
|
+
maxTreeSizeLog2 += (HighsInt)std::ceil(
|
|
991
|
+
std::log2(std::min(1024.0, 1.0 + mipsolver.model_->col_upper_[i] -
|
|
992
|
+
mipsolver.model_->col_lower_[i])));
|
|
993
|
+
// NB Since this is for counting the number of times the
|
|
994
|
+
// condition is true using the bitwise operator avoids having
|
|
995
|
+
// any conditional branch whereas using the logical operator
|
|
996
|
+
// would require a branch due to short circuit
|
|
997
|
+
// evaluation. Semantically both is equivalent and correct. If
|
|
998
|
+
// there was any code to be executed for the condition being
|
|
999
|
+
// true then there would be a conditional branch in any case
|
|
1000
|
+
// and I would have used the logical to begin with.
|
|
1001
|
+
//
|
|
1002
|
+
// Hence any compiler warning can be ignored safely
|
|
1003
|
+
num_binary +=
|
|
1004
|
+
(static_cast<HighsInt>(mipsolver.model_->col_lower_[i] == 0.0) &
|
|
1005
|
+
static_cast<HighsInt>(mipsolver.model_->col_upper_[i] == 1.0));
|
|
1006
|
+
break;
|
|
1007
|
+
case HighsVarType::kSemiContinuous:
|
|
1008
|
+
case HighsVarType::kSemiInteger:
|
|
1009
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kError,
|
|
1010
|
+
"Semicontinuous or semiinteger variables should have been "
|
|
1011
|
+
"reformulated away before HighsMipSolverData::runSetup() "
|
|
1012
|
+
"is called.");
|
|
1013
|
+
throw std::logic_error("Unexpected variable type");
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
basisTransfer();
|
|
1018
|
+
|
|
1019
|
+
numintegercols = integer_cols.size();
|
|
1020
|
+
detectSymmetries = detectSymmetries && num_binary > 0;
|
|
1021
|
+
numCliqueEntriesAfterPresolve = cliquetable.getNumEntries();
|
|
1022
|
+
HighsInt num_col = mipsolver.numCol();
|
|
1023
|
+
HighsInt num_general_integer = numintegercols - num_binary;
|
|
1024
|
+
HighsInt num_implied_integer = implint_cols.size();
|
|
1025
|
+
HighsInt num_continuous = continuous_cols.size();
|
|
1026
|
+
assert(num_col == num_continuous + num_binary + num_general_integer +
|
|
1027
|
+
num_implied_integer + num_domain_fixed);
|
|
1028
|
+
if (numRestarts == 0) {
|
|
1029
|
+
numCliqueEntriesAfterFirstPresolve = cliquetable.getNumEntries();
|
|
1030
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
1031
|
+
// clang-format off
|
|
1032
|
+
"\nSolving MIP model with:\n"
|
|
1033
|
+
" %" HIGHSINT_FORMAT " row%s\n"
|
|
1034
|
+
" %" HIGHSINT_FORMAT " col%s ("
|
|
1035
|
+
"%" HIGHSINT_FORMAT" binary, "
|
|
1036
|
+
"%" HIGHSINT_FORMAT " integer, "
|
|
1037
|
+
"%" HIGHSINT_FORMAT" implied int., "
|
|
1038
|
+
"%" HIGHSINT_FORMAT " continuous, "
|
|
1039
|
+
"%" HIGHSINT_FORMAT " domain fixed)\n"
|
|
1040
|
+
" %" HIGHSINT_FORMAT " nonzero%s\n",
|
|
1041
|
+
// clang-format on
|
|
1042
|
+
mipsolver.numRow(), mipsolver.numRow() == 1 ? "" : "s",
|
|
1043
|
+
num_col, num_col == 1 ? "" : "s", num_binary,
|
|
1044
|
+
num_general_integer, num_implied_integer, num_continuous,
|
|
1045
|
+
num_domain_fixed, mipsolver.numNonzero(),
|
|
1046
|
+
mipsolver.numNonzero() == 1 ? "" : "s");
|
|
1047
|
+
} else {
|
|
1048
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
1049
|
+
"Model after restart has "
|
|
1050
|
+
// clang-format off
|
|
1051
|
+
"%" HIGHSINT_FORMAT " row%s, "
|
|
1052
|
+
"%" HIGHSINT_FORMAT " col%s ("
|
|
1053
|
+
"%" HIGHSINT_FORMAT " bin., "
|
|
1054
|
+
"%" HIGHSINT_FORMAT " int., "
|
|
1055
|
+
"%" HIGHSINT_FORMAT " impl., "
|
|
1056
|
+
"%" HIGHSINT_FORMAT " cont., "
|
|
1057
|
+
"%" HIGHSINT_FORMAT " dom.fix.), and "
|
|
1058
|
+
"%" HIGHSINT_FORMAT " nonzero%s\n",
|
|
1059
|
+
// clang-format on
|
|
1060
|
+
mipsolver.numRow(), mipsolver.numRow() == 1 ? "" : "s",
|
|
1061
|
+
num_col, num_col == 1 ? "" : "s", num_binary,
|
|
1062
|
+
num_general_integer, num_implied_integer, num_continuous,
|
|
1063
|
+
num_domain_fixed, mipsolver.numNonzero(),
|
|
1064
|
+
mipsolver.numNonzero() == 1 ? "" : "s");
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
heuristics.setupIntCols();
|
|
1068
|
+
|
|
1069
|
+
#ifdef HIGHS_DEBUGSOL
|
|
1070
|
+
if (debugSolution.debugSolActive) {
|
|
1071
|
+
debugSolution.debugSolution.clear();
|
|
1072
|
+
debugSolution.debugSolution = postSolveStack.getReducedPrimalSolution(
|
|
1073
|
+
debugSolution.debugOrigSolution);
|
|
1074
|
+
debugSolution.debugSolObjective = 0;
|
|
1075
|
+
HighsCDouble debugsolobj = 0.0;
|
|
1076
|
+
for (HighsInt i = 0; i != mipsolver.numCol(); ++i)
|
|
1077
|
+
debugsolobj +=
|
|
1078
|
+
mipsolver.colCost(i) * HighsCDouble(debugSolution.debugSolution[i]);
|
|
1079
|
+
debugSolution.debugSolObjective = static_cast<double>(debugsolobj);
|
|
1080
|
+
debugSolution.registerDomain(domain);
|
|
1081
|
+
assert(checkSolution(debugSolution.debugSolution));
|
|
1082
|
+
}
|
|
1083
|
+
#endif
|
|
1084
|
+
|
|
1085
|
+
if (upper_limit == kHighsInf) analyticCenterComputed = false;
|
|
1086
|
+
analyticCenterStatus = HighsModelStatus::kNotset;
|
|
1087
|
+
analyticCenter.clear();
|
|
1088
|
+
|
|
1089
|
+
symmetries.clear();
|
|
1090
|
+
|
|
1091
|
+
if (numRestarts != 0)
|
|
1092
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
1093
|
+
"\n");
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
double HighsMipSolverData::transformNewIntegerFeasibleSolution(
|
|
1097
|
+
const std::vector<double>& sol,
|
|
1098
|
+
const bool possibly_store_as_new_incumbent) {
|
|
1099
|
+
HighsSolution solution;
|
|
1100
|
+
solution.col_value = sol;
|
|
1101
|
+
solution.value_valid = true;
|
|
1102
|
+
// Perform primal postsolve to get the original column values
|
|
1103
|
+
postSolveStack.undoPrimal(*mipsolver.options_mip_, solution);
|
|
1104
|
+
// Determine the row values, as they aren't computed in primal
|
|
1105
|
+
// postsolve
|
|
1106
|
+
HighsStatus return_status =
|
|
1107
|
+
calculateRowValuesQuad(*mipsolver.orig_model_, solution);
|
|
1108
|
+
if (kAllowDeveloperAssert) assert(return_status == HighsStatus::kOk);
|
|
1109
|
+
bool allow_try_again = true;
|
|
1110
|
+
try_again:
|
|
1111
|
+
|
|
1112
|
+
// compute the objective value in the original space
|
|
1113
|
+
double bound_violation_ = 0;
|
|
1114
|
+
double row_violation_ = 0;
|
|
1115
|
+
double integrality_violation_ = 0;
|
|
1116
|
+
HighsCDouble mipsolver_quad_objective_value = 0;
|
|
1117
|
+
bool feasible = mipsolver.solutionFeasible(
|
|
1118
|
+
mipsolver.orig_model_, solution.col_value, &solution.row_value,
|
|
1119
|
+
bound_violation_, row_violation_, integrality_violation_,
|
|
1120
|
+
mipsolver_quad_objective_value);
|
|
1121
|
+
double mipsolver_objective_value = double(mipsolver_quad_objective_value);
|
|
1122
|
+
if (!feasible && allow_try_again) {
|
|
1123
|
+
// printf(
|
|
1124
|
+
// "trying to repair sol that is violated by %.12g bounds, %.12g "
|
|
1125
|
+
// "integrality, %.12g rows\n",
|
|
1126
|
+
// bound_violation_, integrality_violation_, row_violation_);
|
|
1127
|
+
HighsLp fixedModel = *mipsolver.orig_model_;
|
|
1128
|
+
fixedModel.integrality_.clear();
|
|
1129
|
+
for (HighsInt i = 0; i != mipsolver.orig_model_->num_col_; ++i) {
|
|
1130
|
+
if (mipsolver.orig_model_->integrality_[i] == HighsVarType::kInteger) {
|
|
1131
|
+
double solval = std::round(solution.col_value[i]);
|
|
1132
|
+
fixedModel.col_lower_[i] = std::max(fixedModel.col_lower_[i], solval);
|
|
1133
|
+
fixedModel.col_upper_[i] = std::min(fixedModel.col_upper_[i], solval);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
this->total_repair_lp++;
|
|
1137
|
+
double time_available = std::max(
|
|
1138
|
+
mipsolver.options_mip_->time_limit - mipsolver.timer_.read(), 0.1);
|
|
1139
|
+
Highs tmpSolver;
|
|
1140
|
+
const bool debug_report = false;
|
|
1141
|
+
if (debug_report) {
|
|
1142
|
+
tmpSolver.setOptionValue("log_dev_level", 2);
|
|
1143
|
+
tmpSolver.setOptionValue("highs_analysis_level", 4);
|
|
1144
|
+
} else {
|
|
1145
|
+
tmpSolver.setOptionValue("output_flag", false);
|
|
1146
|
+
}
|
|
1147
|
+
// tmpSolver.setOptionValue("simplex_scale_strategy", 0);
|
|
1148
|
+
// tmpSolver.setOptionValue("presolve", kHighsOffString);
|
|
1149
|
+
tmpSolver.setOptionValue("time_limit", time_available);
|
|
1150
|
+
// Set primal feasibility tolerance for LP solves according to
|
|
1151
|
+
// mip_feasibility_tolerance. Interestingly, dual feasibility
|
|
1152
|
+
// tolerance not set to smaller tolerance as in
|
|
1153
|
+
// HighsLpRelaxationconstructor.
|
|
1154
|
+
double mip_primal_feasibility_tolerance =
|
|
1155
|
+
mipsolver.options_mip_->mip_feasibility_tolerance;
|
|
1156
|
+
tmpSolver.setOptionValue("primal_feasibility_tolerance",
|
|
1157
|
+
mip_primal_feasibility_tolerance);
|
|
1158
|
+
// check if only root presolve is allowed
|
|
1159
|
+
const bool use_presolve = !mipsolver.options_mip_->mip_root_presolve_only;
|
|
1160
|
+
const std::string presolve =
|
|
1161
|
+
use_presolve ? kHighsChooseString : kHighsOffString;
|
|
1162
|
+
tmpSolver.setOptionValue("presolve", presolve);
|
|
1163
|
+
tmpSolver.passModel(std::move(fixedModel));
|
|
1164
|
+
// Until a good decision can be made on whether to use simplex,
|
|
1165
|
+
// HiPO or IPX to solve an LP without a basis, use simplex
|
|
1166
|
+
tmpSolver.setOptionValue("solver", kSimplexString);
|
|
1167
|
+
tmpSolver.optimizeLp();
|
|
1168
|
+
if (!mipsolver.submip) {
|
|
1169
|
+
const HighsSubSolverCallTime& sub_solver_call_time =
|
|
1170
|
+
tmpSolver.getSubSolverCallTime();
|
|
1171
|
+
const bool analytic_centre = false;
|
|
1172
|
+
mipsolver.analysis_.addSubSolverCallTime(sub_solver_call_time,
|
|
1173
|
+
analytic_centre);
|
|
1174
|
+
// Go through sub_solver_call_time to update any MIP clocks
|
|
1175
|
+
const bool valid_basis = false;
|
|
1176
|
+
mipsolver.analysis_.mipTimerUpdate(sub_solver_call_time, valid_basis,
|
|
1177
|
+
use_presolve, analytic_centre);
|
|
1178
|
+
}
|
|
1179
|
+
this->total_repair_lp_iterations =
|
|
1180
|
+
tmpSolver.getInfo().simplex_iteration_count;
|
|
1181
|
+
if (tmpSolver.getInfo().primal_solution_status == kSolutionStatusFeasible) {
|
|
1182
|
+
this->total_repair_lp_feasible++;
|
|
1183
|
+
solution = tmpSolver.getSolution();
|
|
1184
|
+
allow_try_again = false;
|
|
1185
|
+
goto try_again;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
const double transformed_solobj =
|
|
1190
|
+
static_cast<double>(static_cast<HighsInt>(mipsolver.orig_model_->sense_) *
|
|
1191
|
+
mipsolver_quad_objective_value -
|
|
1192
|
+
mipsolver.model_->offset_);
|
|
1193
|
+
|
|
1194
|
+
// Possible MIP solution callback
|
|
1195
|
+
if (!mipsolver.submip && feasible && mipsolver.callback_->user_callback &&
|
|
1196
|
+
mipsolver.callback_->active[kCallbackMipSolution]) {
|
|
1197
|
+
mipsolver.callback_->clearHighsCallbackOutput();
|
|
1198
|
+
mipsolver.callback_->data_out.mip_solution = solution.col_value;
|
|
1199
|
+
const bool interrupt = interruptFromCallbackWithData(
|
|
1200
|
+
kCallbackMipSolution, mipsolver_objective_value, "Feasible solution");
|
|
1201
|
+
assert(!interrupt);
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// Catch the case where the repaired solution now has worse objective
|
|
1205
|
+
// than the current stored solution
|
|
1206
|
+
if (transformed_solobj >= upper_bound && !sol.empty()) {
|
|
1207
|
+
return transformed_solobj;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
if (possibly_store_as_new_incumbent) {
|
|
1211
|
+
// Store the solution as incumbent in the original space if there
|
|
1212
|
+
// is no solution or if it is feasible
|
|
1213
|
+
if (feasible) {
|
|
1214
|
+
// if (!allow_try_again)
|
|
1215
|
+
// printf("repaired solution with value %g\n",
|
|
1216
|
+
// mipsolver_objective_value);
|
|
1217
|
+
// store
|
|
1218
|
+
mipsolver.row_violation_ = row_violation_;
|
|
1219
|
+
mipsolver.bound_violation_ = bound_violation_;
|
|
1220
|
+
mipsolver.integrality_violation_ = integrality_violation_;
|
|
1221
|
+
mipsolver.solution_ = std::move(solution.col_value);
|
|
1222
|
+
mipsolver.solution_objective_ = mipsolver_objective_value;
|
|
1223
|
+
} else {
|
|
1224
|
+
bool currentFeasible =
|
|
1225
|
+
mipsolver.solution_objective_ != kHighsInf &&
|
|
1226
|
+
mipsolver.bound_violation_ <=
|
|
1227
|
+
mipsolver.options_mip_->mip_feasibility_tolerance &&
|
|
1228
|
+
mipsolver.integrality_violation_ <=
|
|
1229
|
+
mipsolver.options_mip_->mip_feasibility_tolerance &&
|
|
1230
|
+
mipsolver.row_violation_ <=
|
|
1231
|
+
mipsolver.options_mip_->mip_feasibility_tolerance;
|
|
1232
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kWarning,
|
|
1233
|
+
"Solution with objective %g has untransformed violations: "
|
|
1234
|
+
"bound = %.4g; integrality = %.4g; row = %.4g\n",
|
|
1235
|
+
mipsolver_objective_value, bound_violation_,
|
|
1236
|
+
integrality_violation_, row_violation_);
|
|
1237
|
+
if (!currentFeasible) {
|
|
1238
|
+
// if the current incumbent is non existent or also not feasible we
|
|
1239
|
+
// still store the new one
|
|
1240
|
+
mipsolver.row_violation_ = row_violation_;
|
|
1241
|
+
mipsolver.bound_violation_ = bound_violation_;
|
|
1242
|
+
mipsolver.integrality_violation_ = integrality_violation_;
|
|
1243
|
+
mipsolver.solution_ = std::move(solution.col_value);
|
|
1244
|
+
mipsolver.solution_objective_ = mipsolver_objective_value;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
// return infinity so that it is not used for bounding
|
|
1248
|
+
return kHighsInf;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
// return the objective value in the transformed space
|
|
1253
|
+
return transformed_solobj;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
double HighsMipSolverData::percentageInactiveIntegers() const {
|
|
1257
|
+
return 100.0 *
|
|
1258
|
+
(1.0 - static_cast<double>(integer_cols.size() -
|
|
1259
|
+
cliquetable.getSubstitutions().size()) /
|
|
1260
|
+
numintegercols);
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
void HighsMipSolverData::performRestart() {
|
|
1264
|
+
HighsBasis root_basis;
|
|
1265
|
+
HighsPseudocostInitialization pscostinit(
|
|
1266
|
+
pseudocost, mipsolver.options_mip_->mip_pscost_minreliable,
|
|
1267
|
+
postSolveStack);
|
|
1268
|
+
|
|
1269
|
+
mipsolver.pscostinit = &pscostinit;
|
|
1270
|
+
++numRestarts;
|
|
1271
|
+
num_leaves_before_run = num_leaves;
|
|
1272
|
+
num_nodes_before_run = num_nodes;
|
|
1273
|
+
num_nodes_before_run = num_nodes;
|
|
1274
|
+
total_lp_iterations_before_run = total_lp_iterations;
|
|
1275
|
+
heuristic_lp_iterations_before_run = heuristic_lp_iterations;
|
|
1276
|
+
sepa_lp_iterations_before_run = sepa_lp_iterations;
|
|
1277
|
+
sb_lp_iterations_before_run = sb_lp_iterations;
|
|
1278
|
+
HighsInt numLpRows = lp.getLp().num_row_;
|
|
1279
|
+
HighsInt numModelRows = mipsolver.numRow();
|
|
1280
|
+
HighsInt numCuts = numLpRows - numModelRows;
|
|
1281
|
+
if (numCuts > 0) postSolveStack.appendCutsToModel(numCuts);
|
|
1282
|
+
auto integrality = std::move(presolvedModel.integrality_);
|
|
1283
|
+
double offset = presolvedModel.offset_;
|
|
1284
|
+
presolvedModel = lp.getLp();
|
|
1285
|
+
presolvedModel.offset_ = offset;
|
|
1286
|
+
presolvedModel.integrality_ = std::move(integrality);
|
|
1287
|
+
#ifdef HIGHS_DEBUGSOL
|
|
1288
|
+
bool debugSolActive = false;
|
|
1289
|
+
std::swap(debugSolution.debugSolActive, debugSolActive);
|
|
1290
|
+
#endif
|
|
1291
|
+
|
|
1292
|
+
const HighsBasis& basis = firstrootbasis;
|
|
1293
|
+
if (basis.valid) {
|
|
1294
|
+
// if we have a basis after solving the root LP, we expand it to the
|
|
1295
|
+
// original space so that it can be used for constructing a starting basis
|
|
1296
|
+
// for the presolved model after the restart
|
|
1297
|
+
root_basis.col_status.resize(postSolveStack.getOrigNumCol());
|
|
1298
|
+
root_basis.row_status.resize(postSolveStack.getOrigNumRow(),
|
|
1299
|
+
HighsBasisStatus::kBasic);
|
|
1300
|
+
root_basis.valid = true;
|
|
1301
|
+
root_basis.useful = true;
|
|
1302
|
+
|
|
1303
|
+
for (HighsInt i = 0; i < mipsolver.numCol(); ++i)
|
|
1304
|
+
root_basis.col_status[postSolveStack.getOrigColIndex(i)] =
|
|
1305
|
+
basis.col_status[i];
|
|
1306
|
+
|
|
1307
|
+
HighsInt numRow = basis.row_status.size();
|
|
1308
|
+
for (HighsInt i = 0; i < numRow; ++i)
|
|
1309
|
+
root_basis.row_status[postSolveStack.getOrigRowIndex(i)] =
|
|
1310
|
+
basis.row_status[i];
|
|
1311
|
+
|
|
1312
|
+
mipsolver.rootbasis = &root_basis;
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
// Transform the reference of the objective limit and lower/upper
|
|
1316
|
+
// bounds to the original model, since offset will generally change
|
|
1317
|
+
// in presolve. Bound changes are transitory, so no real gap change,
|
|
1318
|
+
// and no update to P-D integral is necessary
|
|
1319
|
+
upper_limit += mipsolver.model_->offset_;
|
|
1320
|
+
optimality_limit += mipsolver.model_->offset_;
|
|
1321
|
+
|
|
1322
|
+
upper_bound += mipsolver.model_->offset_;
|
|
1323
|
+
lower_bound += mipsolver.model_->offset_;
|
|
1324
|
+
|
|
1325
|
+
// remove the current incumbent. Any incumbent is already transformed into the
|
|
1326
|
+
// original space and kept there
|
|
1327
|
+
incumbent.clear();
|
|
1328
|
+
pruned_treeweight = 0;
|
|
1329
|
+
nodequeue.clear();
|
|
1330
|
+
globalOrbits.reset();
|
|
1331
|
+
|
|
1332
|
+
// Need to be able to set presolve reduction limit separately when
|
|
1333
|
+
// restarting - so that bugs in presolve restart can be investigated
|
|
1334
|
+
// independently (see #1553)
|
|
1335
|
+
//
|
|
1336
|
+
// However, when restarting, presolve is (naturally) applied to the
|
|
1337
|
+
// presolved problem, so have to control the number of _further_
|
|
1338
|
+
// presolve reductions
|
|
1339
|
+
//
|
|
1340
|
+
// The number of further presolve reductions must be positive,
|
|
1341
|
+
// otherwise the MIP solver cycles, hence
|
|
1342
|
+
// restart_presolve_reduction_limit cannot be zero
|
|
1343
|
+
//
|
|
1344
|
+
// Although postSolveStack.numReductions() is size_t, it makes no
|
|
1345
|
+
// sense to use presolve_reduction_limit when the number of
|
|
1346
|
+
// reductions is vast
|
|
1347
|
+
HighsInt num_reductions = HighsInt(postSolveStack.numReductions());
|
|
1348
|
+
HighsInt restart_presolve_reduction_limit =
|
|
1349
|
+
mipsolver.options_mip_->restart_presolve_reduction_limit;
|
|
1350
|
+
assert(restart_presolve_reduction_limit);
|
|
1351
|
+
HighsInt further_presolve_reduction_limit =
|
|
1352
|
+
restart_presolve_reduction_limit >= 0
|
|
1353
|
+
? num_reductions + restart_presolve_reduction_limit
|
|
1354
|
+
: -1;
|
|
1355
|
+
runMipPresolve(further_presolve_reduction_limit);
|
|
1356
|
+
|
|
1357
|
+
if (mipsolver.modelstatus_ != HighsModelStatus::kNotset) {
|
|
1358
|
+
// transform the objective limit to the current model
|
|
1359
|
+
upper_limit -= mipsolver.model_->offset_;
|
|
1360
|
+
optimality_limit -= mipsolver.model_->offset_;
|
|
1361
|
+
|
|
1362
|
+
if (mipsolver.modelstatus_ == HighsModelStatus::kOptimal) {
|
|
1363
|
+
mipsolver.mipdata_->upper_bound = 0;
|
|
1364
|
+
mipsolver.mipdata_->transformNewIntegerFeasibleSolution(
|
|
1365
|
+
std::vector<double>());
|
|
1366
|
+
} else {
|
|
1367
|
+
upper_bound -= mipsolver.model_->offset_;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
// lower_bound still relates to the original model, and the offset
|
|
1371
|
+
// is never applied, since MIP solving is complete, and
|
|
1372
|
+
// lower_bound is set to upper_bound, so apply the offset now, so
|
|
1373
|
+
// that housekeeping in updatePrimalDualIntegral is correct
|
|
1374
|
+
lower_bound -= mipsolver.model_->offset_;
|
|
1375
|
+
|
|
1376
|
+
// There must be a gap change, since it's now zero, so always call
|
|
1377
|
+
// updatePrimalDualIntegral (unless solving a sub-MIP)
|
|
1378
|
+
//
|
|
1379
|
+
// Surely there must be a lower bound change
|
|
1380
|
+
updateLowerBound(upper_bound);
|
|
1381
|
+
|
|
1382
|
+
if (mipsolver.solution_objective_ != kHighsInf &&
|
|
1383
|
+
mipsolver.modelstatus_ == HighsModelStatus::kInfeasible)
|
|
1384
|
+
mipsolver.modelstatus_ = HighsModelStatus::kOptimal;
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
// Bounds are currently in the original space since presolve will have
|
|
1388
|
+
// changed offset_
|
|
1389
|
+
#ifdef HIGHS_DEBUGSOL
|
|
1390
|
+
debugSolution.debugSolActive = debugSolActive;
|
|
1391
|
+
#endif
|
|
1392
|
+
runSetup();
|
|
1393
|
+
if (mipsolver.terminate()) return;
|
|
1394
|
+
|
|
1395
|
+
postSolveStack.removeCutsFromModel(numCuts);
|
|
1396
|
+
|
|
1397
|
+
// HighsNodeQueue oldNodeQueue;
|
|
1398
|
+
// std::swap(nodequeue, oldNodeQueue);
|
|
1399
|
+
|
|
1400
|
+
// remove the pointer into the stack-space of this function
|
|
1401
|
+
if (mipsolver.rootbasis == &root_basis) mipsolver.rootbasis = nullptr;
|
|
1402
|
+
mipsolver.pscostinit = nullptr;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
void HighsMipSolverData::basisTransfer() {
|
|
1406
|
+
// if a root basis is given, construct a basis for the root LP from
|
|
1407
|
+
// in the reduced problem space after presolving
|
|
1408
|
+
if (mipsolver.rootbasis) {
|
|
1409
|
+
const HighsInt numRow = mipsolver.numRow();
|
|
1410
|
+
const HighsInt numCol = mipsolver.numCol();
|
|
1411
|
+
firstrootbasis.col_status.assign(numCol, HighsBasisStatus::kNonbasic);
|
|
1412
|
+
firstrootbasis.row_status.assign(numRow, HighsBasisStatus::kNonbasic);
|
|
1413
|
+
firstrootbasis.valid = true;
|
|
1414
|
+
firstrootbasis.alien = true;
|
|
1415
|
+
firstrootbasis.useful = true;
|
|
1416
|
+
|
|
1417
|
+
for (HighsInt i = 0; i < numRow; ++i) {
|
|
1418
|
+
HighsBasisStatus status =
|
|
1419
|
+
mipsolver.rootbasis->row_status[postSolveStack.getOrigRowIndex(i)];
|
|
1420
|
+
firstrootbasis.row_status[i] = status;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
for (HighsInt i = 0; i < numCol; ++i) {
|
|
1424
|
+
HighsBasisStatus status =
|
|
1425
|
+
mipsolver.rootbasis->col_status[postSolveStack.getOrigColIndex(i)];
|
|
1426
|
+
firstrootbasis.col_status[i] = status;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
const std::vector<double>& HighsMipSolverData::getSolution() const {
|
|
1432
|
+
return incumbent;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
bool HighsMipSolverData::addIncumbent(const std::vector<double>& sol,
|
|
1436
|
+
double solobj, const int solution_source,
|
|
1437
|
+
const bool print_display_line,
|
|
1438
|
+
const bool is_user_solution) {
|
|
1439
|
+
const bool execute_mip_solution_callback =
|
|
1440
|
+
!is_user_solution && !mipsolver.submip &&
|
|
1441
|
+
(mipsolver.callback_->user_callback
|
|
1442
|
+
? mipsolver.callback_->active[kCallbackMipSolution]
|
|
1443
|
+
: false);
|
|
1444
|
+
// Determine whether the potential new incumbent should be
|
|
1445
|
+
// transformed
|
|
1446
|
+
//
|
|
1447
|
+
// Happens if solobj improves on the upper bound or the MIP solution
|
|
1448
|
+
// callback is active
|
|
1449
|
+
const bool possibly_store_as_new_incumbent = solobj < upper_bound;
|
|
1450
|
+
const bool get_transformed_solution =
|
|
1451
|
+
possibly_store_as_new_incumbent || execute_mip_solution_callback;
|
|
1452
|
+
// Get the transformed objective and solution if required
|
|
1453
|
+
const double transformed_solobj =
|
|
1454
|
+
get_transformed_solution ? transformNewIntegerFeasibleSolution(
|
|
1455
|
+
sol, possibly_store_as_new_incumbent)
|
|
1456
|
+
: 0;
|
|
1457
|
+
const bool highs_solution_report = false;
|
|
1458
|
+
if (solution_source == kSolutionSourceHighsSolution && highs_solution_report
|
|
1459
|
+
//&& possibly_store_as_new_incumbent
|
|
1460
|
+
) {
|
|
1461
|
+
std::stringstream ss;
|
|
1462
|
+
ss.str(std::string());
|
|
1463
|
+
ss << highsFormatToString(
|
|
1464
|
+
"HighsMipSolverData::addIncumbent HiGHS solution Obj "
|
|
1465
|
+
"= %15.8g; UB = %15.8g; Obj-UB = %11.4g; PossAdd = %s",
|
|
1466
|
+
solobj, upper_bound, solobj - upper_bound,
|
|
1467
|
+
possibly_store_as_new_incumbent ? "T" : "F");
|
|
1468
|
+
if (possibly_store_as_new_incumbent)
|
|
1469
|
+
ss << highsFormatToString(
|
|
1470
|
+
"; TransObj = %15.8g; TransObj-UB = %11.4g; TransSolobj < UB %s",
|
|
1471
|
+
transformed_solobj, transformed_solobj - upper_bound,
|
|
1472
|
+
transformed_solobj < upper_bound ? "T" : "F");
|
|
1473
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
1474
|
+
"%s\n", ss.str().c_str());
|
|
1475
|
+
fflush(stdout);
|
|
1476
|
+
}
|
|
1477
|
+
if (possibly_store_as_new_incumbent) {
|
|
1478
|
+
solobj = transformed_solobj;
|
|
1479
|
+
if (solobj >= upper_bound) return false;
|
|
1480
|
+
|
|
1481
|
+
double prev_upper_bound = upper_bound;
|
|
1482
|
+
|
|
1483
|
+
upper_bound = solobj;
|
|
1484
|
+
|
|
1485
|
+
bool bound_change = upper_bound != prev_upper_bound;
|
|
1486
|
+
if (!mipsolver.submip && bound_change)
|
|
1487
|
+
updatePrimalDualIntegral(lower_bound, lower_bound, prev_upper_bound,
|
|
1488
|
+
upper_bound);
|
|
1489
|
+
|
|
1490
|
+
// Assigning new incumbent
|
|
1491
|
+
incumbent = sol;
|
|
1492
|
+
double new_upper_limit = computeNewUpperLimit(solobj, 0.0, 0.0);
|
|
1493
|
+
|
|
1494
|
+
if (!is_user_solution && !mipsolver.submip)
|
|
1495
|
+
saveReportMipSolution(new_upper_limit);
|
|
1496
|
+
if (new_upper_limit < upper_limit) {
|
|
1497
|
+
++numImprovingSols;
|
|
1498
|
+
upper_limit = new_upper_limit;
|
|
1499
|
+
optimality_limit =
|
|
1500
|
+
computeNewUpperLimit(solobj, mipsolver.options_mip_->mip_abs_gap,
|
|
1501
|
+
mipsolver.options_mip_->mip_rel_gap);
|
|
1502
|
+
nodequeue.setOptimalityLimit(optimality_limit);
|
|
1503
|
+
debugSolution.newIncumbentFound();
|
|
1504
|
+
domain.propagate();
|
|
1505
|
+
if (!domain.infeasible()) redcostfixing.propagateRootRedcost(mipsolver);
|
|
1506
|
+
|
|
1507
|
+
// Two calls to printDisplayLine added for completeness,
|
|
1508
|
+
// ensuring that when the root node has an integer solution, a
|
|
1509
|
+
// logging line is issued
|
|
1510
|
+
|
|
1511
|
+
if (domain.infeasible()) {
|
|
1512
|
+
pruned_treeweight = 1.0;
|
|
1513
|
+
nodequeue.clear();
|
|
1514
|
+
if (print_display_line)
|
|
1515
|
+
printDisplayLine(solution_source); // Added for completeness
|
|
1516
|
+
return true;
|
|
1517
|
+
}
|
|
1518
|
+
cliquetable.extractObjCliques(mipsolver);
|
|
1519
|
+
if (domain.infeasible()) {
|
|
1520
|
+
pruned_treeweight = 1.0;
|
|
1521
|
+
nodequeue.clear();
|
|
1522
|
+
if (print_display_line)
|
|
1523
|
+
printDisplayLine(solution_source); // Added for completeness
|
|
1524
|
+
return true;
|
|
1525
|
+
}
|
|
1526
|
+
pruned_treeweight += nodequeue.performBounding(upper_limit);
|
|
1527
|
+
printDisplayLine(solution_source);
|
|
1528
|
+
}
|
|
1529
|
+
} else if (incumbent.empty())
|
|
1530
|
+
// Assigning new incumbent
|
|
1531
|
+
incumbent = sol;
|
|
1532
|
+
|
|
1533
|
+
return true;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
static std::array<char, 22> convertToPrintString(int64_t val) {
|
|
1537
|
+
decltype(convertToPrintString(std::declval<int64_t>())) printString = {};
|
|
1538
|
+
double l = std::log10(std::max(1.0, double(val)));
|
|
1539
|
+
switch (int(l)) {
|
|
1540
|
+
case 0:
|
|
1541
|
+
case 1:
|
|
1542
|
+
case 2:
|
|
1543
|
+
case 3:
|
|
1544
|
+
case 4:
|
|
1545
|
+
case 5:
|
|
1546
|
+
std::snprintf(printString.data(), printString.size(), "%" PRId64, val);
|
|
1547
|
+
break;
|
|
1548
|
+
case 6:
|
|
1549
|
+
case 7:
|
|
1550
|
+
case 8:
|
|
1551
|
+
std::snprintf(printString.data(), printString.size(), "%" PRId64 "k",
|
|
1552
|
+
val / 1000);
|
|
1553
|
+
break;
|
|
1554
|
+
default:
|
|
1555
|
+
std::snprintf(printString.data(), printString.size(), "%" PRId64 "m",
|
|
1556
|
+
val / 1000000);
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
return printString;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
static std::array<char, 22> convertToPrintString(double val,
|
|
1563
|
+
const char* trailingStr = "") {
|
|
1564
|
+
decltype(convertToPrintString(std::declval<double>(),
|
|
1565
|
+
std::declval<char*>())) printString = {};
|
|
1566
|
+
double l = std::abs(val) == kHighsInf
|
|
1567
|
+
? 0.0
|
|
1568
|
+
: std::log10(std::max(1e-6, std::abs(val)));
|
|
1569
|
+
switch (int(l)) {
|
|
1570
|
+
case 0:
|
|
1571
|
+
case 1:
|
|
1572
|
+
case 2:
|
|
1573
|
+
case 3:
|
|
1574
|
+
std::snprintf(printString.data(), printString.size(), "%.10g%s", val,
|
|
1575
|
+
trailingStr);
|
|
1576
|
+
break;
|
|
1577
|
+
case 4:
|
|
1578
|
+
std::snprintf(printString.data(), printString.size(), "%.11g%s", val,
|
|
1579
|
+
trailingStr);
|
|
1580
|
+
break;
|
|
1581
|
+
case 5:
|
|
1582
|
+
std::snprintf(printString.data(), printString.size(), "%.12g%s", val,
|
|
1583
|
+
trailingStr);
|
|
1584
|
+
break;
|
|
1585
|
+
case 6:
|
|
1586
|
+
case 7:
|
|
1587
|
+
case 8:
|
|
1588
|
+
case 9:
|
|
1589
|
+
case 10:
|
|
1590
|
+
std::snprintf(printString.data(), printString.size(), "%.13g%s", val,
|
|
1591
|
+
trailingStr);
|
|
1592
|
+
break;
|
|
1593
|
+
default:
|
|
1594
|
+
std::snprintf(printString.data(), printString.size(), "%.9g%s", val,
|
|
1595
|
+
trailingStr);
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
return printString;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
void HighsMipSolverData::printSolutionSourceKey() const {
|
|
1602
|
+
std::stringstream ss;
|
|
1603
|
+
// Last MipSolutionSource enum is kSolutionSourceCleanup - which is
|
|
1604
|
+
// not a solution source, but used to force the last logging line to
|
|
1605
|
+
// be printed
|
|
1606
|
+
const int last_enum = kSolutionSourceCount - 1;
|
|
1607
|
+
// Set the index of the last solution source to be printed in each
|
|
1608
|
+
// line of the key. Four or five can be printed, depending on the
|
|
1609
|
+
// lengths of the solution source strings in that line
|
|
1610
|
+
std::vector<int> limits = {4, 9, 14, last_enum};
|
|
1611
|
+
assert(last_enum > limits[limits.size() - 2]);
|
|
1612
|
+
|
|
1613
|
+
ss.str(std::string());
|
|
1614
|
+
for (int k = 0; k < limits[0]; k++) {
|
|
1615
|
+
if (k == 0) {
|
|
1616
|
+
ss << "\nSrc: ";
|
|
1617
|
+
} else {
|
|
1618
|
+
ss << "; ";
|
|
1619
|
+
}
|
|
1620
|
+
ss << solutionSourceToString(k) << " => "
|
|
1621
|
+
<< solutionSourceToString(k, false);
|
|
1622
|
+
}
|
|
1623
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
1624
|
+
"%s;\n", ss.str().c_str());
|
|
1625
|
+
int to_line = limits.size() - 1;
|
|
1626
|
+
for (int line = 0; line < to_line; line++) {
|
|
1627
|
+
ss.str(std::string());
|
|
1628
|
+
for (int k = limits[line]; k < limits[line + 1]; k++) {
|
|
1629
|
+
if (k == limits[line]) {
|
|
1630
|
+
ss << " ";
|
|
1631
|
+
} else {
|
|
1632
|
+
ss << "; ";
|
|
1633
|
+
}
|
|
1634
|
+
ss << solutionSourceToString(k) << " => "
|
|
1635
|
+
<< solutionSourceToString(k, false);
|
|
1636
|
+
}
|
|
1637
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
1638
|
+
"%s%s\n", ss.str().c_str(), line < to_line - 1 ? ";" : "");
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
void HighsMipSolverData::printDisplayLine(const int solution_source) {
|
|
1643
|
+
// MIP logging method
|
|
1644
|
+
//
|
|
1645
|
+
// Note that if the original problem is a maximization, the cost
|
|
1646
|
+
// coefficients are negated so that the MIP solver only solves a
|
|
1647
|
+
// minimization. Hence, in preparing to print the display line, the
|
|
1648
|
+
// dual bound (lb) is always less than the primal bound (ub). When
|
|
1649
|
+
// printed, the sense of the optimization is applied so that the
|
|
1650
|
+
// values printed correspond to the original objective.
|
|
1651
|
+
|
|
1652
|
+
// No point in computing all the logging values if logging is off
|
|
1653
|
+
bool output_flag = *mipsolver.options_mip_->log_options.output_flag;
|
|
1654
|
+
if (!output_flag) return;
|
|
1655
|
+
|
|
1656
|
+
bool timeless_log = mipsolver.options_mip_->timeless_log;
|
|
1657
|
+
disptime = timeless_log ? disptime + 1 : mipsolver.timer_.read();
|
|
1658
|
+
if (solution_source == kSolutionSourceNone &&
|
|
1659
|
+
disptime - last_disptime <
|
|
1660
|
+
mipsolver.options_mip_->mip_min_logging_interval)
|
|
1661
|
+
return;
|
|
1662
|
+
last_disptime = disptime;
|
|
1663
|
+
std::string time_string =
|
|
1664
|
+
timeless_log ? "" : highsFormatToString(" %7.1fs", disptime);
|
|
1665
|
+
|
|
1666
|
+
if (num_disp_lines % 20 == 0) {
|
|
1667
|
+
if (num_disp_lines == 0) printSolutionSourceKey();
|
|
1668
|
+
std::string work_string0 = timeless_log ? " Work" : " Work ";
|
|
1669
|
+
std::string work_string1 = timeless_log ? "LpIters" : "LpIters Time";
|
|
1670
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
1671
|
+
// clang-format off
|
|
1672
|
+
"\n Nodes | B&B Tree | Objective Bounds | Dynamic Constraints | %s\n"
|
|
1673
|
+
"Src Proc. InQueue | Leaves Expl. | BestBound BestSol Gap | Cuts InLp Confl. | %s\n\n",
|
|
1674
|
+
// clang-format on
|
|
1675
|
+
work_string0.c_str(), work_string1.c_str());
|
|
1676
|
+
|
|
1677
|
+
//" %7s | %10s | %10s | %10s | %10s | %-15s | %-15s | %7s | %7s "
|
|
1678
|
+
//"| %8s | %8s\n",
|
|
1679
|
+
//"time", "open nodes", "nodes", "leaves", "lpiters", "dual bound",
|
|
1680
|
+
//"primal bound", "cutpool", "confl.", "gap", "explored");
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
++num_disp_lines;
|
|
1684
|
+
|
|
1685
|
+
auto print_nodes = convertToPrintString(num_nodes);
|
|
1686
|
+
auto queue_nodes = convertToPrintString(nodequeue.numActiveNodes());
|
|
1687
|
+
auto print_leaves = convertToPrintString(num_leaves - num_leaves_before_run);
|
|
1688
|
+
|
|
1689
|
+
double explored = 100 * double(pruned_treeweight);
|
|
1690
|
+
|
|
1691
|
+
double lb;
|
|
1692
|
+
double ub;
|
|
1693
|
+
double gap = limitsToGap(lower_bound, upper_bound, lb, ub);
|
|
1694
|
+
gap *= 1e2;
|
|
1695
|
+
if (mipsolver.options_mip_->objective_bound < ub)
|
|
1696
|
+
ub = mipsolver.options_mip_->objective_bound;
|
|
1697
|
+
|
|
1698
|
+
auto print_lp_iters = convertToPrintString(total_lp_iterations);
|
|
1699
|
+
HighsInt dynamic_constraints_in_lp =
|
|
1700
|
+
lp.numRows() > 0 ? lp.numRows() - lp.getNumModelRows() : 0;
|
|
1701
|
+
if (upper_bound != kHighsInf) {
|
|
1702
|
+
std::array<char, 22> gap_string = {};
|
|
1703
|
+
if (gap >= 9999.)
|
|
1704
|
+
std::strcpy(gap_string.data(), "Large");
|
|
1705
|
+
else
|
|
1706
|
+
std::snprintf(gap_string.data(), gap_string.size(), "%.2f%%", gap);
|
|
1707
|
+
|
|
1708
|
+
std::array<char, 22> ub_string;
|
|
1709
|
+
if (mipsolver.options_mip_->objective_bound < ub) {
|
|
1710
|
+
ub_string =
|
|
1711
|
+
convertToPrintString((int)mipsolver.orig_model_->sense_ * ub, "*");
|
|
1712
|
+
} else
|
|
1713
|
+
ub_string = convertToPrintString((int)mipsolver.orig_model_->sense_ * ub);
|
|
1714
|
+
|
|
1715
|
+
auto lb_string =
|
|
1716
|
+
convertToPrintString((int)mipsolver.orig_model_->sense_ * lb);
|
|
1717
|
+
|
|
1718
|
+
highsLogUser(
|
|
1719
|
+
mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
1720
|
+
// clang-format off
|
|
1721
|
+
" %s %7s %7s %7s %6.2f%% %-15s %-15s %8s %6" HIGHSINT_FORMAT " %6" HIGHSINT_FORMAT " %6" HIGHSINT_FORMAT " %7s%s\n",
|
|
1722
|
+
// clang-format on
|
|
1723
|
+
solutionSourceToString(solution_source).c_str(), print_nodes.data(),
|
|
1724
|
+
queue_nodes.data(), print_leaves.data(), explored, lb_string.data(),
|
|
1725
|
+
ub_string.data(), gap_string.data(), cutpool.getNumCuts(),
|
|
1726
|
+
dynamic_constraints_in_lp, conflictPool.getNumConflicts(),
|
|
1727
|
+
print_lp_iters.data(), time_string.c_str());
|
|
1728
|
+
} else {
|
|
1729
|
+
std::array<char, 22> ub_string;
|
|
1730
|
+
if (mipsolver.options_mip_->objective_bound < ub) {
|
|
1731
|
+
ub_string =
|
|
1732
|
+
convertToPrintString((int)mipsolver.orig_model_->sense_ * ub, "*");
|
|
1733
|
+
} else
|
|
1734
|
+
ub_string = convertToPrintString((int)mipsolver.orig_model_->sense_ * ub);
|
|
1735
|
+
|
|
1736
|
+
auto lb_string =
|
|
1737
|
+
convertToPrintString((int)mipsolver.orig_model_->sense_ * lb);
|
|
1738
|
+
|
|
1739
|
+
highsLogUser(
|
|
1740
|
+
mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
1741
|
+
// clang-format off
|
|
1742
|
+
" %s %7s %7s %7s %6.2f%% %-15s %-15s %8.2f %6" HIGHSINT_FORMAT " %6" HIGHSINT_FORMAT " %6" HIGHSINT_FORMAT " %7s%s\n",
|
|
1743
|
+
// clang-format on
|
|
1744
|
+
solutionSourceToString(solution_source).c_str(), print_nodes.data(),
|
|
1745
|
+
queue_nodes.data(), print_leaves.data(), explored, lb_string.data(),
|
|
1746
|
+
ub_string.data(), gap, cutpool.getNumCuts(), dynamic_constraints_in_lp,
|
|
1747
|
+
conflictPool.getNumConflicts(), print_lp_iters.data(),
|
|
1748
|
+
time_string.c_str());
|
|
1749
|
+
}
|
|
1750
|
+
// Check that limitsToBounds yields the same values for the
|
|
1751
|
+
// dual_bound, primal_bound (modulo optimization sense) and
|
|
1752
|
+
// mip_rel_gap
|
|
1753
|
+
double dual_bound;
|
|
1754
|
+
double primal_bound;
|
|
1755
|
+
double mip_rel_gap;
|
|
1756
|
+
limitsToBounds(dual_bound, primal_bound, mip_rel_gap);
|
|
1757
|
+
mip_rel_gap *= 1e2;
|
|
1758
|
+
assert(dual_bound == (int)mipsolver.orig_model_->sense_ * lb);
|
|
1759
|
+
assert(primal_bound == (int)mipsolver.orig_model_->sense_ * ub);
|
|
1760
|
+
assert(gap == mip_rel_gap);
|
|
1761
|
+
|
|
1762
|
+
// Possibly interrupt from MIP logging callback
|
|
1763
|
+
mipsolver.callback_->clearHighsCallbackOutput();
|
|
1764
|
+
const bool interrupt = interruptFromCallbackWithData(
|
|
1765
|
+
kCallbackMipLogging, mipsolver.solution_objective_, "MIP logging");
|
|
1766
|
+
assert(!interrupt);
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
bool HighsMipSolverData::rootSeparationRound(
|
|
1770
|
+
HighsSeparation& sepa, HighsInt& ncuts, HighsLpRelaxation::Status& status) {
|
|
1771
|
+
int64_t tmpLpIters = -lp.getNumLpIterations();
|
|
1772
|
+
ncuts = sepa.separationRound(domain, status);
|
|
1773
|
+
tmpLpIters += lp.getNumLpIterations();
|
|
1774
|
+
avgrootlpiters = lp.getAvgSolveIters();
|
|
1775
|
+
total_lp_iterations += tmpLpIters;
|
|
1776
|
+
sepa_lp_iterations += tmpLpIters;
|
|
1777
|
+
|
|
1778
|
+
status = evaluateRootLp();
|
|
1779
|
+
if (status == HighsLpRelaxation::Status::kInfeasible) return true;
|
|
1780
|
+
|
|
1781
|
+
const std::vector<double>& solvals = lp.getLpSolver().getSolution().col_value;
|
|
1782
|
+
|
|
1783
|
+
if (mipsolver.submip || incumbent.empty()) {
|
|
1784
|
+
heuristics.randomizedRounding(solvals);
|
|
1785
|
+
if (mipsolver.options_mip_->mip_heuristic_run_shifting)
|
|
1786
|
+
heuristics.shifting(solvals);
|
|
1787
|
+
heuristics.flushStatistics();
|
|
1788
|
+
status = evaluateRootLp();
|
|
1789
|
+
if (status == HighsLpRelaxation::Status::kInfeasible) return true;
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
return false;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
HighsLpRelaxation::Status HighsMipSolverData::evaluateRootLp() {
|
|
1796
|
+
do {
|
|
1797
|
+
domain.propagate();
|
|
1798
|
+
|
|
1799
|
+
if (globalOrbits && !domain.infeasible())
|
|
1800
|
+
globalOrbits->orbitalFixing(domain);
|
|
1801
|
+
|
|
1802
|
+
if (domain.infeasible()) {
|
|
1803
|
+
updateLowerBound(std::min(kHighsInf, upper_bound));
|
|
1804
|
+
pruned_treeweight = 1.0;
|
|
1805
|
+
num_nodes += 1;
|
|
1806
|
+
num_leaves += 1;
|
|
1807
|
+
return HighsLpRelaxation::Status::kInfeasible;
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
bool lpBoundsChanged = false;
|
|
1811
|
+
if (!domain.getChangedCols().empty()) {
|
|
1812
|
+
lpBoundsChanged = true;
|
|
1813
|
+
removeFixedIndices();
|
|
1814
|
+
lp.flushDomain(domain);
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
bool lpWasSolved = false;
|
|
1818
|
+
HighsLpRelaxation::Status status;
|
|
1819
|
+
if (lpBoundsChanged ||
|
|
1820
|
+
lp.getLpSolver().getModelStatus() == HighsModelStatus::kNotset) {
|
|
1821
|
+
int64_t lpIters = -lp.getNumLpIterations();
|
|
1822
|
+
status = lp.resolveLp(&domain);
|
|
1823
|
+
lpIters += lp.getNumLpIterations();
|
|
1824
|
+
total_lp_iterations += lpIters;
|
|
1825
|
+
avgrootlpiters = lp.getAvgSolveIters();
|
|
1826
|
+
lpWasSolved = true;
|
|
1827
|
+
|
|
1828
|
+
if (status == HighsLpRelaxation::Status::kUnbounded) {
|
|
1829
|
+
if (mipsolver.solution_.empty())
|
|
1830
|
+
mipsolver.modelstatus_ = HighsModelStatus::kUnboundedOrInfeasible;
|
|
1831
|
+
else
|
|
1832
|
+
mipsolver.modelstatus_ = HighsModelStatus::kUnbounded;
|
|
1833
|
+
|
|
1834
|
+
pruned_treeweight = 1.0;
|
|
1835
|
+
num_nodes += 1;
|
|
1836
|
+
num_leaves += 1;
|
|
1837
|
+
return status;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
if (status == HighsLpRelaxation::Status::kOptimal &&
|
|
1841
|
+
lp.getFractionalIntegers().empty() &&
|
|
1842
|
+
addIncumbent(lp.getLpSolver().getSolution().col_value,
|
|
1843
|
+
lp.getObjective(), kSolutionSourceEvaluateNode)) {
|
|
1844
|
+
mipsolver.modelstatus_ = HighsModelStatus::kOptimal;
|
|
1845
|
+
updateLowerBound(upper_bound);
|
|
1846
|
+
pruned_treeweight = 1.0;
|
|
1847
|
+
num_nodes += 1;
|
|
1848
|
+
num_leaves += 1;
|
|
1849
|
+
return HighsLpRelaxation::Status::kInfeasible;
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
if (status == HighsLpRelaxation::Status::kOptimal &&
|
|
1853
|
+
mipsolver.options_mip_->mip_heuristic_run_zi_round)
|
|
1854
|
+
heuristics.ziRound(lp.getLpSolver().getSolution().col_value);
|
|
1855
|
+
|
|
1856
|
+
} else
|
|
1857
|
+
status = lp.getStatus();
|
|
1858
|
+
|
|
1859
|
+
if (status == HighsLpRelaxation::Status::kInfeasible) {
|
|
1860
|
+
updateLowerBound(std::min(kHighsInf, upper_bound));
|
|
1861
|
+
pruned_treeweight = 1.0;
|
|
1862
|
+
num_nodes += 1;
|
|
1863
|
+
num_leaves += 1;
|
|
1864
|
+
return status;
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
if (lp.unscaledDualFeasible(lp.getStatus())) {
|
|
1868
|
+
updateLowerBound(std::max(lp.getObjective(), lower_bound));
|
|
1869
|
+
|
|
1870
|
+
if (lpWasSolved) {
|
|
1871
|
+
redcostfixing.addRootRedcost(mipsolver,
|
|
1872
|
+
lp.getLpSolver().getSolution().col_dual,
|
|
1873
|
+
lp.getObjective());
|
|
1874
|
+
if (upper_limit != kHighsInf)
|
|
1875
|
+
redcostfixing.propagateRootRedcost(mipsolver);
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
if (lower_bound > optimality_limit) {
|
|
1880
|
+
pruned_treeweight = 1.0;
|
|
1881
|
+
num_nodes += 1;
|
|
1882
|
+
num_leaves += 1;
|
|
1883
|
+
return HighsLpRelaxation::Status::kInfeasible;
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
if (domain.getChangedCols().empty()) return status;
|
|
1887
|
+
} while (true);
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
static void clockOff(HighsMipAnalysis& analysis) {
|
|
1891
|
+
if (!analysis.analyse_mip_time) return;
|
|
1892
|
+
// Make sure that exactly one of the following clocks is running
|
|
1893
|
+
const int clock0_running =
|
|
1894
|
+
analysis.mipTimerRunning(kMipClockEvaluateRootNode0) ? 1 : 0;
|
|
1895
|
+
const int clock1_running =
|
|
1896
|
+
analysis.mipTimerRunning(kMipClockEvaluateRootNode1) ? 1 : 0;
|
|
1897
|
+
const int clock2_running =
|
|
1898
|
+
analysis.mipTimerRunning(kMipClockEvaluateRootNode2) ? 1 : 0;
|
|
1899
|
+
const bool one_running = clock0_running + clock1_running + clock2_running;
|
|
1900
|
+
if (!one_running)
|
|
1901
|
+
printf("HighsMipSolverData::clockOff Clocks running are (%d; %d; %d)\n",
|
|
1902
|
+
clock0_running, clock1_running, clock2_running);
|
|
1903
|
+
assert(one_running);
|
|
1904
|
+
if (clock0_running) analysis.mipTimerStop(kMipClockEvaluateRootNode0);
|
|
1905
|
+
if (clock1_running) analysis.mipTimerStop(kMipClockEvaluateRootNode1);
|
|
1906
|
+
if (clock2_running) analysis.mipTimerStop(kMipClockEvaluateRootNode2);
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
void HighsMipSolverData::evaluateRootNode() {
|
|
1910
|
+
const bool compute_analytic_centre = true;
|
|
1911
|
+
if (!compute_analytic_centre) printf("NOT COMPUTING ANALYTIC CENTRE!\n");
|
|
1912
|
+
HighsInt maxSepaRounds = mipsolver.submip ? 5 : kHighsIInf;
|
|
1913
|
+
if (numRestarts == 0)
|
|
1914
|
+
maxSepaRounds =
|
|
1915
|
+
std::min(HighsInt(2 * std::sqrt(maxTreeSizeLog2)), maxSepaRounds);
|
|
1916
|
+
std::unique_ptr<SymmetryDetectionData> symData;
|
|
1917
|
+
highs::parallel::TaskGroup tg;
|
|
1918
|
+
HighsMipAnalysis& analysis = mipsolver.analysis_;
|
|
1919
|
+
restart:
|
|
1920
|
+
analysis.mipTimerStart(kMipClockEvaluateRootNode0);
|
|
1921
|
+
|
|
1922
|
+
if (detectSymmetries) {
|
|
1923
|
+
analysis.mipTimerStart(kMipClockStartSymmetryDetection);
|
|
1924
|
+
startSymmetryDetection(tg, symData);
|
|
1925
|
+
analysis.mipTimerStop(kMipClockStartSymmetryDetection);
|
|
1926
|
+
}
|
|
1927
|
+
if (compute_analytic_centre && !analyticCenterComputed) {
|
|
1928
|
+
if (analysis.analyse_mip_time)
|
|
1929
|
+
highsLogUser(
|
|
1930
|
+
mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
1931
|
+
"MIP-Timing: %11.2g - starting analytic centre calculation\n",
|
|
1932
|
+
mipsolver.timer_.read());
|
|
1933
|
+
analysis.mipTimerStart(kMipClockStartAnalyticCentreComputation);
|
|
1934
|
+
startAnalyticCenterComputation(tg);
|
|
1935
|
+
analysis.mipTimerStop(kMipClockStartAnalyticCentreComputation);
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
// lp.getLpSolver().setOptionValue(
|
|
1939
|
+
// "dual_simplex_cost_perturbation_multiplier", 10.0);
|
|
1940
|
+
lp.setIterationLimit();
|
|
1941
|
+
lp.loadModel();
|
|
1942
|
+
domain.clearChangedCols();
|
|
1943
|
+
lp.setObjectiveLimit(upper_limit);
|
|
1944
|
+
|
|
1945
|
+
updateLowerBound(std::max(lower_bound, domain.getObjectiveLowerBound()));
|
|
1946
|
+
|
|
1947
|
+
printDisplayLine();
|
|
1948
|
+
|
|
1949
|
+
// Possibly query existence of an external solution
|
|
1950
|
+
if (!mipsolver.submip)
|
|
1951
|
+
mipsolver.mipdata_->queryExternalSolution(
|
|
1952
|
+
mipsolver.solution_objective_,
|
|
1953
|
+
kExternalMipSolutionQueryOriginEvaluateRootNode0);
|
|
1954
|
+
|
|
1955
|
+
// check if only root presolve is allowed
|
|
1956
|
+
if (firstrootbasis.valid)
|
|
1957
|
+
lp.getLpSolver().setBasis(firstrootbasis,
|
|
1958
|
+
"HighsMipSolverData::evaluateRootNode");
|
|
1959
|
+
else if (mipsolver.options_mip_->mip_root_presolve_only)
|
|
1960
|
+
lp.getLpSolver().setOptionValue("presolve", kHighsOffString);
|
|
1961
|
+
else
|
|
1962
|
+
lp.getLpSolver().setOptionValue("presolve", kHighsOnString);
|
|
1963
|
+
if (mipsolver.options_mip_->highs_debug_level)
|
|
1964
|
+
lp.getLpSolver().setOptionValue("output_flag",
|
|
1965
|
+
mipsolver.options_mip_->output_flag);
|
|
1966
|
+
// lp.getLpSolver().setOptionValue("log_dev_level", kHighsLogDevLevelInfo);
|
|
1967
|
+
// lp.getLpSolver().setOptionValue("log_file",
|
|
1968
|
+
// mipsolver.options_mip_->log_file);
|
|
1969
|
+
|
|
1970
|
+
analysis.mipTimerStart(kMipClockEvaluateRootLp);
|
|
1971
|
+
HighsLpRelaxation::Status status = evaluateRootLp();
|
|
1972
|
+
analysis.mipTimerStop(kMipClockEvaluateRootLp);
|
|
1973
|
+
if (numRestarts == 0) firstrootlpiters = total_lp_iterations;
|
|
1974
|
+
|
|
1975
|
+
lp.getLpSolver().setOptionValue("output_flag", false);
|
|
1976
|
+
lp.getLpSolver().setOptionValue("presolve", kHighsOffString);
|
|
1977
|
+
lp.getLpSolver().setOptionValue("parallel", kHighsOffString);
|
|
1978
|
+
|
|
1979
|
+
if (status == HighsLpRelaxation::Status::kInfeasible ||
|
|
1980
|
+
status == HighsLpRelaxation::Status::kUnbounded)
|
|
1981
|
+
return clockOff(analysis);
|
|
1982
|
+
|
|
1983
|
+
firstlpsol = lp.getSolution().col_value;
|
|
1984
|
+
firstlpsolobj = lp.getObjective();
|
|
1985
|
+
rootlpsolobj = firstlpsolobj;
|
|
1986
|
+
|
|
1987
|
+
if (lp.getLpSolver().getBasis().valid && lp.numRows() == mipsolver.numRow())
|
|
1988
|
+
firstrootbasis = lp.getLpSolver().getBasis();
|
|
1989
|
+
else {
|
|
1990
|
+
// the root basis is later expected to be consistent for the model without
|
|
1991
|
+
// cuts so set it to the slack basis if the current basis already includes
|
|
1992
|
+
// cuts, e.g. due to a restart
|
|
1993
|
+
firstrootbasis.col_status.assign(mipsolver.numCol(),
|
|
1994
|
+
HighsBasisStatus::kNonbasic);
|
|
1995
|
+
firstrootbasis.row_status.assign(mipsolver.numRow(),
|
|
1996
|
+
HighsBasisStatus::kBasic);
|
|
1997
|
+
firstrootbasis.valid = true;
|
|
1998
|
+
firstrootbasis.useful = true;
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
if (cutpool.getNumCuts() != 0) {
|
|
2002
|
+
assert(numRestarts != 0);
|
|
2003
|
+
HighsCutSet cutset;
|
|
2004
|
+
analysis.mipTimerStart(kMipClockSeparateLpCuts);
|
|
2005
|
+
cutpool.separateLpCutsAfterRestart(cutset);
|
|
2006
|
+
analysis.mipTimerStop(kMipClockSeparateLpCuts);
|
|
2007
|
+
#ifdef HIGHS_DEBUGSOL
|
|
2008
|
+
for (HighsInt i = 0; i < cutset.numCuts(); ++i) {
|
|
2009
|
+
debugSolution.checkCut(cutset.ARindex_.data() + cutset.ARstart_[i],
|
|
2010
|
+
cutset.ARvalue_.data() + cutset.ARstart_[i],
|
|
2011
|
+
cutset.ARstart_[i + 1] - cutset.ARstart_[i],
|
|
2012
|
+
cutset.upper_[i]);
|
|
2013
|
+
}
|
|
2014
|
+
#endif
|
|
2015
|
+
lp.addCuts(cutset);
|
|
2016
|
+
analysis.mipTimerStart(kMipClockEvaluateRootLp);
|
|
2017
|
+
status = evaluateRootLp();
|
|
2018
|
+
analysis.mipTimerStop(kMipClockEvaluateRootLp);
|
|
2019
|
+
lp.removeObsoleteRows();
|
|
2020
|
+
if (status == HighsLpRelaxation::Status::kInfeasible)
|
|
2021
|
+
return clockOff(analysis);
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
lp.setIterationLimit(std::max(10000, int(10 * avgrootlpiters)));
|
|
2025
|
+
|
|
2026
|
+
// make sure first line after solving root LP is printed
|
|
2027
|
+
last_disptime = -kHighsInf;
|
|
2028
|
+
disptime = 0;
|
|
2029
|
+
|
|
2030
|
+
if (mipsolver.options_mip_->mip_heuristic_run_zi_round)
|
|
2031
|
+
heuristics.ziRound(firstlpsol);
|
|
2032
|
+
analysis.mipTimerStart(kMipClockRandomizedRounding);
|
|
2033
|
+
heuristics.randomizedRounding(firstlpsol);
|
|
2034
|
+
analysis.mipTimerStop(kMipClockRandomizedRounding);
|
|
2035
|
+
if (mipsolver.options_mip_->mip_heuristic_run_shifting)
|
|
2036
|
+
heuristics.shifting(firstlpsol);
|
|
2037
|
+
|
|
2038
|
+
heuristics.flushStatistics();
|
|
2039
|
+
|
|
2040
|
+
analysis.mipTimerStart(kMipClockEvaluateRootLp);
|
|
2041
|
+
status = evaluateRootLp();
|
|
2042
|
+
analysis.mipTimerStop(kMipClockEvaluateRootLp);
|
|
2043
|
+
if (status == HighsLpRelaxation::Status::kInfeasible)
|
|
2044
|
+
return clockOff(analysis);
|
|
2045
|
+
|
|
2046
|
+
rootlpsolobj = firstlpsolobj;
|
|
2047
|
+
removeFixedIndices();
|
|
2048
|
+
if (mipsolver.options_mip_->mip_allow_restart &&
|
|
2049
|
+
mipsolver.options_mip_->presolve != kHighsOffString) {
|
|
2050
|
+
double fixingRate = percentageInactiveIntegers();
|
|
2051
|
+
if (fixingRate >= 10.0) {
|
|
2052
|
+
tg.cancel();
|
|
2053
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
2054
|
+
"\n%.1f%% inactive integer columns, restarting\n",
|
|
2055
|
+
fixingRate);
|
|
2056
|
+
tg.taskWait();
|
|
2057
|
+
analysis.mipTimerStart(kMipClockPerformRestart);
|
|
2058
|
+
performRestart();
|
|
2059
|
+
analysis.mipTimerStop(kMipClockPerformRestart);
|
|
2060
|
+
++numRestartsRoot;
|
|
2061
|
+
if (mipsolver.modelstatus_ == HighsModelStatus::kNotset) {
|
|
2062
|
+
clockOff(analysis);
|
|
2063
|
+
goto restart;
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
return clockOff(analysis);
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
// begin separation
|
|
2071
|
+
if (analysis.analyse_mip_time) {
|
|
2072
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
2073
|
+
"MIP-Timing: %11.2g - starting separation\n",
|
|
2074
|
+
analysis.mip_clocks.timer_pointer_->read(0));
|
|
2075
|
+
fflush(stdout);
|
|
2076
|
+
}
|
|
2077
|
+
analysis.mipTimerStart(kMipClockRootSeparation);
|
|
2078
|
+
std::vector<double> avgdirection;
|
|
2079
|
+
std::vector<double> curdirection;
|
|
2080
|
+
avgdirection.resize(mipsolver.numCol());
|
|
2081
|
+
curdirection.resize(mipsolver.numCol());
|
|
2082
|
+
|
|
2083
|
+
HighsInt stall = 0;
|
|
2084
|
+
double smoothprogress = 0.0;
|
|
2085
|
+
HighsInt nseparounds = 0;
|
|
2086
|
+
HighsSeparation sepa(mipsolver);
|
|
2087
|
+
sepa.setLpRelaxation(&lp);
|
|
2088
|
+
|
|
2089
|
+
while (lp.scaledOptimal(status) && !lp.getFractionalIntegers().empty() &&
|
|
2090
|
+
stall < 3) {
|
|
2091
|
+
printDisplayLine();
|
|
2092
|
+
|
|
2093
|
+
if (checkLimits()) {
|
|
2094
|
+
analysis.mipTimerStop(kMipClockRootSeparation);
|
|
2095
|
+
return clockOff(analysis);
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
if (nseparounds == maxSepaRounds) break;
|
|
2099
|
+
|
|
2100
|
+
removeFixedIndices();
|
|
2101
|
+
|
|
2102
|
+
if (!mipsolver.submip &&
|
|
2103
|
+
mipsolver.options_mip_->presolve != kHighsOffString) {
|
|
2104
|
+
double fixingRate = percentageInactiveIntegers();
|
|
2105
|
+
if (fixingRate >= 10.0) {
|
|
2106
|
+
stall = -1;
|
|
2107
|
+
break;
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
++nseparounds;
|
|
2112
|
+
|
|
2113
|
+
HighsInt ncuts;
|
|
2114
|
+
|
|
2115
|
+
analysis.mipTimerStart(kMipClockRootSeparationRound);
|
|
2116
|
+
const bool root_separation_round_result =
|
|
2117
|
+
rootSeparationRound(sepa, ncuts, status);
|
|
2118
|
+
analysis.mipTimerStop(kMipClockRootSeparationRound);
|
|
2119
|
+
if (root_separation_round_result) {
|
|
2120
|
+
analysis.mipTimerStop(kMipClockRootSeparation);
|
|
2121
|
+
return clockOff(analysis);
|
|
2122
|
+
}
|
|
2123
|
+
if (nseparounds >= 5 && !mipsolver.submip && !analyticCenterComputed &&
|
|
2124
|
+
compute_analytic_centre) {
|
|
2125
|
+
if (checkLimits()) {
|
|
2126
|
+
analysis.mipTimerStop(kMipClockRootSeparation);
|
|
2127
|
+
return clockOff(analysis);
|
|
2128
|
+
}
|
|
2129
|
+
analysis.mipTimerStart(
|
|
2130
|
+
kMipClockRootSeparationFinishAnalyticCentreComputation);
|
|
2131
|
+
finishAnalyticCenterComputation(tg);
|
|
2132
|
+
analysis.mipTimerStop(
|
|
2133
|
+
kMipClockRootSeparationFinishAnalyticCentreComputation);
|
|
2134
|
+
|
|
2135
|
+
analysis.mipTimerStart(kMipClockRootSeparationCentralRounding);
|
|
2136
|
+
heuristics.centralRounding();
|
|
2137
|
+
analysis.mipTimerStop(kMipClockRootSeparationCentralRounding);
|
|
2138
|
+
|
|
2139
|
+
heuristics.flushStatistics();
|
|
2140
|
+
|
|
2141
|
+
if (checkLimits()) {
|
|
2142
|
+
analysis.mipTimerStop(kMipClockRootSeparation);
|
|
2143
|
+
return clockOff(analysis);
|
|
2144
|
+
}
|
|
2145
|
+
analysis.mipTimerStart(kMipClockRootSeparationEvaluateRootLp);
|
|
2146
|
+
status = evaluateRootLp();
|
|
2147
|
+
analysis.mipTimerStop(kMipClockRootSeparationEvaluateRootLp);
|
|
2148
|
+
if (status == HighsLpRelaxation::Status::kInfeasible) {
|
|
2149
|
+
analysis.mipTimerStop(kMipClockRootSeparation);
|
|
2150
|
+
return clockOff(analysis);
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
HighsCDouble sqrnorm = 0.0;
|
|
2155
|
+
const auto& solvals = lp.getSolution().col_value;
|
|
2156
|
+
|
|
2157
|
+
for (HighsInt i = 0; i != mipsolver.numCol(); ++i) {
|
|
2158
|
+
curdirection[i] = firstlpsol[i] - solvals[i];
|
|
2159
|
+
|
|
2160
|
+
// if (mip.integrality_[i] == 2 && lp.getObjective() > firstobj &&
|
|
2161
|
+
// std::abs(curdirection[i]) > 1e-6)
|
|
2162
|
+
// pseudocost.addObservation(i, -curdirection[i],
|
|
2163
|
+
// lp.getObjective() - firstobj);
|
|
2164
|
+
|
|
2165
|
+
sqrnorm += curdirection[i] * curdirection[i];
|
|
2166
|
+
}
|
|
2167
|
+
#if 1
|
|
2168
|
+
double scale = double(1.0 / sqrt(sqrnorm));
|
|
2169
|
+
sqrnorm = 0.0;
|
|
2170
|
+
HighsCDouble dotproduct = 0.0;
|
|
2171
|
+
for (HighsInt i = 0; i != mipsolver.numCol(); ++i) {
|
|
2172
|
+
avgdirection[i] =
|
|
2173
|
+
(scale * curdirection[i] - avgdirection[i]) / nseparounds;
|
|
2174
|
+
sqrnorm += avgdirection[i] * avgdirection[i];
|
|
2175
|
+
dotproduct += avgdirection[i] * curdirection[i];
|
|
2176
|
+
}
|
|
2177
|
+
#endif
|
|
2178
|
+
|
|
2179
|
+
double progress = double(dotproduct / sqrt(sqrnorm));
|
|
2180
|
+
|
|
2181
|
+
if (nseparounds == 1) {
|
|
2182
|
+
smoothprogress = progress;
|
|
2183
|
+
} else {
|
|
2184
|
+
double alpha = 1.0 / 3.0;
|
|
2185
|
+
double nextprogress = (1.0 - alpha) * smoothprogress + alpha * progress;
|
|
2186
|
+
|
|
2187
|
+
if (nextprogress < smoothprogress * 1.01 &&
|
|
2188
|
+
(lp.getObjective() - firstlpsolobj) <=
|
|
2189
|
+
(rootlpsolobj - firstlpsolobj) * 1.001)
|
|
2190
|
+
++stall;
|
|
2191
|
+
else {
|
|
2192
|
+
stall = 0;
|
|
2193
|
+
}
|
|
2194
|
+
smoothprogress = nextprogress;
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
rootlpsolobj = lp.getObjective();
|
|
2198
|
+
lp.setIterationLimit(std::max(10000, int(10 * avgrootlpiters)));
|
|
2199
|
+
if (ncuts == 0) break;
|
|
2200
|
+
|
|
2201
|
+
// Possibly query existence of an external solution
|
|
2202
|
+
if (!mipsolver.submip)
|
|
2203
|
+
mipsolver.mipdata_->queryExternalSolution(
|
|
2204
|
+
mipsolver.solution_objective_,
|
|
2205
|
+
kExternalMipSolutionQueryOriginEvaluateRootNode1);
|
|
2206
|
+
}
|
|
2207
|
+
analysis.mipTimerStop(kMipClockRootSeparation);
|
|
2208
|
+
if (analysis.analyse_mip_time) {
|
|
2209
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
2210
|
+
"MIP-Timing: %11.2g - completed separation\n",
|
|
2211
|
+
analysis.mip_clocks.timer_pointer_->read(0));
|
|
2212
|
+
fflush(stdout);
|
|
2213
|
+
}
|
|
2214
|
+
|
|
2215
|
+
lp.setIterationLimit();
|
|
2216
|
+
analysis.mipTimerStart(kMipClockEvaluateRootLp);
|
|
2217
|
+
status = evaluateRootLp();
|
|
2218
|
+
analysis.mipTimerStop(kMipClockEvaluateRootLp);
|
|
2219
|
+
if (status == HighsLpRelaxation::Status::kInfeasible)
|
|
2220
|
+
return clockOff(analysis);
|
|
2221
|
+
|
|
2222
|
+
rootlpsol = lp.getLpSolver().getSolution().col_value;
|
|
2223
|
+
rootlpsolobj = lp.getObjective();
|
|
2224
|
+
lp.setIterationLimit(std::max(10000, int(10 * avgrootlpiters)));
|
|
2225
|
+
|
|
2226
|
+
if (mipsolver.options_mip_->mip_heuristic_run_zi_round) {
|
|
2227
|
+
heuristics.ziRound(firstlpsol);
|
|
2228
|
+
heuristics.flushStatistics();
|
|
2229
|
+
}
|
|
2230
|
+
if (mipsolver.options_mip_->mip_heuristic_run_shifting) {
|
|
2231
|
+
heuristics.shifting(rootlpsol);
|
|
2232
|
+
heuristics.flushStatistics();
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
if (!analyticCenterComputed && compute_analytic_centre) {
|
|
2236
|
+
if (checkLimits()) return clockOff(analysis);
|
|
2237
|
+
|
|
2238
|
+
analysis.mipTimerStart(kMipClockFinishAnalyticCentreComputation);
|
|
2239
|
+
finishAnalyticCenterComputation(tg);
|
|
2240
|
+
analysis.mipTimerStop(kMipClockFinishAnalyticCentreComputation);
|
|
2241
|
+
|
|
2242
|
+
analysis.mipTimerStart(kMipClockRootCentralRounding);
|
|
2243
|
+
heuristics.centralRounding();
|
|
2244
|
+
analysis.mipTimerStop(kMipClockRootCentralRounding);
|
|
2245
|
+
|
|
2246
|
+
heuristics.flushStatistics();
|
|
2247
|
+
|
|
2248
|
+
// if there are new global bound changes we re-evaluate the LP and do one
|
|
2249
|
+
// more separation round
|
|
2250
|
+
if (checkLimits()) return clockOff(analysis);
|
|
2251
|
+
bool separate = !domain.getChangedCols().empty();
|
|
2252
|
+
analysis.mipTimerStart(kMipClockEvaluateRootLp);
|
|
2253
|
+
status = evaluateRootLp();
|
|
2254
|
+
analysis.mipTimerStop(kMipClockEvaluateRootLp);
|
|
2255
|
+
if (status == HighsLpRelaxation::Status::kInfeasible)
|
|
2256
|
+
return clockOff(analysis);
|
|
2257
|
+
if (separate && lp.scaledOptimal(status)) {
|
|
2258
|
+
HighsInt ncuts;
|
|
2259
|
+
analysis.mipTimerStart(kMipClockRootSeparationRound0);
|
|
2260
|
+
const bool root_separation_round_result =
|
|
2261
|
+
rootSeparationRound(sepa, ncuts, status);
|
|
2262
|
+
analysis.mipTimerStop(kMipClockRootSeparationRound0);
|
|
2263
|
+
if (root_separation_round_result) return clockOff(analysis);
|
|
2264
|
+
++nseparounds;
|
|
2265
|
+
printDisplayLine();
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
printDisplayLine();
|
|
2270
|
+
// Possibly query existence of an external solution
|
|
2271
|
+
if (!mipsolver.submip)
|
|
2272
|
+
mipsolver.mipdata_->queryExternalSolution(
|
|
2273
|
+
mipsolver.solution_objective_,
|
|
2274
|
+
kExternalMipSolutionQueryOriginEvaluateRootNode2);
|
|
2275
|
+
|
|
2276
|
+
// Possible cut extraction callback
|
|
2277
|
+
if (!mipsolver.submip && mipsolver.callback_->user_callback &&
|
|
2278
|
+
mipsolver.callback_->callbackActive(kCallbackMipGetCutPool))
|
|
2279
|
+
mipsolver.callbackGetCutPool();
|
|
2280
|
+
if (checkLimits()) return clockOff(analysis);
|
|
2281
|
+
|
|
2282
|
+
analysis.mipTimerStop(kMipClockEvaluateRootNode0);
|
|
2283
|
+
analysis.mipTimerStart(kMipClockEvaluateRootNode1);
|
|
2284
|
+
do {
|
|
2285
|
+
if (rootlpsol.empty()) break;
|
|
2286
|
+
if (upper_limit != kHighsInf && !moreHeuristicsAllowed()) break;
|
|
2287
|
+
|
|
2288
|
+
if (mipsolver.options_mip_->mip_heuristic_run_root_reduced_cost) {
|
|
2289
|
+
analysis.mipTimerStart(kMipClockRootHeuristicsReducedCost);
|
|
2290
|
+
heuristics.rootReducedCost();
|
|
2291
|
+
analysis.mipTimerStop(kMipClockRootHeuristicsReducedCost);
|
|
2292
|
+
heuristics.flushStatistics();
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
if (checkLimits()) return clockOff(analysis);
|
|
2296
|
+
|
|
2297
|
+
// if there are new global bound changes we re-evaluate the LP and do one
|
|
2298
|
+
// more separation round
|
|
2299
|
+
bool separate = !domain.getChangedCols().empty();
|
|
2300
|
+
analysis.mipTimerStart(kMipClockEvaluateRootLp);
|
|
2301
|
+
status = evaluateRootLp();
|
|
2302
|
+
analysis.mipTimerStop(kMipClockEvaluateRootLp);
|
|
2303
|
+
if (status == HighsLpRelaxation::Status::kInfeasible)
|
|
2304
|
+
return clockOff(analysis);
|
|
2305
|
+
if (separate && lp.scaledOptimal(status)) {
|
|
2306
|
+
HighsInt ncuts;
|
|
2307
|
+
analysis.mipTimerStart(kMipClockRootSeparationRound1);
|
|
2308
|
+
const bool root_separation_round_result =
|
|
2309
|
+
rootSeparationRound(sepa, ncuts, status);
|
|
2310
|
+
analysis.mipTimerStop(kMipClockRootSeparationRound1);
|
|
2311
|
+
if (root_separation_round_result) return clockOff(analysis);
|
|
2312
|
+
++nseparounds;
|
|
2313
|
+
printDisplayLine();
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
if (upper_limit != kHighsInf && !moreHeuristicsAllowed()) break;
|
|
2317
|
+
|
|
2318
|
+
if (checkLimits()) return clockOff(analysis);
|
|
2319
|
+
if (mipsolver.options_mip_->mip_heuristic_run_rens) {
|
|
2320
|
+
analysis.mipTimerStart(kMipClockRootHeuristicsRens);
|
|
2321
|
+
heuristics.RENS(rootlpsol);
|
|
2322
|
+
analysis.mipTimerStop(kMipClockRootHeuristicsRens);
|
|
2323
|
+
heuristics.flushStatistics();
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
if (checkLimits()) return clockOff(analysis);
|
|
2327
|
+
// if there are new global bound changes we re-evaluate the LP and do one
|
|
2328
|
+
// more separation round
|
|
2329
|
+
separate = !domain.getChangedCols().empty();
|
|
2330
|
+
analysis.mipTimerStart(kMipClockEvaluateRootLp);
|
|
2331
|
+
status = evaluateRootLp();
|
|
2332
|
+
analysis.mipTimerStop(kMipClockEvaluateRootLp);
|
|
2333
|
+
if (status == HighsLpRelaxation::Status::kInfeasible)
|
|
2334
|
+
return clockOff(analysis);
|
|
2335
|
+
if (separate && lp.scaledOptimal(status)) {
|
|
2336
|
+
HighsInt ncuts;
|
|
2337
|
+
analysis.mipTimerStart(kMipClockRootSeparationRound2);
|
|
2338
|
+
const bool root_separation_round_result =
|
|
2339
|
+
rootSeparationRound(sepa, ncuts, status);
|
|
2340
|
+
analysis.mipTimerStop(kMipClockRootSeparationRound2);
|
|
2341
|
+
if (root_separation_round_result) return clockOff(analysis);
|
|
2342
|
+
++nseparounds;
|
|
2343
|
+
|
|
2344
|
+
printDisplayLine();
|
|
2345
|
+
// Possibly query existence of an external solution
|
|
2346
|
+
if (!mipsolver.submip)
|
|
2347
|
+
mipsolver.mipdata_->queryExternalSolution(
|
|
2348
|
+
mipsolver.solution_objective_,
|
|
2349
|
+
kExternalMipSolutionQueryOriginEvaluateRootNode3);
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2352
|
+
if (upper_limit != kHighsInf || mipsolver.submip) break;
|
|
2353
|
+
|
|
2354
|
+
if (checkLimits()) return clockOff(analysis);
|
|
2355
|
+
analysis.mipTimerStart(kMipClockRootFeasibilityPump);
|
|
2356
|
+
heuristics.feasibilityPump();
|
|
2357
|
+
analysis.mipTimerStop(kMipClockRootFeasibilityPump);
|
|
2358
|
+
heuristics.flushStatistics();
|
|
2359
|
+
|
|
2360
|
+
if (checkLimits()) return clockOff(analysis);
|
|
2361
|
+
analysis.mipTimerStart(kMipClockEvaluateRootLp);
|
|
2362
|
+
status = evaluateRootLp();
|
|
2363
|
+
analysis.mipTimerStop(kMipClockEvaluateRootLp);
|
|
2364
|
+
if (status == HighsLpRelaxation::Status::kInfeasible)
|
|
2365
|
+
return clockOff(analysis);
|
|
2366
|
+
} while (false);
|
|
2367
|
+
|
|
2368
|
+
analysis.mipTimerStop(kMipClockEvaluateRootNode1);
|
|
2369
|
+
analysis.mipTimerStart(kMipClockEvaluateRootNode2);
|
|
2370
|
+
if (lower_bound > upper_limit) {
|
|
2371
|
+
mipsolver.modelstatus_ = HighsModelStatus::kOptimal;
|
|
2372
|
+
pruned_treeweight = 1.0;
|
|
2373
|
+
num_nodes += 1;
|
|
2374
|
+
num_leaves += 1;
|
|
2375
|
+
return clockOff(analysis);
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
// if there are new global bound changes we re-evaluate the LP and do one
|
|
2379
|
+
// more separation round
|
|
2380
|
+
bool separate = !domain.getChangedCols().empty();
|
|
2381
|
+
analysis.mipTimerStart(kMipClockEvaluateRootLp);
|
|
2382
|
+
status = evaluateRootLp();
|
|
2383
|
+
analysis.mipTimerStop(kMipClockEvaluateRootLp);
|
|
2384
|
+
if (status == HighsLpRelaxation::Status::kInfeasible)
|
|
2385
|
+
return clockOff(analysis);
|
|
2386
|
+
if (separate && lp.scaledOptimal(status)) {
|
|
2387
|
+
HighsInt ncuts;
|
|
2388
|
+
analysis.mipTimerStart(kMipClockRootSeparationRound3);
|
|
2389
|
+
const bool root_separation_round_result =
|
|
2390
|
+
rootSeparationRound(sepa, ncuts, status);
|
|
2391
|
+
analysis.mipTimerStop(kMipClockRootSeparationRound3);
|
|
2392
|
+
if (root_separation_round_result) return clockOff(analysis);
|
|
2393
|
+
++nseparounds;
|
|
2394
|
+
printDisplayLine();
|
|
2395
|
+
}
|
|
2396
|
+
|
|
2397
|
+
// Possibly query existence of an external solution
|
|
2398
|
+
if (!mipsolver.submip)
|
|
2399
|
+
mipsolver.mipdata_->queryExternalSolution(
|
|
2400
|
+
mipsolver.solution_objective_,
|
|
2401
|
+
kExternalMipSolutionQueryOriginEvaluateRootNode4);
|
|
2402
|
+
|
|
2403
|
+
removeFixedIndices();
|
|
2404
|
+
if (lp.getLpSolver().getBasis().valid) lp.removeObsoleteRows();
|
|
2405
|
+
rootlpsolobj = lp.getObjective();
|
|
2406
|
+
|
|
2407
|
+
printDisplayLine();
|
|
2408
|
+
|
|
2409
|
+
if (lower_bound <= upper_limit) {
|
|
2410
|
+
if (!mipsolver.submip && mipsolver.options_mip_->mip_allow_restart &&
|
|
2411
|
+
mipsolver.options_mip_->presolve != kHighsOffString) {
|
|
2412
|
+
if (!analyticCenterComputed && compute_analytic_centre) {
|
|
2413
|
+
analysis.mipTimerStart(kMipClockFinishAnalyticCentreComputation);
|
|
2414
|
+
finishAnalyticCenterComputation(tg);
|
|
2415
|
+
analysis.mipTimerStop(kMipClockFinishAnalyticCentreComputation);
|
|
2416
|
+
}
|
|
2417
|
+
double fixingRate = percentageInactiveIntegers();
|
|
2418
|
+
if (fixingRate >= 2.5 + 7.5 * mipsolver.submip ||
|
|
2419
|
+
(!mipsolver.submip && fixingRate > 0 && numRestarts == 0)) {
|
|
2420
|
+
tg.cancel();
|
|
2421
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
2422
|
+
"\n%.1f%% inactive integer columns, restarting\n",
|
|
2423
|
+
fixingRate);
|
|
2424
|
+
if (stall != -1) maxSepaRounds = std::min(maxSepaRounds, nseparounds);
|
|
2425
|
+
tg.taskWait();
|
|
2426
|
+
analysis.mipTimerStart(kMipClockPerformRestart);
|
|
2427
|
+
performRestart();
|
|
2428
|
+
analysis.mipTimerStop(kMipClockPerformRestart);
|
|
2429
|
+
if (mipsolver.terminate()) return;
|
|
2430
|
+
++numRestartsRoot;
|
|
2431
|
+
if (mipsolver.modelstatus_ == HighsModelStatus::kNotset) {
|
|
2432
|
+
clockOff(analysis);
|
|
2433
|
+
goto restart;
|
|
2434
|
+
}
|
|
2435
|
+
return clockOff(analysis);
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
|
|
2439
|
+
if (detectSymmetries) {
|
|
2440
|
+
finishSymmetryDetection(tg, symData);
|
|
2441
|
+
analysis.mipTimerStart(kMipClockEvaluateRootLp);
|
|
2442
|
+
status = evaluateRootLp();
|
|
2443
|
+
analysis.mipTimerStop(kMipClockEvaluateRootLp);
|
|
2444
|
+
if (status == HighsLpRelaxation::Status::kInfeasible)
|
|
2445
|
+
return clockOff(analysis);
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
// add the root node to the nodequeue to initialize the search
|
|
2449
|
+
nodequeue.emplaceNode(std::vector<HighsDomainChange>(),
|
|
2450
|
+
std::vector<HighsInt>(), lower_bound,
|
|
2451
|
+
lp.computeBestEstimate(pseudocost), 1);
|
|
2452
|
+
}
|
|
2453
|
+
// End of HighsMipSolverData::evaluateRootNode()
|
|
2454
|
+
clockOff(analysis);
|
|
2455
|
+
}
|
|
2456
|
+
|
|
2457
|
+
bool HighsMipSolverData::checkLimits(int64_t nodeOffset) const {
|
|
2458
|
+
const HighsOptions& options = *mipsolver.options_mip_;
|
|
2459
|
+
|
|
2460
|
+
// This MIP instance may have been terminated
|
|
2461
|
+
if (terminatorActive())
|
|
2462
|
+
if (this->terminatorTerminated()) return true;
|
|
2463
|
+
|
|
2464
|
+
// Possible user interrupt
|
|
2465
|
+
if (!mipsolver.submip && mipsolver.callback_->user_callback) {
|
|
2466
|
+
mipsolver.callback_->clearHighsCallbackOutput();
|
|
2467
|
+
if (interruptFromCallbackWithData(kCallbackMipInterrupt,
|
|
2468
|
+
mipsolver.solution_objective_,
|
|
2469
|
+
"MIP check limits")) {
|
|
2470
|
+
if (mipsolver.modelstatus_ == HighsModelStatus::kNotset) {
|
|
2471
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
2472
|
+
"User interrupt\n");
|
|
2473
|
+
mipsolver.modelstatus_ = HighsModelStatus::kInterrupt;
|
|
2474
|
+
}
|
|
2475
|
+
return true;
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
// Possible termination due to objective being at least as good as
|
|
2479
|
+
// the target value
|
|
2480
|
+
if (!mipsolver.submip && mipsolver.solution_objective_ < kHighsInf &&
|
|
2481
|
+
options.objective_target > -kHighsInf) {
|
|
2482
|
+
// Note:
|
|
2483
|
+
//
|
|
2484
|
+
// Whether the sense is ObjSense::kMinimize or
|
|
2485
|
+
// ObjSense::kMaximize, the undefined value of
|
|
2486
|
+
// mipsolver.solution_objective_ is kHighsInf, and the default
|
|
2487
|
+
// target value is -kHighsInf, so had to rule out these cases in
|
|
2488
|
+
// the conditional statement above.
|
|
2489
|
+
//
|
|
2490
|
+
// mipsolver.solution_objective_ is the actual objective of the
|
|
2491
|
+
// MIP - including the offset, and independent of objective sense
|
|
2492
|
+
//
|
|
2493
|
+
// The target is reached if the objective is below (above) the
|
|
2494
|
+
// target value when minimizing (maximizing).
|
|
2495
|
+
const int int_sense = int(this->mipsolver.orig_model_->sense_);
|
|
2496
|
+
const bool reached_objective_target =
|
|
2497
|
+
int_sense * mipsolver.solution_objective_ <
|
|
2498
|
+
int_sense * options.objective_target;
|
|
2499
|
+
if (reached_objective_target) {
|
|
2500
|
+
if (mipsolver.modelstatus_ == HighsModelStatus::kNotset) {
|
|
2501
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
2502
|
+
"Reached objective target\n");
|
|
2503
|
+
mipsolver.modelstatus_ = HighsModelStatus::kObjectiveTarget;
|
|
2504
|
+
}
|
|
2505
|
+
return true;
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
if (options.mip_max_nodes != kHighsIInf &&
|
|
2510
|
+
num_nodes + nodeOffset >= options.mip_max_nodes) {
|
|
2511
|
+
if (mipsolver.modelstatus_ == HighsModelStatus::kNotset) {
|
|
2512
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
2513
|
+
"Reached node limit\n");
|
|
2514
|
+
mipsolver.modelstatus_ = HighsModelStatus::kSolutionLimit;
|
|
2515
|
+
}
|
|
2516
|
+
return true;
|
|
2517
|
+
}
|
|
2518
|
+
|
|
2519
|
+
if (options.mip_max_leaves != kHighsIInf &&
|
|
2520
|
+
num_leaves >= options.mip_max_leaves) {
|
|
2521
|
+
if (mipsolver.modelstatus_ == HighsModelStatus::kNotset) {
|
|
2522
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
2523
|
+
"Reached leaf node limit\n");
|
|
2524
|
+
mipsolver.modelstatus_ = HighsModelStatus::kSolutionLimit;
|
|
2525
|
+
}
|
|
2526
|
+
return true;
|
|
2527
|
+
}
|
|
2528
|
+
|
|
2529
|
+
if (options.mip_max_improving_sols != kHighsIInf &&
|
|
2530
|
+
numImprovingSols >= options.mip_max_improving_sols) {
|
|
2531
|
+
if (mipsolver.modelstatus_ == HighsModelStatus::kNotset) {
|
|
2532
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
2533
|
+
"Reached improving solution limit\n");
|
|
2534
|
+
mipsolver.modelstatus_ = HighsModelStatus::kSolutionLimit;
|
|
2535
|
+
}
|
|
2536
|
+
return true;
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
// const double time = mipsolver.timer_.read();
|
|
2540
|
+
// printf("checkLimits: time = %g\n", time);
|
|
2541
|
+
if (options.time_limit < kHighsInf &&
|
|
2542
|
+
mipsolver.timer_.read() >= options.time_limit) {
|
|
2543
|
+
if (mipsolver.modelstatus_ == HighsModelStatus::kNotset) {
|
|
2544
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
2545
|
+
"Reached time limit\n");
|
|
2546
|
+
mipsolver.modelstatus_ = HighsModelStatus::kTimeLimit;
|
|
2547
|
+
}
|
|
2548
|
+
return true;
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2551
|
+
return false;
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
void HighsMipSolverData::checkObjIntegrality() {
|
|
2555
|
+
objectiveFunction.checkIntegrality(epsilon);
|
|
2556
|
+
if (objectiveFunction.isIntegral() && numRestarts == 0) {
|
|
2557
|
+
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
|
|
2558
|
+
"Objective function is integral with scale %g\n",
|
|
2559
|
+
objectiveFunction.integralScale());
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
void HighsMipSolverData::setupDomainPropagation() {
|
|
2564
|
+
const HighsLp& model = *mipsolver.model_;
|
|
2565
|
+
highsSparseTranspose(model.num_row_, model.num_col_, model.a_matrix_.start_,
|
|
2566
|
+
model.a_matrix_.index_, model.a_matrix_.value_, ARstart_,
|
|
2567
|
+
ARindex_, ARvalue_);
|
|
2568
|
+
|
|
2569
|
+
pseudocost = HighsPseudocost(mipsolver);
|
|
2570
|
+
|
|
2571
|
+
// compute the maximal absolute coefficients to filter propagation
|
|
2572
|
+
maxAbsRowCoef.resize(mipsolver.numRow());
|
|
2573
|
+
for (HighsInt i = 0; i != mipsolver.numRow(); ++i) {
|
|
2574
|
+
double maxabsval = 0.0;
|
|
2575
|
+
|
|
2576
|
+
HighsInt start = ARstart_[i];
|
|
2577
|
+
HighsInt end = ARstart_[i + 1];
|
|
2578
|
+
for (HighsInt j = start; j != end; ++j)
|
|
2579
|
+
maxabsval = std::max(maxabsval, std::abs(ARvalue_[j]));
|
|
2580
|
+
|
|
2581
|
+
maxAbsRowCoef[i] = maxabsval;
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2584
|
+
domain = HighsDomain(mipsolver);
|
|
2585
|
+
domain.computeRowActivities();
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2588
|
+
void HighsMipSolverData::saveReportMipSolution(const double new_upper_limit) {
|
|
2589
|
+
const bool non_improving = new_upper_limit >= upper_limit;
|
|
2590
|
+
if (mipsolver.submip) return;
|
|
2591
|
+
if (non_improving) return;
|
|
2592
|
+
|
|
2593
|
+
if (mipsolver.callback_->user_callback) {
|
|
2594
|
+
if (mipsolver.callback_->active[kCallbackMipImprovingSolution]) {
|
|
2595
|
+
mipsolver.callback_->clearHighsCallbackOutput();
|
|
2596
|
+
mipsolver.callback_->data_out.mip_solution = mipsolver.solution_;
|
|
2597
|
+
const bool interrupt = interruptFromCallbackWithData(
|
|
2598
|
+
kCallbackMipImprovingSolution, mipsolver.solution_objective_,
|
|
2599
|
+
"Improving solution");
|
|
2600
|
+
assert(!interrupt);
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
if (mipsolver.options_mip_->mip_improving_solution_save) {
|
|
2605
|
+
HighsObjectiveSolution record;
|
|
2606
|
+
record.objective = mipsolver.solution_objective_;
|
|
2607
|
+
record.col_value = mipsolver.solution_;
|
|
2608
|
+
mipsolver.saved_objective_and_solution_.push_back(record);
|
|
2609
|
+
}
|
|
2610
|
+
FILE* file = mipsolver.improving_solution_file_;
|
|
2611
|
+
if (file) {
|
|
2612
|
+
writeLpObjective(file, mipsolver.options_mip_->log_options,
|
|
2613
|
+
*(mipsolver.orig_model_), mipsolver.solution_);
|
|
2614
|
+
writePrimalSolution(
|
|
2615
|
+
file, mipsolver.options_mip_->log_options, *(mipsolver.orig_model_),
|
|
2616
|
+
mipsolver.solution_,
|
|
2617
|
+
mipsolver.options_mip_->mip_improving_solution_report_sparse);
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
|
|
2621
|
+
void HighsMipSolverData::limitsToBounds(double& dual_bound,
|
|
2622
|
+
double& primal_bound,
|
|
2623
|
+
double& mip_rel_gap) const {
|
|
2624
|
+
mip_rel_gap = limitsToGap(lower_bound, upper_bound, dual_bound, primal_bound);
|
|
2625
|
+
primal_bound =
|
|
2626
|
+
std::min(mipsolver.options_mip_->objective_bound, primal_bound);
|
|
2627
|
+
// Adjust objective sense in case of maximization problem
|
|
2628
|
+
if (this->mipsolver.orig_model_->sense_ == ObjSense::kMaximize) {
|
|
2629
|
+
dual_bound = -dual_bound;
|
|
2630
|
+
primal_bound = -primal_bound;
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2634
|
+
void HighsMipSolverData::updateLowerBound(double new_lower_bound) {
|
|
2635
|
+
// Update lower bound
|
|
2636
|
+
double prev_lower_bound = lower_bound;
|
|
2637
|
+
lower_bound = new_lower_bound;
|
|
2638
|
+
if (!mipsolver.submip && lower_bound != prev_lower_bound)
|
|
2639
|
+
updatePrimalDualIntegral(prev_lower_bound, lower_bound, upper_bound,
|
|
2640
|
+
upper_bound);
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
// Interface to callbackAction, with mipsolver_objective_value since
|
|
2644
|
+
// incumbent value (mipsolver.solution_objective_) is not right for
|
|
2645
|
+
// callback_type = kCallbackMipSolution
|
|
2646
|
+
|
|
2647
|
+
void HighsMipSolverData::setCallbackDataOut(
|
|
2648
|
+
const double mipsolver_objective_value) const {
|
|
2649
|
+
double dual_bound;
|
|
2650
|
+
double primal_bound;
|
|
2651
|
+
double mip_rel_gap;
|
|
2652
|
+
limitsToBounds(dual_bound, primal_bound, mip_rel_gap);
|
|
2653
|
+
mipsolver.callback_->data_out.running_time = mipsolver.timer_.read();
|
|
2654
|
+
mipsolver.callback_->data_out.objective_function_value =
|
|
2655
|
+
mipsolver_objective_value;
|
|
2656
|
+
mipsolver.callback_->data_out.mip_node_count = mipsolver.mipdata_->num_nodes;
|
|
2657
|
+
mipsolver.callback_->data_out.mip_total_lp_iterations =
|
|
2658
|
+
mipsolver.mipdata_->total_lp_iterations;
|
|
2659
|
+
mipsolver.callback_->data_out.mip_primal_bound = primal_bound;
|
|
2660
|
+
mipsolver.callback_->data_out.mip_dual_bound = dual_bound;
|
|
2661
|
+
mipsolver.callback_->data_out.mip_gap = mip_rel_gap;
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2664
|
+
bool HighsMipSolverData::interruptFromCallbackWithData(
|
|
2665
|
+
const int callback_type, const double mipsolver_objective_value,
|
|
2666
|
+
const std::string message) const {
|
|
2667
|
+
if (!mipsolver.callback_->callbackActive(callback_type)) return false;
|
|
2668
|
+
assert(!mipsolver.submip);
|
|
2669
|
+
setCallbackDataOut(mipsolver_objective_value);
|
|
2670
|
+
return mipsolver.callback_->callbackAction(callback_type, message);
|
|
2671
|
+
}
|
|
2672
|
+
|
|
2673
|
+
void HighsMipSolverData::queryExternalSolution(
|
|
2674
|
+
const double mipsolver_objective_value,
|
|
2675
|
+
const ExternalMipSolutionQueryOrigin external_solution_query_origin) {
|
|
2676
|
+
assert(!mipsolver.submip);
|
|
2677
|
+
HighsCallback* callback = mipsolver.callback_;
|
|
2678
|
+
const bool use_callback =
|
|
2679
|
+
callback->user_callback && callback->active[kCallbackMipUserSolution];
|
|
2680
|
+
if (use_callback) {
|
|
2681
|
+
setCallbackDataOut(mipsolver_objective_value);
|
|
2682
|
+
callback->data_out.external_solution_query_origin =
|
|
2683
|
+
external_solution_query_origin;
|
|
2684
|
+
callback->clearHighsCallbackInput();
|
|
2685
|
+
|
|
2686
|
+
const bool interrupt =
|
|
2687
|
+
callback->callbackAction(kCallbackMipUserSolution, "MIP User solution");
|
|
2688
|
+
assert(!interrupt);
|
|
2689
|
+
if (callback->data_in.user_has_solution) {
|
|
2690
|
+
// Objective is assumed to be original_offset +
|
|
2691
|
+
// (original_c)^T(original_x), but MIP solver bounds are based on the
|
|
2692
|
+
// reduced objective (reduced_c)^T(reduced_x)
|
|
2693
|
+
//
|
|
2694
|
+
// Now, original_sense*[reduced_offset + (reduced_c)^T(reduced_x)] is an
|
|
2695
|
+
// objective in the original space, so
|
|
2696
|
+
//
|
|
2697
|
+
// f0 + c0^Tx0 = s*(f1 + c1^Tx1)
|
|
2698
|
+
//
|
|
2699
|
+
// where 0 => original; 1 => reduced
|
|
2700
|
+
//
|
|
2701
|
+
// This allows the reduced objective value to be deduced as
|
|
2702
|
+
//
|
|
2703
|
+
// c1^Tx1 = s*(f0 + c0^Tx0) - f1
|
|
2704
|
+
//
|
|
2705
|
+
// (reduced_c)^T(reduced_x) = original_sense*[original_offset +
|
|
2706
|
+
// (original_c)^T(original_x) - reduced_offset]
|
|
2707
|
+
const auto& user_solution = callback->data_in.user_solution;
|
|
2708
|
+
double bound_violation_ = 0;
|
|
2709
|
+
double row_violation_ = 0;
|
|
2710
|
+
double integrality_violation_ = 0;
|
|
2711
|
+
HighsCDouble user_solution_quad_objective_value = 0;
|
|
2712
|
+
const bool feasible = mipsolver.solutionFeasible(
|
|
2713
|
+
mipsolver.orig_model_, user_solution, nullptr, bound_violation_,
|
|
2714
|
+
row_violation_, integrality_violation_,
|
|
2715
|
+
user_solution_quad_objective_value);
|
|
2716
|
+
double user_solution_objective_value =
|
|
2717
|
+
double(user_solution_quad_objective_value);
|
|
2718
|
+
if (!feasible) {
|
|
2719
|
+
highsLogUser(
|
|
2720
|
+
mipsolver.options_mip_->log_options, HighsLogType::kWarning,
|
|
2721
|
+
"User-supplied solution has with objective %g has violations: "
|
|
2722
|
+
"bound = %.4g; integrality = %.4g; row = %.4g\n",
|
|
2723
|
+
user_solution_objective_value, bound_violation_,
|
|
2724
|
+
integrality_violation_, row_violation_);
|
|
2725
|
+
return;
|
|
2726
|
+
}
|
|
2727
|
+
std::vector<double> reduced_user_solution;
|
|
2728
|
+
reduced_user_solution =
|
|
2729
|
+
postSolveStack.getReducedPrimalSolution(user_solution);
|
|
2730
|
+
const bool print_display_line = true;
|
|
2731
|
+
const bool is_user_solution = true;
|
|
2732
|
+
addIncumbent(reduced_user_solution, user_solution_objective_value,
|
|
2733
|
+
kSolutionSourceUserSolution, print_display_line,
|
|
2734
|
+
is_user_solution);
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
|
|
2739
|
+
HighsInt HighsMipSolverData::terminatorConcurrency() const {
|
|
2740
|
+
return mipsolver.terminator_.num_instance;
|
|
2741
|
+
}
|
|
2742
|
+
|
|
2743
|
+
HighsInt HighsMipSolverData::terminatorMyInstance() const {
|
|
2744
|
+
return mipsolver.terminator_.my_instance;
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2747
|
+
void HighsMipSolverData::terminatorTerminate() {
|
|
2748
|
+
assert(terminatorActive());
|
|
2749
|
+
mipsolver.terminator_.terminate();
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2752
|
+
bool HighsMipSolverData::terminatorTerminated() const {
|
|
2753
|
+
if (this->terminatorActive())
|
|
2754
|
+
mipsolver.termination_status_ = mipsolver.terminator_.terminationStatus();
|
|
2755
|
+
return mipsolver.termination_status_ != HighsModelStatus::kNotset;
|
|
2756
|
+
}
|
|
2757
|
+
|
|
2758
|
+
void HighsMipSolverData::terminatorReport() const {
|
|
2759
|
+
if (this->terminatorActive())
|
|
2760
|
+
mipsolver.terminator_.report(mipsolver.options_mip_->log_options);
|
|
2761
|
+
}
|
|
2762
|
+
|
|
2763
|
+
static double possInfRelDiff(const double v0, const double v1,
|
|
2764
|
+
const double den) {
|
|
2765
|
+
double rel_diff;
|
|
2766
|
+
if (std::fabs(v0) == kHighsInf) {
|
|
2767
|
+
if (std::fabs(v1) == kHighsInf) {
|
|
2768
|
+
rel_diff = 0;
|
|
2769
|
+
} else {
|
|
2770
|
+
rel_diff = kHighsInf;
|
|
2771
|
+
}
|
|
2772
|
+
} else {
|
|
2773
|
+
if (std::fabs(v1) == kHighsInf) {
|
|
2774
|
+
rel_diff = kHighsInf;
|
|
2775
|
+
} else {
|
|
2776
|
+
rel_diff = std::fabs(v1 - v0) / std::max(1.0, std::fabs(den));
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
return rel_diff;
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
void HighsMipSolverData::updatePrimalDualIntegral(const double from_lower_bound,
|
|
2783
|
+
const double to_lower_bound,
|
|
2784
|
+
const double from_upper_bound,
|
|
2785
|
+
const double to_upper_bound,
|
|
2786
|
+
const bool check_bound_change,
|
|
2787
|
+
const bool check_prev_data) {
|
|
2788
|
+
// Parameters to updatePrimalDualIntegral are lower and upper bounds
|
|
2789
|
+
// before/after a change
|
|
2790
|
+
//
|
|
2791
|
+
// updatePrimalDualIntegral should only be called when there is a
|
|
2792
|
+
// change in one of the bounds, except when the final update is
|
|
2793
|
+
// made, in which case the bounds must NOT have changed. By default,
|
|
2794
|
+
// a check for some bound change is made, unless check_bound_change
|
|
2795
|
+
// is false, in which case there is a check for unchanged bounds.
|
|
2796
|
+
//
|
|
2797
|
+
HighsPrimaDualIntegral& pdi = this->primal_dual_integral;
|
|
2798
|
+
// HighsPrimaDualIntegral struct contains the following data
|
|
2799
|
+
//
|
|
2800
|
+
// * value: Current value of the P-D integral
|
|
2801
|
+
//
|
|
2802
|
+
// * prev_lb: Value of lb that was computed from to_lower_bound in
|
|
2803
|
+
// the previous call. Used as a check that the value of lb
|
|
2804
|
+
// computed from from_lower_bound in this call is equal - to
|
|
2805
|
+
// within bound_change_tolerance. If not true, then a change in lb
|
|
2806
|
+
// has been missed. Only for checking/debugging
|
|
2807
|
+
//
|
|
2808
|
+
// * prev_ub: Ditto for upper_bound. Only for checking/debugging
|
|
2809
|
+
//
|
|
2810
|
+
// * prev_gap: Ditto for gap. Only for checking/debugging
|
|
2811
|
+
//
|
|
2812
|
+
// * prev_time: Used to determine the time spent at the previous gap
|
|
2813
|
+
|
|
2814
|
+
double from_lb;
|
|
2815
|
+
double from_ub;
|
|
2816
|
+
const double from_gap =
|
|
2817
|
+
this->limitsToGap(from_lower_bound, from_upper_bound, from_lb, from_ub);
|
|
2818
|
+
double to_lb;
|
|
2819
|
+
double to_ub;
|
|
2820
|
+
const double to_gap =
|
|
2821
|
+
this->limitsToGap(to_lower_bound, to_upper_bound, to_lb, to_ub);
|
|
2822
|
+
|
|
2823
|
+
const double lb_difference = possInfRelDiff(from_lb, to_lb, to_lb);
|
|
2824
|
+
const double ub_difference = possInfRelDiff(from_ub, to_ub, to_ub);
|
|
2825
|
+
const double bound_change_tolerance = 0;
|
|
2826
|
+
const bool bound_change = lb_difference > bound_change_tolerance ||
|
|
2827
|
+
ub_difference > bound_change_tolerance;
|
|
2828
|
+
|
|
2829
|
+
if (check_bound_change) {
|
|
2830
|
+
if (!bound_change) {
|
|
2831
|
+
if (from_lower_bound == to_lower_bound &&
|
|
2832
|
+
from_upper_bound == to_upper_bound) {
|
|
2833
|
+
const double lower_bound_difference =
|
|
2834
|
+
possInfRelDiff(from_lower_bound, to_lower_bound, to_lower_bound);
|
|
2835
|
+
const double upper_bound_difference =
|
|
2836
|
+
possInfRelDiff(from_upper_bound, to_upper_bound, to_upper_bound);
|
|
2837
|
+
assert(bound_change);
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
} else {
|
|
2841
|
+
if (bound_change) {
|
|
2842
|
+
if (from_lower_bound != to_lower_bound ||
|
|
2843
|
+
from_upper_bound != to_upper_bound) {
|
|
2844
|
+
const double lower_bound_difference =
|
|
2845
|
+
possInfRelDiff(from_lower_bound, to_lower_bound, to_lower_bound);
|
|
2846
|
+
const double upper_bound_difference =
|
|
2847
|
+
possInfRelDiff(from_upper_bound, to_upper_bound, to_upper_bound);
|
|
2848
|
+
assert(!bound_change);
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
if (pdi.value > -kHighsInf) {
|
|
2853
|
+
// updatePrimalDualIntegral has been called previously, so can
|
|
2854
|
+
// usually test housekeeping, even if gap is still inf
|
|
2855
|
+
//
|
|
2856
|
+
// The one case where the checking can't be done comes after restart, where
|
|
2857
|
+
// the
|
|
2858
|
+
//
|
|
2859
|
+
if (check_prev_data) {
|
|
2860
|
+
// These housekeeping tests check that the previous saved
|
|
2861
|
+
// lower/upper bounds and gap are very close to the "from"
|
|
2862
|
+
// lower/upper bounds and corresponding gap. They are usually
|
|
2863
|
+
// identical, but rounding error can occur when passing through
|
|
2864
|
+
// reset, when the old/new offsets are added/subtracted from the
|
|
2865
|
+
// bounds due to changes in offset during presolve.
|
|
2866
|
+
const double lb_inconsistency =
|
|
2867
|
+
possInfRelDiff(from_lb, pdi.prev_lb, pdi.prev_lb);
|
|
2868
|
+
const bool lb_consistent = lb_inconsistency < 1e-12;
|
|
2869
|
+
const double ub_inconsistency =
|
|
2870
|
+
possInfRelDiff(from_ub, pdi.prev_ub, pdi.prev_ub);
|
|
2871
|
+
const bool ub_consistent = ub_inconsistency < 1e-12;
|
|
2872
|
+
const double gap_inconsistency =
|
|
2873
|
+
possInfRelDiff(from_gap, pdi.prev_gap, 1.0);
|
|
2874
|
+
const bool gap_consistent = gap_inconsistency < 1e-12;
|
|
2875
|
+
assert(lb_consistent);
|
|
2876
|
+
assert(ub_consistent);
|
|
2877
|
+
assert(gap_consistent);
|
|
2878
|
+
}
|
|
2879
|
+
if (to_gap < kHighsInf) {
|
|
2880
|
+
double time = mipsolver.timer_.read();
|
|
2881
|
+
if (from_gap < kHighsInf) {
|
|
2882
|
+
// Need to update the P-D integral
|
|
2883
|
+
double time_diff = time - pdi.prev_time;
|
|
2884
|
+
assert(time_diff >= 0);
|
|
2885
|
+
pdi.value += time_diff * pdi.prev_gap;
|
|
2886
|
+
}
|
|
2887
|
+
pdi.prev_time = time;
|
|
2888
|
+
}
|
|
2889
|
+
} else {
|
|
2890
|
+
pdi.value = 0;
|
|
2891
|
+
}
|
|
2892
|
+
pdi.prev_lb = to_lb;
|
|
2893
|
+
pdi.prev_ub = to_ub;
|
|
2894
|
+
pdi.prev_gap = to_gap;
|
|
2895
|
+
}
|
|
2896
|
+
|
|
2897
|
+
void HighsPrimaDualIntegral::initialise() { this->value = -kHighsInf; }
|
|
2898
|
+
|
|
2899
|
+
void HighsTerminator::clear() {
|
|
2900
|
+
this->num_instance = 0;
|
|
2901
|
+
this->my_instance = kNoThreadInstance;
|
|
2902
|
+
this->record = nullptr;
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2905
|
+
void HighsTerminator::initialise(HighsInt num_instance_, HighsInt my_instance_,
|
|
2906
|
+
HighsModelStatus* record_) {
|
|
2907
|
+
this->clear();
|
|
2908
|
+
this->num_instance = num_instance_;
|
|
2909
|
+
this->my_instance = my_instance_;
|
|
2910
|
+
this->record = record_;
|
|
2911
|
+
}
|
|
2912
|
+
|
|
2913
|
+
HighsInt HighsTerminator::concurrency() const { return this->num_instance; }
|
|
2914
|
+
|
|
2915
|
+
void HighsTerminator::terminate() {
|
|
2916
|
+
assert(this->record);
|
|
2917
|
+
assert(this->my_instance < this->num_instance);
|
|
2918
|
+
this->record[this->my_instance] = HighsModelStatus::kHighsInterrupt;
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2921
|
+
HighsModelStatus HighsTerminator::terminationStatus() const {
|
|
2922
|
+
assert(this->record);
|
|
2923
|
+
for (HighsInt instance = 0; instance < this->num_instance; instance++) {
|
|
2924
|
+
if (this->record[instance] != HighsModelStatus::kNotset)
|
|
2925
|
+
return this->record[instance];
|
|
2926
|
+
}
|
|
2927
|
+
return HighsModelStatus::kNotset;
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2930
|
+
void HighsTerminator::report(const HighsLogOptions log_options) const {
|
|
2931
|
+
highsLogUser(log_options, HighsLogType::kInfo, "\nTerminator: ");
|
|
2932
|
+
for (HighsInt instance = 0; instance < this->num_instance; instance++)
|
|
2933
|
+
highsLogUser(log_options, HighsLogType::kInfo, " %20d",
|
|
2934
|
+
int(this->record[instance]));
|
|
2935
|
+
highsLogUser(log_options, HighsLogType::kInfo, "\n");
|
|
2936
|
+
}
|