lpsolver 0.1.0 → 0.2.0
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 +70 -26
- data/ext/lpsolver/Makefile +273 -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 +28 -4
- data/lib/lpsolver/native.so +0 -0
- data/lib/lpsolver/native_model.rb +261 -0
- data/lib/lpsolver/solution.rb +72 -7
- data/lib/lpsolver/version.rb +1 -1
- data/lpsolver.gemspec +4 -1
- metadata +1176 -4
|
@@ -0,0 +1,3003 @@
|
|
|
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
|
+
/**@file simplex/HEkkDual.cpp
|
|
9
|
+
* @brief
|
|
10
|
+
*/
|
|
11
|
+
#include "simplex/HEkkDual.h"
|
|
12
|
+
|
|
13
|
+
#include <algorithm>
|
|
14
|
+
#include <cassert>
|
|
15
|
+
#include <cmath>
|
|
16
|
+
#include <cstdio>
|
|
17
|
+
#include <cstring>
|
|
18
|
+
#include <iostream>
|
|
19
|
+
#include <set>
|
|
20
|
+
|
|
21
|
+
#include "lp_data/HighsLpUtils.h"
|
|
22
|
+
#include "parallel/HighsParallel.h"
|
|
23
|
+
#include "simplex/HEkkPrimal.h"
|
|
24
|
+
#include "simplex/SimplexTimer.h"
|
|
25
|
+
|
|
26
|
+
using std::fabs;
|
|
27
|
+
|
|
28
|
+
HighsStatus HEkkDual::solve(const bool pass_force_phase2) {
|
|
29
|
+
// Initialise control data for a particular solve
|
|
30
|
+
initialiseSolve();
|
|
31
|
+
|
|
32
|
+
if (debugDualSimplex("Initialise", true) == HighsDebugStatus::kLogicalError)
|
|
33
|
+
return ekk_instance_.returnFromSolve(HighsStatus::kError);
|
|
34
|
+
// Assumes that the LP has a positive number of rows
|
|
35
|
+
if (ekk_instance_.isUnconstrainedLp())
|
|
36
|
+
return ekk_instance_.returnFromSolve(HighsStatus::kError);
|
|
37
|
+
|
|
38
|
+
HighsOptions& options = *ekk_instance_.options_;
|
|
39
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
40
|
+
HighsSimplexStatus& status = ekk_instance_.status_;
|
|
41
|
+
HighsModelStatus& model_status = ekk_instance_.model_status_;
|
|
42
|
+
|
|
43
|
+
if (!dualInfoOk(ekk_instance_.lp_)) {
|
|
44
|
+
highsLogDev(options.log_options, HighsLogType::kError,
|
|
45
|
+
"HPrimalDual::solve has error in dual information\n");
|
|
46
|
+
return ekk_instance_.returnFromSolve(HighsStatus::kError);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Possibly use Li dual steepest edge weights by not storing squared
|
|
50
|
+
// primal infeasibilities
|
|
51
|
+
possiblyUseLiDualSteepestEdge();
|
|
52
|
+
|
|
53
|
+
assert(status.has_invert);
|
|
54
|
+
if (!status.has_invert) {
|
|
55
|
+
highsLogDev(options.log_options, HighsLogType::kError,
|
|
56
|
+
"HDual:: Should enter solve with INVERT\n");
|
|
57
|
+
return ekk_instance_.returnFromSolve(HighsStatus::kError);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Determine the duals without cost perturbation
|
|
61
|
+
ekk_instance_.initialiseCost(SimplexAlgorithm::kDual, kSolvePhaseUnknown);
|
|
62
|
+
ekk_instance_.computeDual();
|
|
63
|
+
ekk_instance_.computeSimplexDualInfeasible();
|
|
64
|
+
// Record whether the solution with unperturbed costs is dual feasible
|
|
65
|
+
const bool dual_feasible_with_unperturbed_costs =
|
|
66
|
+
info.num_dual_infeasibilities == 0;
|
|
67
|
+
// Force phase 2 if dual infeasibilities without cost perturbation
|
|
68
|
+
// involved fixed variables or were (at most) small
|
|
69
|
+
force_phase2 = pass_force_phase2 ||
|
|
70
|
+
info.max_dual_infeasibility * info.max_dual_infeasibility <
|
|
71
|
+
ekk_instance_.options_->dual_feasibility_tolerance;
|
|
72
|
+
// Within the MIP solver, unless the basis supplied was alien, the
|
|
73
|
+
// simplex solver should be able to start from dual feasibility, so
|
|
74
|
+
// possibly debug this property. Note that debug_dual_feasible is
|
|
75
|
+
// set in HEkk::setBasis, and is false if kDebugMipNodeDualFeasible
|
|
76
|
+
// is false
|
|
77
|
+
if (ekk_instance_.debug_dual_feasible &&
|
|
78
|
+
!dual_feasible_with_unperturbed_costs) {
|
|
79
|
+
SimplexBasis& basis = ekk_instance_.basis_;
|
|
80
|
+
highsLogDev(
|
|
81
|
+
options.log_options, HighsLogType::kWarning,
|
|
82
|
+
"Basis should be dual feasible, but duals without cost perturbation "
|
|
83
|
+
"have num / max / sum = %4d / %g / %g infeasibilities",
|
|
84
|
+
(int)info.num_dual_infeasibilities, info.max_dual_infeasibility,
|
|
85
|
+
info.sum_dual_infeasibilities);
|
|
86
|
+
if (!force_phase2) {
|
|
87
|
+
highsLogDev(options.log_options, HighsLogType::kWarning,
|
|
88
|
+
" !!Not forcing phase 2!! basis Id = %d; update count = %d; "
|
|
89
|
+
"name = %s\n",
|
|
90
|
+
(int)basis.debug_id, (int)basis.debug_update_count,
|
|
91
|
+
basis.debug_origin_name.c_str());
|
|
92
|
+
} else {
|
|
93
|
+
highsLogDev(options.log_options, HighsLogType::kWarning, "\n");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Determine whether the solution is near-optimal. Values 1000 and
|
|
97
|
+
// 1e-3 (ensuring sum<1) are unimportant, as the sum of primal
|
|
98
|
+
// infeasibilities for near-optimal solutions is typically many
|
|
99
|
+
// orders of magnitude smaller than 1, and the sum of primal
|
|
100
|
+
// infeasibilities will be very much larger for non-trivial LPs
|
|
101
|
+
// that are dual feasible for a logical or crash basis.
|
|
102
|
+
//
|
|
103
|
+
// Consider there to be no dual infeasibilities if there are none,
|
|
104
|
+
// or if phase 2 is forced, in which case any dual infeasibilities
|
|
105
|
+
// will be shifted
|
|
106
|
+
const bool no_simplex_dual_infeasibilities =
|
|
107
|
+
dual_feasible_with_unperturbed_costs || force_phase2;
|
|
108
|
+
const bool near_optimal = no_simplex_dual_infeasibilities &&
|
|
109
|
+
info.num_primal_infeasibilities < 1000 &&
|
|
110
|
+
info.max_primal_infeasibility < 1e-3;
|
|
111
|
+
if (near_optimal)
|
|
112
|
+
highsLogDev(options.log_options, HighsLogType::kDetailed,
|
|
113
|
+
"Dual feasible with unperturbed costs and num / max / sum "
|
|
114
|
+
"primal infeasibilities of "
|
|
115
|
+
"%" HIGHSINT_FORMAT
|
|
116
|
+
" / %g "
|
|
117
|
+
"/ %g, so near-optimal\n",
|
|
118
|
+
info.num_primal_infeasibilities, info.max_primal_infeasibility,
|
|
119
|
+
info.sum_primal_infeasibilities);
|
|
120
|
+
|
|
121
|
+
// Perturb costs according to whether the solution is near-optimal
|
|
122
|
+
const bool perturb_costs = !near_optimal;
|
|
123
|
+
if (!perturb_costs)
|
|
124
|
+
highsLogDev(options.log_options, HighsLogType::kDetailed,
|
|
125
|
+
"Near-optimal, so don't use cost perturbation\n");
|
|
126
|
+
ekk_instance_.initialiseCost(SimplexAlgorithm::kDual, kSolvePhaseUnknown,
|
|
127
|
+
perturb_costs);
|
|
128
|
+
// Check whether the time/iteration limit has been reached. First
|
|
129
|
+
// point at which a non-error return can occur
|
|
130
|
+
if (ekk_instance_.bailout())
|
|
131
|
+
return ekk_instance_.returnFromSolve(HighsStatus::kWarning);
|
|
132
|
+
|
|
133
|
+
// Consider initialising edge weights
|
|
134
|
+
if (status.has_dual_steepest_edge_weights) {
|
|
135
|
+
// Dual steepest edge weights are known, so possibly check
|
|
136
|
+
assert((HighsInt)ekk_instance_.dual_edge_weight_.size() >= solver_num_row);
|
|
137
|
+
assert((HighsInt)ekk_instance_.scattered_dual_edge_weight_.size() >=
|
|
138
|
+
solver_num_tot);
|
|
139
|
+
ekk_instance_.devDebugDualSteepestEdgeWeights("before solve");
|
|
140
|
+
} else {
|
|
141
|
+
// Set up edge weights
|
|
142
|
+
//
|
|
143
|
+
// Assign unit weights - necessary for Dantzig and Devex, and
|
|
144
|
+
// correct for steepest edge when B=I so, for clarity, do it for
|
|
145
|
+
// all. Also ensure that the scattering vector is the right size
|
|
146
|
+
ekk_instance_.dual_edge_weight_.assign(solver_num_row, 1.0);
|
|
147
|
+
ekk_instance_.scattered_dual_edge_weight_.resize(solver_num_tot);
|
|
148
|
+
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
|
|
149
|
+
// Intending to using dual steepest edge weights
|
|
150
|
+
//
|
|
151
|
+
// Exact DSE weights need to be computed if the basis contains
|
|
152
|
+
// structurals
|
|
153
|
+
if (ekk_instance_.logicalBasis()) {
|
|
154
|
+
// Unit weights already set up for B=I
|
|
155
|
+
status.has_dual_steepest_edge_weights = true;
|
|
156
|
+
} else {
|
|
157
|
+
// Non-logical basis
|
|
158
|
+
if (near_optimal) {
|
|
159
|
+
// Use Devex rather than compute steepest edge weights
|
|
160
|
+
highsLogDev(
|
|
161
|
+
options.log_options, HighsLogType::kDetailed,
|
|
162
|
+
"Basis is not logical, but near-optimal, so use Devex rather "
|
|
163
|
+
"than compute steepest edge weights\n");
|
|
164
|
+
edge_weight_mode = EdgeWeightMode::kDevex;
|
|
165
|
+
assert(!status.has_dual_steepest_edge_weights);
|
|
166
|
+
} else {
|
|
167
|
+
// Compute steepest edge weights
|
|
168
|
+
highsLogDev(
|
|
169
|
+
options.log_options, HighsLogType::kDetailed,
|
|
170
|
+
"Basis is not logical, so compute steepest edge weights\n");
|
|
171
|
+
ekk_instance_.computeDualSteepestEdgeWeights(true);
|
|
172
|
+
status.has_dual_steepest_edge_weights = true;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (edge_weight_mode == EdgeWeightMode::kDevex) initialiseDevexFramework();
|
|
177
|
+
// Check on consistency between edge_weight_mode and
|
|
178
|
+
// status.has_dual_steepest_edge_weights
|
|
179
|
+
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
|
|
180
|
+
assert(status.has_dual_steepest_edge_weights);
|
|
181
|
+
} else {
|
|
182
|
+
assert(!status.has_dual_steepest_edge_weights);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Resize the copy of scattered edge weights for backtracking
|
|
186
|
+
info.backtracking_basis_edge_weight_.resize(solver_num_tot);
|
|
187
|
+
|
|
188
|
+
if (perturb_costs) {
|
|
189
|
+
// Compute the dual values with perturbed costs
|
|
190
|
+
ekk_instance_.computeDual();
|
|
191
|
+
// Determine the number of dual infeasibilities after fixed
|
|
192
|
+
// variable flips
|
|
193
|
+
computeDualInfeasibilitiesWithFixedVariableFlips();
|
|
194
|
+
dualInfeasCount = info.num_dual_infeasibilities;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Determine the solve phase
|
|
198
|
+
if (force_phase2) {
|
|
199
|
+
// Dual infeasibilities without cost perturbation involved
|
|
200
|
+
// fixed variables or were (at most) small, so can easily be
|
|
201
|
+
// removed by flips for fixed variables and shifts for the rest
|
|
202
|
+
solve_phase = kSolvePhase2;
|
|
203
|
+
} else {
|
|
204
|
+
// Phase depends on the number of dual infeasibilities after fixed
|
|
205
|
+
// variable flips
|
|
206
|
+
solve_phase = dualInfeasCount > 0 ? kSolvePhase1 : kSolvePhase2;
|
|
207
|
+
}
|
|
208
|
+
if (ekk_instance_.debugOkForSolve(SimplexAlgorithm::kDual, solve_phase) ==
|
|
209
|
+
HighsDebugStatus::kLogicalError)
|
|
210
|
+
return ekk_instance_.returnFromSolve(HighsStatus::kError);
|
|
211
|
+
//
|
|
212
|
+
// The major solving loop
|
|
213
|
+
//
|
|
214
|
+
while (solve_phase) {
|
|
215
|
+
HighsInt it0 = ekk_instance_.iteration_count_;
|
|
216
|
+
// When starting a new phase the (updated) dual objective function
|
|
217
|
+
// value isn't known. Indicate this so that when the value
|
|
218
|
+
// computed from scratch in rebuild() isn't checked against the
|
|
219
|
+
// the updated value
|
|
220
|
+
status.has_dual_objective_value = false;
|
|
221
|
+
if (solve_phase == kSolvePhaseUnknown) {
|
|
222
|
+
// Reset the phase 2 bounds so that true number of dual
|
|
223
|
+
// infeasibilities can be determined
|
|
224
|
+
ekk_instance_.initialiseBound(SimplexAlgorithm::kDual,
|
|
225
|
+
kSolvePhaseUnknown);
|
|
226
|
+
ekk_instance_.initialiseNonbasicValueAndMove();
|
|
227
|
+
// Determine the number of unavoidable dual infeasibilities, and
|
|
228
|
+
// hence the solve phase
|
|
229
|
+
computeDualInfeasibilitiesWithFixedVariableFlips();
|
|
230
|
+
dualInfeasCount = info.num_dual_infeasibilities;
|
|
231
|
+
solve_phase = dualInfeasCount > 0 ? kSolvePhase1 : kSolvePhase2;
|
|
232
|
+
if (info.backtracking_) {
|
|
233
|
+
// Backtracking, so set the bounds and primal values
|
|
234
|
+
ekk_instance_.initialiseBound(SimplexAlgorithm::kDual, solve_phase);
|
|
235
|
+
ekk_instance_.initialiseNonbasicValueAndMove();
|
|
236
|
+
// Can now forget that we might have been backtracking
|
|
237
|
+
info.backtracking_ = false;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
assert(solve_phase == kSolvePhase1 || solve_phase == kSolvePhase2);
|
|
241
|
+
if (solve_phase == kSolvePhase1) {
|
|
242
|
+
// Phase 1
|
|
243
|
+
analysis->simplexTimerStart(SimplexDualPhase1Clock);
|
|
244
|
+
solvePhase1();
|
|
245
|
+
analysis->simplexTimerStop(SimplexDualPhase1Clock);
|
|
246
|
+
info.dual_phase1_iteration_count +=
|
|
247
|
+
(ekk_instance_.iteration_count_ - it0);
|
|
248
|
+
} else if (solve_phase == kSolvePhase2) {
|
|
249
|
+
// Phase 2
|
|
250
|
+
analysis->simplexTimerStart(SimplexDualPhase2Clock);
|
|
251
|
+
solvePhase2();
|
|
252
|
+
analysis->simplexTimerStop(SimplexDualPhase2Clock);
|
|
253
|
+
info.dual_phase2_iteration_count +=
|
|
254
|
+
(ekk_instance_.iteration_count_ - it0);
|
|
255
|
+
} else {
|
|
256
|
+
// Should only be kSolvePhase1 or kSolvePhase2
|
|
257
|
+
model_status = HighsModelStatus::kSolveError;
|
|
258
|
+
return ekk_instance_.returnFromSolve(HighsStatus::kError);
|
|
259
|
+
}
|
|
260
|
+
// Return if bailing out from solve
|
|
261
|
+
if (ekk_instance_.solve_bailout_)
|
|
262
|
+
return ekk_instance_.returnFromSolve(HighsStatus::kWarning);
|
|
263
|
+
// Can have all possible cases of solve_phase
|
|
264
|
+
assert(solve_phase >= kSolvePhaseMin && solve_phase <= kSolvePhaseMax);
|
|
265
|
+
// Look for scenarios when the major solving loop ends
|
|
266
|
+
if (solve_phase == kSolvePhaseTabooBasis) {
|
|
267
|
+
// Only basis change is taboo
|
|
268
|
+
ekk_instance_.model_status_ = HighsModelStatus::kUnknown;
|
|
269
|
+
return ekk_instance_.returnFromSolve(HighsStatus::kWarning);
|
|
270
|
+
}
|
|
271
|
+
if (solve_phase == kSolvePhaseError) {
|
|
272
|
+
// Solver error so return HighsStatus::kError
|
|
273
|
+
assert(model_status == HighsModelStatus::kSolveError);
|
|
274
|
+
return ekk_instance_.returnFromSolve(HighsStatus::kError);
|
|
275
|
+
}
|
|
276
|
+
if (solve_phase == kSolvePhaseExit) {
|
|
277
|
+
// LP identified as not having an optimal solution
|
|
278
|
+
assert(model_status == HighsModelStatus::kUnboundedOrInfeasible ||
|
|
279
|
+
model_status == HighsModelStatus::kInfeasible);
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
if (solve_phase == kSolvePhaseOptimalCleanup ||
|
|
283
|
+
solve_phase == kSolvePhasePrimalInfeasibleCleanup) {
|
|
284
|
+
// Dual infeasibilities after phase 2 which ends either
|
|
285
|
+
//
|
|
286
|
+
// primal feasible with dual infeasibilities, so use primal
|
|
287
|
+
// simplex to clean up expecting to identify optimality
|
|
288
|
+
//
|
|
289
|
+
// primal infeasible with dual infeasibilities so use primal
|
|
290
|
+
// simplex to clean up expecting to identify (primal)
|
|
291
|
+
// infeasibility
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
// If solve_phase == kSolvePhaseOptimal == 0 then major solving
|
|
295
|
+
// loop ends naturally since solve_phase is false
|
|
296
|
+
}
|
|
297
|
+
// If bailing out, should have returned already
|
|
298
|
+
assert(!ekk_instance_.solve_bailout_);
|
|
299
|
+
// Should only have these cases
|
|
300
|
+
assert(solve_phase == kSolvePhaseExit || solve_phase == kSolvePhaseUnknown ||
|
|
301
|
+
solve_phase == kSolvePhaseOptimal ||
|
|
302
|
+
solve_phase == kSolvePhaseOptimalCleanup ||
|
|
303
|
+
solve_phase == kSolvePhasePrimalInfeasibleCleanup);
|
|
304
|
+
// Can't be solve_phase == kSolvePhase1 since this requires simplex
|
|
305
|
+
// solver to have continued after identifying dual infeasibility.
|
|
306
|
+
if (solve_phase == kSolvePhaseOptimalCleanup ||
|
|
307
|
+
solve_phase == kSolvePhasePrimalInfeasibleCleanup) {
|
|
308
|
+
ekk_instance_.dual_simplex_cleanup_level_++;
|
|
309
|
+
if (solve_phase == kSolvePhasePrimalInfeasibleCleanup) {
|
|
310
|
+
// Primal and dual infeasibilities aren't known when cleaning up
|
|
311
|
+
// after suspected unboundedness in dual phase 2. All that's
|
|
312
|
+
// known is that cost shifting was required to get dual
|
|
313
|
+
// feasibility after removing cost perturbations, and dual
|
|
314
|
+
// simplex iterations may also have been done. This is unlike
|
|
315
|
+
// clean-up of dual infeasibilities after suspected optimality,
|
|
316
|
+
// when no shifting and dual simplex iterations are done after
|
|
317
|
+
// removing cost perturbations.
|
|
318
|
+
//
|
|
319
|
+
// Determine the primal and dual infeasibilities
|
|
320
|
+
ekk_instance_.computeSimplexInfeasible();
|
|
321
|
+
}
|
|
322
|
+
if (ekk_instance_.dual_simplex_cleanup_level_ >
|
|
323
|
+
options.max_dual_simplex_cleanup_level) {
|
|
324
|
+
// No clean up. Dual simplex was optimal or unbounded with
|
|
325
|
+
// unperturbed costs, so say that the scaled LP has been solved
|
|
326
|
+
// optimally. Optimality or infeasibility for the unscaled LP
|
|
327
|
+
// are unlikely but will still be assessed honestly, so leave it
|
|
328
|
+
// to the user to decide whether the solution can be accepted.
|
|
329
|
+
highsLogDev(options.log_options, HighsLogType::kWarning,
|
|
330
|
+
"HEkkDual:: Cannot use level %" HIGHSINT_FORMAT
|
|
331
|
+
" primal simplex cleanup for %" HIGHSINT_FORMAT
|
|
332
|
+
" dual infeasibilities\n",
|
|
333
|
+
ekk_instance_.dual_simplex_cleanup_level_,
|
|
334
|
+
info.num_dual_infeasibilities);
|
|
335
|
+
if (solve_phase == kSolvePhaseOptimalCleanup) {
|
|
336
|
+
ekk_instance_.model_status_ = HighsModelStatus::kOptimal;
|
|
337
|
+
} else {
|
|
338
|
+
ekk_instance_.model_status_ = HighsModelStatus::kInfeasible;
|
|
339
|
+
}
|
|
340
|
+
} else {
|
|
341
|
+
// Use primal simplex to clean up. This usually yields
|
|
342
|
+
// optimality or infeasibility (according to whether solve_phase
|
|
343
|
+
// is kSolvePhaseOptimalCleanup or
|
|
344
|
+
// kSolvePhasePrimalInfeasibleCleanup) but can yield
|
|
345
|
+
// unboundedness. Time/iteration limit return is, of course,
|
|
346
|
+
// possible, as are solver error
|
|
347
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
348
|
+
"HEkkDual:: Using primal simplex to try to clean up num / "
|
|
349
|
+
"max / sum = %" HIGHSINT_FORMAT
|
|
350
|
+
" / %g / %g dual infeasibilities\n",
|
|
351
|
+
info.num_dual_infeasibilities, info.max_dual_infeasibility,
|
|
352
|
+
info.sum_dual_infeasibilities);
|
|
353
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
354
|
+
analysis->simplexTimerStart(SimplexPrimalPhase2Clock);
|
|
355
|
+
// Switch off any bound perturbation
|
|
356
|
+
double save_primal_simplex_bound_perturbation_multiplier =
|
|
357
|
+
info.primal_simplex_bound_perturbation_multiplier;
|
|
358
|
+
info.primal_simplex_bound_perturbation_multiplier = 0;
|
|
359
|
+
HEkkPrimal primal_solver(ekk_instance_);
|
|
360
|
+
HighsStatus call_status = primal_solver.solve(true);
|
|
361
|
+
// Restore any bound perturbation
|
|
362
|
+
info.primal_simplex_bound_perturbation_multiplier =
|
|
363
|
+
save_primal_simplex_bound_perturbation_multiplier;
|
|
364
|
+
analysis->simplexTimerStop(SimplexPrimalPhase2Clock);
|
|
365
|
+
assert(ekk_instance_.called_return_from_solve_);
|
|
366
|
+
return_status = interpretCallStatus(options.log_options, call_status,
|
|
367
|
+
return_status, "HEkkPrimal::solve");
|
|
368
|
+
// Reset called_return_from_solve_ to be false, since it's
|
|
369
|
+
// called for this solve
|
|
370
|
+
ekk_instance_.called_return_from_solve_ = false;
|
|
371
|
+
if (return_status != HighsStatus::kOk)
|
|
372
|
+
return ekk_instance_.returnFromSolve(return_status);
|
|
373
|
+
if (ekk_instance_.model_status_ == HighsModelStatus::kOptimal &&
|
|
374
|
+
info.num_primal_infeasibilities + info.num_dual_infeasibilities)
|
|
375
|
+
highsLogDev(options.log_options, HighsLogType::kWarning,
|
|
376
|
+
"HEkkDual:: Primal simplex clean up yields optimality, "
|
|
377
|
+
"but with %" HIGHSINT_FORMAT
|
|
378
|
+
" (max %g) primal infeasibilities and " HIGHSINT_FORMAT
|
|
379
|
+
" (max %g) dual infeasibilities\n",
|
|
380
|
+
info.num_primal_infeasibilities,
|
|
381
|
+
info.max_primal_infeasibility,
|
|
382
|
+
info.num_dual_infeasibilities, info.max_dual_infeasibility);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
assert(model_status == HighsModelStatus::kOptimal ||
|
|
386
|
+
model_status == HighsModelStatus::kInfeasible ||
|
|
387
|
+
model_status == HighsModelStatus::kUnbounded ||
|
|
388
|
+
model_status == HighsModelStatus::kUnboundedOrInfeasible);
|
|
389
|
+
if (ekk_instance_.debugOkForSolve(SimplexAlgorithm::kDual, solve_phase) ==
|
|
390
|
+
HighsDebugStatus::kLogicalError)
|
|
391
|
+
return ekk_instance_.returnFromSolve(HighsStatus::kError);
|
|
392
|
+
return ekk_instance_.returnFromSolve(HighsStatus::kOk);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
void HEkkDual::initialiseInstance() {
|
|
396
|
+
// Called in constructor for HEkkDual class
|
|
397
|
+
// Copy size, matrix and simplex NLA
|
|
398
|
+
|
|
399
|
+
solver_num_col = ekk_instance_.lp_.num_col_;
|
|
400
|
+
solver_num_row = ekk_instance_.lp_.num_row_;
|
|
401
|
+
solver_num_tot = solver_num_col + solver_num_row;
|
|
402
|
+
inv_solver_num_row = 1.0 / solver_num_row;
|
|
403
|
+
|
|
404
|
+
a_matrix = &ekk_instance_.lp_.a_matrix_;
|
|
405
|
+
simplex_nla = &ekk_instance_.simplex_nla_;
|
|
406
|
+
analysis = &ekk_instance_.analysis_;
|
|
407
|
+
|
|
408
|
+
// Copy pointers
|
|
409
|
+
jMove = ekk_instance_.basis_.nonbasicMove_.data();
|
|
410
|
+
workDual = ekk_instance_.info_.workDual_.data();
|
|
411
|
+
workValue = ekk_instance_.info_.workValue_.data();
|
|
412
|
+
workRange = ekk_instance_.info_.workRange_.data();
|
|
413
|
+
baseLower = ekk_instance_.info_.baseLower_.data();
|
|
414
|
+
baseUpper = ekk_instance_.info_.baseUpper_.data();
|
|
415
|
+
baseValue = ekk_instance_.info_.baseValue_.data();
|
|
416
|
+
|
|
417
|
+
// Setup local vectors
|
|
418
|
+
col_DSE.setup(solver_num_row);
|
|
419
|
+
col_BFRT.setup(solver_num_row);
|
|
420
|
+
col_aq.setup(solver_num_row);
|
|
421
|
+
row_ep.setup(solver_num_row);
|
|
422
|
+
row_ap.setup(solver_num_col);
|
|
423
|
+
|
|
424
|
+
dev_row_ep.setup(solver_num_row);
|
|
425
|
+
dev_col_DSE.setup(solver_num_row);
|
|
426
|
+
|
|
427
|
+
// Setup other buffers
|
|
428
|
+
dualRow.setup();
|
|
429
|
+
dualRHS.setup();
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
void HEkkDual::initialiseInstanceParallel(HEkk& simplex) {
|
|
433
|
+
// No need to call this with kSimplexStrategyDualPlain
|
|
434
|
+
if (ekk_instance_.info_.simplex_strategy == kSimplexStrategyDualPlain) return;
|
|
435
|
+
|
|
436
|
+
// Identify the (current) number of HiGHS tasks to be used
|
|
437
|
+
const HighsInt num_concurrency = ekk_instance_.info_.num_concurrency;
|
|
438
|
+
|
|
439
|
+
HighsInt pass_num_slice;
|
|
440
|
+
if (ekk_instance_.info_.simplex_strategy == kSimplexStrategyDualTasks) {
|
|
441
|
+
// Initialize for tasks
|
|
442
|
+
pass_num_slice = num_concurrency - 2;
|
|
443
|
+
assert(pass_num_slice > 0);
|
|
444
|
+
if (pass_num_slice <= 0) {
|
|
445
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kWarning,
|
|
446
|
+
"SIP trying to use using %" HIGHSINT_FORMAT
|
|
447
|
+
" slices due to concurrency (%" HIGHSINT_FORMAT
|
|
448
|
+
") being too small: results unpredictable\n",
|
|
449
|
+
pass_num_slice, num_concurrency);
|
|
450
|
+
}
|
|
451
|
+
} else {
|
|
452
|
+
// Initialize for multi
|
|
453
|
+
multi_num = num_concurrency;
|
|
454
|
+
if (multi_num < 1) multi_num = 1;
|
|
455
|
+
if (multi_num > kSimplexConcurrencyLimit)
|
|
456
|
+
multi_num = kSimplexConcurrencyLimit;
|
|
457
|
+
for (HighsInt i = 0; i < multi_num; i++) {
|
|
458
|
+
multi_choice[i].row_out = -1;
|
|
459
|
+
multi_choice[i].row_ep.setup(solver_num_row);
|
|
460
|
+
multi_choice[i].col_aq.setup(solver_num_row);
|
|
461
|
+
multi_choice[i].col_BFRT.setup(solver_num_row);
|
|
462
|
+
}
|
|
463
|
+
pass_num_slice = max(multi_num - 1, HighsInt{1});
|
|
464
|
+
assert(pass_num_slice > 0);
|
|
465
|
+
if (pass_num_slice <= 0) {
|
|
466
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kWarning,
|
|
467
|
+
"PAMI trying to use using %" HIGHSINT_FORMAT
|
|
468
|
+
" slices due to concurrency (%" HIGHSINT_FORMAT
|
|
469
|
+
") being too small: results unpredictable\n",
|
|
470
|
+
pass_num_slice, num_concurrency);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
// Create the multiple HEkkDualRow instances: one for each column
|
|
474
|
+
// slice
|
|
475
|
+
for (HighsInt i = 0; i < pass_num_slice; i++)
|
|
476
|
+
slice_dualRow.push_back(HEkkDualRow(simplex));
|
|
477
|
+
// Initialise the column slices
|
|
478
|
+
initSlice(pass_num_slice);
|
|
479
|
+
multi_iteration = 0;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
void HEkkDual::initSlice(const HighsInt initial_num_slice) {
|
|
483
|
+
// Number of slices
|
|
484
|
+
slice_num = initial_num_slice;
|
|
485
|
+
if (slice_num < 1) slice_num = 1;
|
|
486
|
+
assert(slice_num <= kHighsSlicedLimit);
|
|
487
|
+
if (slice_num > kHighsSlicedLimit) {
|
|
488
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kWarning,
|
|
489
|
+
"WARNING: %" HIGHSINT_FORMAT
|
|
490
|
+
" = slice_num > kHighsSlicedLimit = %" HIGHSINT_FORMAT
|
|
491
|
+
" so truncating "
|
|
492
|
+
"slice_num\n",
|
|
493
|
+
slice_num, kHighsSlicedLimit);
|
|
494
|
+
slice_num = kHighsSlicedLimit;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Alias to the matrix
|
|
498
|
+
const HighsInt* Astart = a_matrix->start_.data();
|
|
499
|
+
const HighsInt AcountX = Astart[solver_num_col];
|
|
500
|
+
|
|
501
|
+
// Figure out partition weight
|
|
502
|
+
double sliced_countX = AcountX / (double)slice_num;
|
|
503
|
+
slice_start[0] = 0;
|
|
504
|
+
for (HighsInt i = 0; i < slice_num - 1; i++) {
|
|
505
|
+
HighsInt endColumn = slice_start[i] + 1; // At least one column
|
|
506
|
+
HighsInt endX = Astart[endColumn];
|
|
507
|
+
HighsInt stopX = (i + 1) * sliced_countX;
|
|
508
|
+
while (endX < stopX) {
|
|
509
|
+
endX = Astart[++endColumn];
|
|
510
|
+
}
|
|
511
|
+
slice_start[i + 1] = endColumn;
|
|
512
|
+
if (endColumn >= solver_num_col) {
|
|
513
|
+
slice_num = i; // SHRINK
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
slice_start[slice_num] = solver_num_col;
|
|
518
|
+
|
|
519
|
+
// Partition the matrix, row_ap and related packet
|
|
520
|
+
vector<HighsInt> sliced_Astart;
|
|
521
|
+
for (HighsInt i = 0; i < slice_num; i++) {
|
|
522
|
+
// The matrix
|
|
523
|
+
HighsInt from_col = slice_start[i];
|
|
524
|
+
HighsInt to_col = slice_start[i + 1] - 1;
|
|
525
|
+
HighsInt slice_num_col = slice_start[i + 1] - from_col;
|
|
526
|
+
HighsInt from_el = Astart[from_col];
|
|
527
|
+
sliced_Astart.resize(slice_num_col + 1);
|
|
528
|
+
for (HighsInt k = 0; k <= slice_num_col; k++)
|
|
529
|
+
sliced_Astart[k] = Astart[k + from_col] - from_el;
|
|
530
|
+
slice_a_matrix[i].createSlice(ekk_instance_.lp_.a_matrix_, from_col,
|
|
531
|
+
to_col);
|
|
532
|
+
slice_ar_matrix[i].createRowwise(slice_a_matrix[i]);
|
|
533
|
+
|
|
534
|
+
// The row_ap and its packages
|
|
535
|
+
slice_row_ap[i].setup(slice_num_col);
|
|
536
|
+
slice_dualRow[i].setupSlice(slice_num_col);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
void HEkkDual::initialiseSolve() {
|
|
541
|
+
// Copy values of simplex solver options to dual simplex options
|
|
542
|
+
primal_feasibility_tolerance =
|
|
543
|
+
ekk_instance_.options_->primal_feasibility_tolerance;
|
|
544
|
+
dual_feasibility_tolerance =
|
|
545
|
+
ekk_instance_.options_->dual_feasibility_tolerance;
|
|
546
|
+
objective_bound = ekk_instance_.options_->objective_bound;
|
|
547
|
+
|
|
548
|
+
// Copy tolerances
|
|
549
|
+
// ToDo: Eliminate these horribly-named unnecessary copies!
|
|
550
|
+
Tp = primal_feasibility_tolerance;
|
|
551
|
+
Td = dual_feasibility_tolerance;
|
|
552
|
+
|
|
553
|
+
initial_basis_is_logical_ = true;
|
|
554
|
+
for (HighsInt iRow = 0; iRow < solver_num_row; iRow++) {
|
|
555
|
+
if (ekk_instance_.basis_.basicIndex_[iRow] < solver_num_col) {
|
|
556
|
+
initial_basis_is_logical_ = false;
|
|
557
|
+
break;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
interpretDualEdgeWeightStrategy(
|
|
562
|
+
ekk_instance_.info_.dual_edge_weight_strategy);
|
|
563
|
+
|
|
564
|
+
// Initialise model and run status values
|
|
565
|
+
ekk_instance_.model_status_ = HighsModelStatus::kNotset;
|
|
566
|
+
ekk_instance_.solve_bailout_ = false;
|
|
567
|
+
ekk_instance_.called_return_from_solve_ = false;
|
|
568
|
+
ekk_instance_.exit_algorithm_ = SimplexAlgorithm::kDual;
|
|
569
|
+
|
|
570
|
+
rebuild_reason = kRebuildReasonNo;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
void HEkkDual::solvePhase1() {
|
|
574
|
+
// Performs dual phase 1 iterations. Returns solve_phase with value
|
|
575
|
+
//
|
|
576
|
+
// kSolvePhaseError => Solver error
|
|
577
|
+
//
|
|
578
|
+
// kSolvePhaseTabooBasis => Only basis change is taboo
|
|
579
|
+
//
|
|
580
|
+
// kSolvePhaseExit => LP identified as dual infeasible
|
|
581
|
+
//
|
|
582
|
+
// kSolvePhaseUnknown => Back-tracking due to singularity
|
|
583
|
+
//
|
|
584
|
+
// kSolvePhase1 => Dual infeasibility suspected, but have to go out
|
|
585
|
+
// and back in to solvePhase1 to perform fresh rebuild. Also if
|
|
586
|
+
// bailing out due to reaching time/iteration limit.
|
|
587
|
+
//
|
|
588
|
+
// kSolvePhase2 => Continue with dual phase 2 iterations
|
|
589
|
+
|
|
590
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
591
|
+
HighsSimplexStatus& status = ekk_instance_.status_;
|
|
592
|
+
HighsModelStatus& model_status = ekk_instance_.model_status_;
|
|
593
|
+
// When starting a new phase the (updated) dual objective function
|
|
594
|
+
// value isn't known. Indicate this so that when the value computed
|
|
595
|
+
// from scratch in build() isn't checked against the updated
|
|
596
|
+
// value
|
|
597
|
+
status.has_primal_objective_value = false;
|
|
598
|
+
status.has_dual_objective_value = false;
|
|
599
|
+
// Set rebuild_reason so that it's assigned when first tested
|
|
600
|
+
rebuild_reason = kRebuildReasonNo;
|
|
601
|
+
// Use to set solve_phase = kSolvePhase1 and ekk_instance_.solve_bailout_ =
|
|
602
|
+
// false so they are set if solvePhase1() is called directly - but it never is
|
|
603
|
+
assert(solve_phase == kSolvePhase1);
|
|
604
|
+
assert(!ekk_instance_.solve_bailout_);
|
|
605
|
+
if (ekk_instance_.bailout()) return;
|
|
606
|
+
// Report the phase start
|
|
607
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kDetailed,
|
|
608
|
+
"dual-phase-1-start\n");
|
|
609
|
+
// Switch to dual phase 1 bounds
|
|
610
|
+
ekk_instance_.initialiseBound(SimplexAlgorithm::kDual, solve_phase);
|
|
611
|
+
ekk_instance_.initialiseNonbasicValueAndMove();
|
|
612
|
+
|
|
613
|
+
// If there's no backtracking basis, save the initial basis in case of
|
|
614
|
+
// backtracking
|
|
615
|
+
if (!info.valid_backtracking_basis_) ekk_instance_.putBacktrackingBasis();
|
|
616
|
+
|
|
617
|
+
// Main solving structure
|
|
618
|
+
analysis->simplexTimerStart(IterateClock);
|
|
619
|
+
for (;;) {
|
|
620
|
+
analysis->simplexTimerStart(IterateDualRebuildClock);
|
|
621
|
+
rebuild();
|
|
622
|
+
analysis->simplexTimerStop(IterateDualRebuildClock);
|
|
623
|
+
if (solve_phase == kSolvePhaseError) {
|
|
624
|
+
model_status = HighsModelStatus::kSolveError;
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
if (solve_phase == kSolvePhaseUnknown) {
|
|
628
|
+
// If backtracking, may change phase, so drop out
|
|
629
|
+
analysis->simplexTimerStop(IterateClock);
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
if (ekk_instance_.bailout()) break;
|
|
633
|
+
for (;;) {
|
|
634
|
+
if (debugDualSimplex("Before iteration") ==
|
|
635
|
+
HighsDebugStatus::kLogicalError) {
|
|
636
|
+
solve_phase = kSolvePhaseError;
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
switch (info.simplex_strategy) {
|
|
640
|
+
default:
|
|
641
|
+
case kSimplexStrategyDualPlain:
|
|
642
|
+
iterate();
|
|
643
|
+
break;
|
|
644
|
+
case kSimplexStrategyDualTasks:
|
|
645
|
+
iterateTasks();
|
|
646
|
+
break;
|
|
647
|
+
case kSimplexStrategyDualMulti:
|
|
648
|
+
iterateMulti();
|
|
649
|
+
break;
|
|
650
|
+
}
|
|
651
|
+
if (ekk_instance_.bailout()) break;
|
|
652
|
+
assert(solve_phase != kSolvePhaseTabooBasis);
|
|
653
|
+
if (rebuild_reason) break;
|
|
654
|
+
}
|
|
655
|
+
if (ekk_instance_.solve_bailout_) break;
|
|
656
|
+
// If the data are fresh from rebuild(), possibly break out of the
|
|
657
|
+
// outer loop to see what's occurred
|
|
658
|
+
//
|
|
659
|
+
// Deciding whether to rebuild is now more complicated if
|
|
660
|
+
// refactorization is being avoided, since
|
|
661
|
+
// status.has_fresh_rebuild being true may not imply that there is
|
|
662
|
+
// a fresh factorization
|
|
663
|
+
//
|
|
664
|
+
bool finished = status.has_fresh_rebuild &&
|
|
665
|
+
!ekk_instance_.rebuildRefactor(rebuild_reason);
|
|
666
|
+
if (finished && ekk_instance_.tabooBadBasisChange()) {
|
|
667
|
+
// A bad basis change has had to be made taboo without any other
|
|
668
|
+
// basis changes having been performed from a fresh rebuild. In
|
|
669
|
+
// other words, the only basis change that could be made is not
|
|
670
|
+
// permitted, so no definitive statement about the LP can be
|
|
671
|
+
// made.
|
|
672
|
+
solve_phase = kSolvePhaseTabooBasis;
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
if (finished) break;
|
|
676
|
+
}
|
|
677
|
+
analysis->simplexTimerStop(IterateClock);
|
|
678
|
+
// Possibly return due to bailing out, having now stopped
|
|
679
|
+
// IterateClock
|
|
680
|
+
if (ekk_instance_.solve_bailout_) return;
|
|
681
|
+
|
|
682
|
+
// If bailing out, should have done so already
|
|
683
|
+
assert(!ekk_instance_.solve_bailout_);
|
|
684
|
+
// Assess outcome of dual phase 1
|
|
685
|
+
if (row_out == kNoRowChosen) {
|
|
686
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kDetailed,
|
|
687
|
+
"dual-phase-1-optimal\n");
|
|
688
|
+
// Optimal in phase 1
|
|
689
|
+
if (info.dual_objective_value == 0) {
|
|
690
|
+
// Zero phase 1 objective so go to phase 2
|
|
691
|
+
//
|
|
692
|
+
// This is the usual way to exit phase 1. Although the test
|
|
693
|
+
// looks ambitious, the dual objective is the sum of products of
|
|
694
|
+
// primal and dual values for nonbasic variables. For dual
|
|
695
|
+
// simplex phase 1, the primal bounds are set so that when the
|
|
696
|
+
// dual value is feasible, the primal value is set to
|
|
697
|
+
// zero. Otherwise the value is +1/-1 according to the required
|
|
698
|
+
// sign of the dual, except for free variables, where the bounds
|
|
699
|
+
// are [-1000, 1000].
|
|
700
|
+
//
|
|
701
|
+
// OK if costs are perturbed, since they remain perturbed in phase 2 until
|
|
702
|
+
// the final clean-up
|
|
703
|
+
solve_phase = kSolvePhase2;
|
|
704
|
+
} else {
|
|
705
|
+
// A nonzero dual objective value at an optimal solution of
|
|
706
|
+
// phase 1 means that there may be dual infeasibilities. If the
|
|
707
|
+
// objective value is very negative, then it's clear
|
|
708
|
+
// enough. However, if it's small in magnitude, it could be the
|
|
709
|
+
// sum of values, all of which are smaller than the dual
|
|
710
|
+
// feasibility tolerance. Plus there may be cost perturbations
|
|
711
|
+
// to remove before reliable conclusions on dual infeasibility
|
|
712
|
+
// of the (scaled) LP being solved can be drawn.
|
|
713
|
+
//
|
|
714
|
+
// If assessPhase1Optimality() is happy that there are no dual
|
|
715
|
+
// infeasibilities, it will set solve_phase = kSolvePhase2;
|
|
716
|
+
assessPhase1Optimality();
|
|
717
|
+
}
|
|
718
|
+
} else if (rebuild_reason == kRebuildReasonChooseColumnFail ||
|
|
719
|
+
rebuild_reason == kRebuildReasonExcessivePrimalValue) {
|
|
720
|
+
// chooseColumn has failed or excessive primal values have been
|
|
721
|
+
// created Behave as "Report strange issues" below
|
|
722
|
+
solve_phase = kSolvePhaseError;
|
|
723
|
+
// Solve error is opaque to users, so put in some logging
|
|
724
|
+
if (rebuild_reason == kRebuildReasonChooseColumnFail) {
|
|
725
|
+
highsLogUser(
|
|
726
|
+
ekk_instance_.options_->log_options, HighsLogType::kError,
|
|
727
|
+
"Dual simplex ratio test failed due to excessive dual values: "
|
|
728
|
+
"consider scaling down the LP objective coefficients\n");
|
|
729
|
+
} else {
|
|
730
|
+
highsLogUser(ekk_instance_.options_->log_options, HighsLogType::kError,
|
|
731
|
+
"Dual simplex detected excessive primal values: consider "
|
|
732
|
+
"scaling down the LP bounds\n");
|
|
733
|
+
}
|
|
734
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
735
|
+
"dual-phase-1-not-solved\n");
|
|
736
|
+
model_status = HighsModelStatus::kSolveError;
|
|
737
|
+
} else if (variable_in == -1) {
|
|
738
|
+
// We got dual phase 1 unbounded - strange
|
|
739
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
740
|
+
"dual-phase-1-unbounded\n");
|
|
741
|
+
// This use of costs_alt_perturbed is (unsurprisingly) not
|
|
742
|
+
// executed by ctest
|
|
743
|
+
//
|
|
744
|
+
// assert(99==1);
|
|
745
|
+
if (ekk_instance_.info_.costs_perturbed) {
|
|
746
|
+
// Clean up perturbation
|
|
747
|
+
cleanup();
|
|
748
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kWarning,
|
|
749
|
+
"Cleaning up cost perturbation when unbounded in phase 1\n");
|
|
750
|
+
if (dualInfeasCount == 0) {
|
|
751
|
+
// No dual infeasibilities and (since unbounded) at least zero
|
|
752
|
+
// phase 1 objective so go to phase 2
|
|
753
|
+
solve_phase = kSolvePhase2;
|
|
754
|
+
}
|
|
755
|
+
} else {
|
|
756
|
+
// Report strange issues
|
|
757
|
+
solve_phase = kSolvePhaseError;
|
|
758
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
759
|
+
"dual-phase-1-not-solved\n");
|
|
760
|
+
model_status = HighsModelStatus::kSolveError;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Debug here since not all simplex data will be correct until after
|
|
765
|
+
// rebuild() when switching to Phase 2
|
|
766
|
+
//
|
|
767
|
+
// Also have to avoid debug when the model status is not set and
|
|
768
|
+
// there are dual infeasibilities, since this happens legitimately
|
|
769
|
+
// when the LP is dual infeasible. However, the model status can't
|
|
770
|
+
// be set to dual infeasible until perturbations have been removed.
|
|
771
|
+
//
|
|
772
|
+
const bool no_debug = ekk_instance_.info_.num_dual_infeasibilities > 0 &&
|
|
773
|
+
model_status == HighsModelStatus::kNotset;
|
|
774
|
+
if (!no_debug) {
|
|
775
|
+
if (debugDualSimplex("End of solvePhase1") ==
|
|
776
|
+
HighsDebugStatus::kLogicalError) {
|
|
777
|
+
solve_phase = kSolvePhaseError;
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// Can also get here with solve_phase = kSolvePhaseError
|
|
783
|
+
const bool solve_phase_ok =
|
|
784
|
+
solve_phase == kSolvePhase1 || solve_phase == kSolvePhase2 ||
|
|
785
|
+
solve_phase == kSolvePhaseExit || solve_phase == kSolvePhaseError;
|
|
786
|
+
if (!solve_phase_ok)
|
|
787
|
+
highsLogDev(
|
|
788
|
+
ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
789
|
+
"HEkkDual::solvePhase1 solve_phase == %d (solve call %d; iter %d)\n",
|
|
790
|
+
(int)solve_phase, (int)ekk_instance_.debug_solve_call_num_,
|
|
791
|
+
(int)ekk_instance_.iteration_count_);
|
|
792
|
+
assert(solve_phase_ok);
|
|
793
|
+
if (solve_phase == kSolvePhase2 || solve_phase == kSolvePhaseExit ||
|
|
794
|
+
solve_phase == kSolvePhaseError) {
|
|
795
|
+
// Moving to phase 2 or exiting, so make sure that the simplex
|
|
796
|
+
// bounds and nonbasic value/move correspond to the LP
|
|
797
|
+
ekk_instance_.initialiseBound(SimplexAlgorithm::kDual, kSolvePhase2);
|
|
798
|
+
ekk_instance_.initialiseNonbasicValueAndMove();
|
|
799
|
+
if (solve_phase == kSolvePhase2) {
|
|
800
|
+
// Moving to phase 2 so possibly reinstate cost perturbation
|
|
801
|
+
if (ekk_instance_.dual_simplex_phase1_cleanup_level_ <
|
|
802
|
+
ekk_instance_.options_->max_dual_simplex_phase1_cleanup_level) {
|
|
803
|
+
// Allow cost perturbation for now, but may have to prevent it
|
|
804
|
+
// to avoid cleanup-perturbation loops
|
|
805
|
+
info.allow_cost_shifting = true;
|
|
806
|
+
info.allow_cost_perturbation = true;
|
|
807
|
+
}
|
|
808
|
+
// Comment if cost perturbation is not permitted
|
|
809
|
+
if (!info.allow_cost_perturbation)
|
|
810
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kWarning,
|
|
811
|
+
"Moving to phase 2, but not allowing cost perturbation\n");
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
void HEkkDual::solvePhase2() {
|
|
818
|
+
// Performs dual phase 2 iterations. Returns solve_phase with value
|
|
819
|
+
//
|
|
820
|
+
// kSolvePhaseError => Solver error
|
|
821
|
+
//
|
|
822
|
+
// kSolvePhaseTabooBasis => Only basis change is taboo
|
|
823
|
+
//
|
|
824
|
+
// kSolvePhaseExit => LP identified as not having an optimal solution
|
|
825
|
+
//
|
|
826
|
+
// kSolvePhaseUnknown => Back-tracking due to singularity
|
|
827
|
+
//
|
|
828
|
+
// kSolvePhaseOptimal => Primal feasible and no dual infeasibilities =>
|
|
829
|
+
// Optimal
|
|
830
|
+
//
|
|
831
|
+
// kSolvePhase1 => Primal feasible and dual infeasibilities.
|
|
832
|
+
//
|
|
833
|
+
// kSolvePhase2 => Dual unboundedness suspected, but have to go out
|
|
834
|
+
// and back in to solvePhase2 to perform fresh rebuild. Also if
|
|
835
|
+
// bailing out due to reaching time/iteration limit or dual
|
|
836
|
+
// objective
|
|
837
|
+
//
|
|
838
|
+
// kSolvePhaseOptimalCleanup => Continue with primal phase 2 iterations to
|
|
839
|
+
// clean up dual infeasibilities
|
|
840
|
+
//
|
|
841
|
+
// Have to set multi_chooseAgain = 1 since it may come in set to 0
|
|
842
|
+
// from the end of Phase 1, implying that there is a set of
|
|
843
|
+
// attractive candidates to choose from in minorChooseRow() so
|
|
844
|
+
// majorChooseRow() is unnecessary. If there are no such candidates
|
|
845
|
+
// optimality may be declared in error. Previously, the forced
|
|
846
|
+
// reinversion in the rebuild at the start of phase 2 led to
|
|
847
|
+
// update_count == 0 causing multi_chooseAgain to be set to 1 in
|
|
848
|
+
// majorChooseRow!
|
|
849
|
+
multi_chooseAgain = 1;
|
|
850
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
851
|
+
HighsSimplexStatus& status = ekk_instance_.status_;
|
|
852
|
+
HighsModelStatus& model_status = ekk_instance_.model_status_;
|
|
853
|
+
// When starting a new phase the (updated) dual objective function
|
|
854
|
+
// value isn't known. Indicate this so that when the value computed
|
|
855
|
+
// from scratch in build() isn't checked against the updated
|
|
856
|
+
// value
|
|
857
|
+
status.has_primal_objective_value = false;
|
|
858
|
+
status.has_dual_objective_value = false;
|
|
859
|
+
// Set rebuild_reason so that it's assigned when first tested
|
|
860
|
+
rebuild_reason = kRebuildReasonNo;
|
|
861
|
+
// Set solve_phase = kSolvePhase2 and ekk_instance_.solve_bailout_ = false so
|
|
862
|
+
// they are set if solvePhase2() is called directly
|
|
863
|
+
solve_phase = kSolvePhase2;
|
|
864
|
+
ekk_instance_.solve_bailout_ = false;
|
|
865
|
+
if (ekk_instance_.bailout()) return;
|
|
866
|
+
// Report the phase start
|
|
867
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kDetailed,
|
|
868
|
+
"dual-phase-2-start\n");
|
|
869
|
+
// Collect free variables
|
|
870
|
+
dualRow.createFreelist();
|
|
871
|
+
|
|
872
|
+
// If there's no backtracking basis, save the initial basis in case
|
|
873
|
+
// of backtracking
|
|
874
|
+
if (!info.valid_backtracking_basis_) ekk_instance_.putBacktrackingBasis();
|
|
875
|
+
|
|
876
|
+
// Main solving structure
|
|
877
|
+
analysis->simplexTimerStart(IterateClock);
|
|
878
|
+
for (;;) {
|
|
879
|
+
// Outer loop of solvePhase2()
|
|
880
|
+
// Rebuild all values, reinverting B if updates have been performed
|
|
881
|
+
analysis->simplexTimerStart(IterateDualRebuildClock);
|
|
882
|
+
rebuild();
|
|
883
|
+
analysis->simplexTimerStop(IterateDualRebuildClock);
|
|
884
|
+
if (solve_phase == kSolvePhaseError) {
|
|
885
|
+
model_status = HighsModelStatus::kSolveError;
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
if (solve_phase == kSolvePhaseUnknown) {
|
|
889
|
+
// If backtracking, may change phase, so drop out
|
|
890
|
+
analysis->simplexTimerStop(IterateClock);
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
if (ekk_instance_.bailout()) break;
|
|
894
|
+
if (bailoutOnDualObjective()) break;
|
|
895
|
+
if (dualInfeasCount > 0) break;
|
|
896
|
+
for (;;) {
|
|
897
|
+
// Inner loop of solvePhase2()
|
|
898
|
+
// Performs one iteration in case kSimplexStrategyDualPlain:
|
|
899
|
+
if (debugDualSimplex("Before iteration") ==
|
|
900
|
+
HighsDebugStatus::kLogicalError) {
|
|
901
|
+
solve_phase = kSolvePhaseError;
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
switch (info.simplex_strategy) {
|
|
905
|
+
default:
|
|
906
|
+
case kSimplexStrategyDualPlain:
|
|
907
|
+
iterate();
|
|
908
|
+
break;
|
|
909
|
+
case kSimplexStrategyDualTasks:
|
|
910
|
+
iterateTasks();
|
|
911
|
+
break;
|
|
912
|
+
case kSimplexStrategyDualMulti:
|
|
913
|
+
iterateMulti();
|
|
914
|
+
break;
|
|
915
|
+
}
|
|
916
|
+
if (ekk_instance_.bailout()) break;
|
|
917
|
+
if (bailoutOnDualObjective()) break;
|
|
918
|
+
assert(solve_phase != kSolvePhaseTabooBasis);
|
|
919
|
+
|
|
920
|
+
// If possibly dual unbounded, assess whether this implies
|
|
921
|
+
// primal infeasibility.
|
|
922
|
+
if (rebuild_reason == kRebuildReasonPossiblyDualUnbounded)
|
|
923
|
+
assessPossiblyDualUnbounded();
|
|
924
|
+
|
|
925
|
+
if (rebuild_reason) break;
|
|
926
|
+
}
|
|
927
|
+
if (ekk_instance_.solve_bailout_) break;
|
|
928
|
+
// If the data are fresh from rebuild(), possibly break out of the
|
|
929
|
+
// outer loop to see what's occurred
|
|
930
|
+
bool finished = status.has_fresh_rebuild &&
|
|
931
|
+
!ekk_instance_.rebuildRefactor(rebuild_reason);
|
|
932
|
+
// ToDo: Handle the following more elegantly as the first case of
|
|
933
|
+
// "Assess outcome of dual phase 2"
|
|
934
|
+
if (finished && ekk_instance_.tabooBadBasisChange()) {
|
|
935
|
+
// A bad basis change has had to be made taboo without any other
|
|
936
|
+
// basis changes having been performed from a fresh rebuild. In
|
|
937
|
+
// other words, the only basis change that could be made is not
|
|
938
|
+
// permitted, so no definitive statement about the LP can be
|
|
939
|
+
// made.
|
|
940
|
+
solve_phase = kSolvePhaseTabooBasis;
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
if (finished) break;
|
|
944
|
+
}
|
|
945
|
+
analysis->simplexTimerStop(IterateClock);
|
|
946
|
+
// Possibly return due to bailing out, having now stopped
|
|
947
|
+
// IterateClock
|
|
948
|
+
if (ekk_instance_.solve_bailout_) return;
|
|
949
|
+
|
|
950
|
+
// If bailing out, should have done so already
|
|
951
|
+
assert(!ekk_instance_.solve_bailout_);
|
|
952
|
+
// Assess outcome of dual phase 2
|
|
953
|
+
if (dualInfeasCount > 0) {
|
|
954
|
+
// There are dual infeasibilities so possibly switch to Phase 1 and
|
|
955
|
+
// return. "Possibly" because, if dual infeasibility has already
|
|
956
|
+
// been shown, primal simplex is used to distinguish primal
|
|
957
|
+
// unboundedness from primal infeasibility
|
|
958
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kDetailed,
|
|
959
|
+
"dual-phase-2-found-free\n");
|
|
960
|
+
solve_phase = kSolvePhase1;
|
|
961
|
+
} else if (row_out == kNoRowChosen) {
|
|
962
|
+
// There is no candidate in CHUZR, even after rebuild so probably optimal
|
|
963
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kDetailed,
|
|
964
|
+
"dual-phase-2-optimal\n");
|
|
965
|
+
// Remove any cost perturbations and see if basis is still dual feasible
|
|
966
|
+
cleanup();
|
|
967
|
+
if (dualInfeasCount > 0) {
|
|
968
|
+
// There are dual infeasibilities, so consider performing primal
|
|
969
|
+
// simplex iterations to get dual feasibility
|
|
970
|
+
solve_phase = kSolvePhaseOptimalCleanup;
|
|
971
|
+
} else {
|
|
972
|
+
// There are no dual infeasibilities so optimal!
|
|
973
|
+
solve_phase = kSolvePhaseOptimal;
|
|
974
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kDetailed,
|
|
975
|
+
"problem-optimal\n");
|
|
976
|
+
model_status = HighsModelStatus::kOptimal;
|
|
977
|
+
}
|
|
978
|
+
} else if (rebuild_reason == kRebuildReasonChooseColumnFail ||
|
|
979
|
+
rebuild_reason == kRebuildReasonExcessivePrimalValue) {
|
|
980
|
+
// chooseColumn has failed or excessive primal values have been
|
|
981
|
+
// created Behave as "Report strange issues" below
|
|
982
|
+
solve_phase = kSolvePhaseError;
|
|
983
|
+
// Solve error is opaque to users, so put in some logging
|
|
984
|
+
if (rebuild_reason == kRebuildReasonChooseColumnFail) {
|
|
985
|
+
highsLogUser(
|
|
986
|
+
ekk_instance_.options_->log_options, HighsLogType::kError,
|
|
987
|
+
"Dual simplex ratio test failed due to excessive dual values: "
|
|
988
|
+
"consider scaling down the LP objective coefficients\n");
|
|
989
|
+
} else {
|
|
990
|
+
highsLogUser(ekk_instance_.options_->log_options, HighsLogType::kError,
|
|
991
|
+
"Dual simplex detected excessive primal values: consider "
|
|
992
|
+
"scaling down the LP bounds\n");
|
|
993
|
+
}
|
|
994
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
995
|
+
"dual-phase-2-not-solved\n");
|
|
996
|
+
model_status = HighsModelStatus::kSolveError;
|
|
997
|
+
} else {
|
|
998
|
+
// Can only be that primal infeasibility has been detected
|
|
999
|
+
assert(model_status == HighsModelStatus::kInfeasible);
|
|
1000
|
+
assert(solve_phase == kSolvePhaseExit);
|
|
1001
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
1002
|
+
"problem-primal-infeasible\n");
|
|
1003
|
+
}
|
|
1004
|
+
// Possibly debug unless before primal simplex clean-up (in which
|
|
1005
|
+
// case there will be dual infeasibilities).
|
|
1006
|
+
if (solve_phase != kSolvePhaseOptimalCleanup) {
|
|
1007
|
+
if (debugDualSimplex("End of solvePhase2") ==
|
|
1008
|
+
HighsDebugStatus::kLogicalError) {
|
|
1009
|
+
solve_phase = kSolvePhaseError;
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
void HEkkDual::rebuild() {
|
|
1017
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
1018
|
+
HighsSimplexStatus& status = ekk_instance_.status_;
|
|
1019
|
+
// Clear taboo flag from any bad basis changes
|
|
1020
|
+
ekk_instance_.clearBadBasisChangeTabooFlag();
|
|
1021
|
+
|
|
1022
|
+
// Decide whether refactorization should be performed
|
|
1023
|
+
const bool refactor_basis_matrix =
|
|
1024
|
+
ekk_instance_.rebuildRefactor(rebuild_reason);
|
|
1025
|
+
|
|
1026
|
+
// Take a local copy of the rebuild reason and then reset the global value
|
|
1027
|
+
const HighsInt local_rebuild_reason = rebuild_reason;
|
|
1028
|
+
rebuild_reason = kRebuildReasonNo;
|
|
1029
|
+
if (refactor_basis_matrix) {
|
|
1030
|
+
// Get a nonsingular inverse if possible. One of three things
|
|
1031
|
+
// happens: Current basis is nonsingular; Current basis is
|
|
1032
|
+
// singular and last nonsingular basis is refactorized as
|
|
1033
|
+
// nonsingular - or found singular. Latter is code failure.
|
|
1034
|
+
if (!ekk_instance_.getNonsingularInverse(solve_phase)) {
|
|
1035
|
+
solve_phase = kSolvePhaseError;
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
// Record the synthetic clock for INVERT, and zero it for UPDATE
|
|
1039
|
+
ekk_instance_.resetSyntheticClock();
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
HighsInt alt_debug_level = -1;
|
|
1043
|
+
// if (ekk_instance_.debug_solve_report_) alt_debug_level =
|
|
1044
|
+
// kHighsDebugLevelExpensive;
|
|
1045
|
+
ekk_instance_.debugNlaCheckInvert("HEkkDual::rebuild", alt_debug_level);
|
|
1046
|
+
|
|
1047
|
+
if (!ekk_instance_.status_.has_ar_matrix) {
|
|
1048
|
+
// Don't have the row-wise matrix, so reinitialise it
|
|
1049
|
+
//
|
|
1050
|
+
// Should only happen when backtracking
|
|
1051
|
+
assert(info.backtracking_);
|
|
1052
|
+
ekk_instance_.initialisePartitionedRowwiseMatrix();
|
|
1053
|
+
assert(ekk_instance_.ar_matrix_.debugPartitionOk(
|
|
1054
|
+
ekk_instance_.basis_.nonbasicFlag_.data()));
|
|
1055
|
+
}
|
|
1056
|
+
// Record whether the update objective value should be tested. If
|
|
1057
|
+
// the objective value is known, then the updated objective value
|
|
1058
|
+
// should be correct - once the correction due to recomputing the
|
|
1059
|
+
// dual values has been applied.
|
|
1060
|
+
//
|
|
1061
|
+
// Note that computePrimalObjectiveValue sets
|
|
1062
|
+
// has_primal_objective_value
|
|
1063
|
+
const bool check_updated_objective_value = status.has_dual_objective_value;
|
|
1064
|
+
double previous_dual_objective_value = -kHighsInf;
|
|
1065
|
+
if (check_updated_objective_value) {
|
|
1066
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase,
|
|
1067
|
+
// "Before computeDual");
|
|
1068
|
+
previous_dual_objective_value = info.updated_dual_objective_value;
|
|
1069
|
+
} else {
|
|
1070
|
+
// Reset the knowledge of previous objective values
|
|
1071
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm, -1, "");
|
|
1072
|
+
}
|
|
1073
|
+
// Recompute dual solution
|
|
1074
|
+
ekk_instance_.computeDual();
|
|
1075
|
+
|
|
1076
|
+
if (info.backtracking_) {
|
|
1077
|
+
// If backtracking, may change phase, so drop out
|
|
1078
|
+
solve_phase = kSolvePhaseUnknown;
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
analysis->simplexTimerStart(CorrectDualClock);
|
|
1082
|
+
correctDualInfeasibilities(dualInfeasCount);
|
|
1083
|
+
analysis->simplexTimerStop(CorrectDualClock);
|
|
1084
|
+
|
|
1085
|
+
// Recompute primal solution
|
|
1086
|
+
ekk_instance_.computePrimal();
|
|
1087
|
+
|
|
1088
|
+
// Collect primal infeasible as a list
|
|
1089
|
+
analysis->simplexTimerStart(CollectPrIfsClock);
|
|
1090
|
+
dualRHS.createArrayOfPrimalInfeasibilities();
|
|
1091
|
+
dualRHS.createInfeasList(ekk_instance_.info_.col_aq_density);
|
|
1092
|
+
analysis->simplexTimerStop(CollectPrIfsClock);
|
|
1093
|
+
|
|
1094
|
+
// Dual objective section
|
|
1095
|
+
//
|
|
1096
|
+
ekk_instance_.computeDualObjectiveValue(solve_phase);
|
|
1097
|
+
|
|
1098
|
+
if (check_updated_objective_value) {
|
|
1099
|
+
// Apply the objective value correction due to computing duals
|
|
1100
|
+
// from scratch.
|
|
1101
|
+
const double dual_objective_value_correction =
|
|
1102
|
+
info.dual_objective_value - previous_dual_objective_value;
|
|
1103
|
+
info.updated_dual_objective_value += dual_objective_value_correction;
|
|
1104
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm);
|
|
1105
|
+
}
|
|
1106
|
+
// Now that there's a new dual_objective_value, reset the updated
|
|
1107
|
+
// value
|
|
1108
|
+
info.updated_dual_objective_value = info.dual_objective_value;
|
|
1109
|
+
|
|
1110
|
+
if (!info.run_quiet) {
|
|
1111
|
+
ekk_instance_.computeInfeasibilitiesForReporting(SimplexAlgorithm::kDual,
|
|
1112
|
+
solve_phase);
|
|
1113
|
+
reportRebuild(local_rebuild_reason);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// Record the synthetic clock for INVERT, and zero it for UPDATE
|
|
1117
|
+
ekk_instance_.resetSyntheticClock();
|
|
1118
|
+
|
|
1119
|
+
// Dual simplex doesn't maintain the number of primal
|
|
1120
|
+
// infeasibilities, so set it to an illegal value now
|
|
1121
|
+
ekk_instance_.invalidatePrimalInfeasibilityRecord();
|
|
1122
|
+
// Although dual simplex should always be dual feasible,
|
|
1123
|
+
// infeasibilities are only corrected in rebuild
|
|
1124
|
+
ekk_instance_.invalidateDualInfeasibilityRecord();
|
|
1125
|
+
|
|
1126
|
+
// Data are fresh from rebuild
|
|
1127
|
+
status.has_fresh_rebuild = true;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
void HEkkDual::cleanup() {
|
|
1131
|
+
if (solve_phase == kSolvePhase1) {
|
|
1132
|
+
// Take action to prevent infinite loop. Shouldn't get to this
|
|
1133
|
+
// stage, since cost perturbation isn't permitted unless the dual
|
|
1134
|
+
// simplex phase 1 cleanup level is less than the limit
|
|
1135
|
+
ekk_instance_.dual_simplex_phase1_cleanup_level_++;
|
|
1136
|
+
const bool excessive_cleanup_calls =
|
|
1137
|
+
ekk_instance_.dual_simplex_phase1_cleanup_level_ >
|
|
1138
|
+
ekk_instance_.options_->max_dual_simplex_phase1_cleanup_level;
|
|
1139
|
+
if (excessive_cleanup_calls) {
|
|
1140
|
+
highsLogDev(
|
|
1141
|
+
ekk_instance_.options_->log_options, HighsLogType::kError,
|
|
1142
|
+
"Dual simplex cleanup level has exceeded limit of %d\n",
|
|
1143
|
+
(int)ekk_instance_.options_->max_dual_simplex_phase1_cleanup_level);
|
|
1144
|
+
assert(!excessive_cleanup_calls);
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kDetailed,
|
|
1148
|
+
"dual-cleanup-shift\n");
|
|
1149
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
1150
|
+
// Remove perturbation and don't permit further perturbation
|
|
1151
|
+
ekk_instance_.initialiseCost(SimplexAlgorithm::kDual, kSolvePhaseUnknown);
|
|
1152
|
+
info.allow_cost_perturbation = false;
|
|
1153
|
+
// No solve_phase term in initialiseBound is surely an omission -
|
|
1154
|
+
// when cleanup called in phase 1
|
|
1155
|
+
ekk_instance_.initialiseBound(SimplexAlgorithm::kDual, solve_phase);
|
|
1156
|
+
// Possibly take a copy of the original duals before recomputing them
|
|
1157
|
+
vector<double> original_workDual;
|
|
1158
|
+
if (ekk_instance_.options_->highs_debug_level > kHighsDebugLevelCheap)
|
|
1159
|
+
original_workDual = info.workDual_;
|
|
1160
|
+
// Compute the dual values
|
|
1161
|
+
ekk_instance_.computeDual();
|
|
1162
|
+
// Possibly analyse the change in duals
|
|
1163
|
+
// debugCleanup(ekk_instance_, original_workDual);
|
|
1164
|
+
// Compute the dual infeasibilities
|
|
1165
|
+
ekk_instance_.computeSimplexDualInfeasible();
|
|
1166
|
+
dualInfeasCount = ekk_instance_.info_.num_dual_infeasibilities;
|
|
1167
|
+
|
|
1168
|
+
// Compute the dual objective value
|
|
1169
|
+
ekk_instance_.computeDualObjectiveValue(solve_phase);
|
|
1170
|
+
// Now that there's a new dual_objective_value, reset the updated
|
|
1171
|
+
// value
|
|
1172
|
+
info.updated_dual_objective_value = info.dual_objective_value;
|
|
1173
|
+
|
|
1174
|
+
if (!info.run_quiet) {
|
|
1175
|
+
// Report the primal infeasibilities
|
|
1176
|
+
ekk_instance_.computeSimplexPrimalInfeasible();
|
|
1177
|
+
// In phase 1, report the simplex LP dual infeasibilities
|
|
1178
|
+
// In phase 2, report the simplex dual infeasibilities (known)
|
|
1179
|
+
if (solve_phase == kSolvePhase1)
|
|
1180
|
+
ekk_instance_.computeSimplexLpDualInfeasible();
|
|
1181
|
+
reportRebuild(kRebuildReasonCleanup);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
void HEkkDual::iterate() {
|
|
1186
|
+
// This is the main iteration loop for dual revised simplex. All the
|
|
1187
|
+
// methods have as their first line if (rebuild_reason) return;, where
|
|
1188
|
+
// rebuild_reason is, for example, set to 1 when CHUZR finds no
|
|
1189
|
+
// candidate. This causes a break from the inner loop of
|
|
1190
|
+
// solvePhase% and, hence, a call to rebuild()
|
|
1191
|
+
|
|
1192
|
+
// Reporting:
|
|
1193
|
+
// Row-wise matrix after update in updateMatrix(variable_in, variable_out);
|
|
1194
|
+
|
|
1195
|
+
const HighsInt from_check_iter = 0;
|
|
1196
|
+
const HighsInt to_check_iter = from_check_iter + 100;
|
|
1197
|
+
if (ekk_instance_.debug_solve_report_) {
|
|
1198
|
+
ekk_instance_.debug_iteration_report_ =
|
|
1199
|
+
ekk_instance_.iteration_count_ >= from_check_iter &&
|
|
1200
|
+
ekk_instance_.iteration_count_ <= to_check_iter;
|
|
1201
|
+
if (ekk_instance_.debug_iteration_report_) {
|
|
1202
|
+
printf("HEkkDual::iterate Debug iteration %d\n",
|
|
1203
|
+
(int)ekk_instance_.iteration_count_);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
analysis->simplexTimerStart(IterateChuzrClock);
|
|
1208
|
+
chooseRow();
|
|
1209
|
+
analysis->simplexTimerStop(IterateChuzrClock);
|
|
1210
|
+
|
|
1211
|
+
analysis->simplexTimerStart(IterateChuzcClock);
|
|
1212
|
+
chooseColumn(&row_ep);
|
|
1213
|
+
analysis->simplexTimerStop(IterateChuzcClock);
|
|
1214
|
+
|
|
1215
|
+
if (isBadBasisChange()) return;
|
|
1216
|
+
|
|
1217
|
+
analysis->simplexTimerStart(IterateFtranClock);
|
|
1218
|
+
updateFtranBFRT();
|
|
1219
|
+
|
|
1220
|
+
// updateFtran(); computes the pivotal column in the data structure "column"
|
|
1221
|
+
updateFtran();
|
|
1222
|
+
|
|
1223
|
+
// updateFtranDSE performs the DSE FTRAN on pi_p
|
|
1224
|
+
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge)
|
|
1225
|
+
updateFtranDSE(&row_ep);
|
|
1226
|
+
analysis->simplexTimerStop(IterateFtranClock);
|
|
1227
|
+
|
|
1228
|
+
// updateVerify() Checks row-wise pivot against column-wise pivot for
|
|
1229
|
+
// numerical trouble
|
|
1230
|
+
analysis->simplexTimerStart(IterateVerifyClock);
|
|
1231
|
+
updateVerify();
|
|
1232
|
+
analysis->simplexTimerStop(IterateVerifyClock);
|
|
1233
|
+
|
|
1234
|
+
// updateDual() Updates the dual values
|
|
1235
|
+
analysis->simplexTimerStart(IterateDualClock);
|
|
1236
|
+
updateDual();
|
|
1237
|
+
analysis->simplexTimerStop(IterateDualClock);
|
|
1238
|
+
|
|
1239
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase, "Before
|
|
1240
|
+
// updatePrimal");
|
|
1241
|
+
// updatePrimal(&row_ep); Updates the primal values and the edge weights
|
|
1242
|
+
analysis->simplexTimerStart(IteratePrimalClock);
|
|
1243
|
+
updatePrimal(&row_ep);
|
|
1244
|
+
analysis->simplexTimerStop(IteratePrimalClock);
|
|
1245
|
+
// After primal update in dual simplex the primal objective value is not known
|
|
1246
|
+
ekk_instance_.status_.has_primal_objective_value = false;
|
|
1247
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase, "After
|
|
1248
|
+
// updatePrimal");
|
|
1249
|
+
|
|
1250
|
+
// Update the records of chosen rows and pivots
|
|
1251
|
+
// ekk_instance_.info_.pivot_.push_back(alpha_row);
|
|
1252
|
+
// ekk_instance_.info_.index_chosen_.push_back(row_out);
|
|
1253
|
+
|
|
1254
|
+
// Update the basis representation
|
|
1255
|
+
analysis->simplexTimerStart(IteratePivotsClock);
|
|
1256
|
+
updatePivots();
|
|
1257
|
+
analysis->simplexTimerStop(IteratePivotsClock);
|
|
1258
|
+
|
|
1259
|
+
if (new_devex_framework) {
|
|
1260
|
+
// Initialise new Devex framework
|
|
1261
|
+
analysis->simplexTimerStart(IterateDevexIzClock);
|
|
1262
|
+
initialiseDevexFramework();
|
|
1263
|
+
analysis->simplexTimerStop(IterateDevexIzClock);
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
// Analyse the iteration: possibly report; possibly switch strategy
|
|
1267
|
+
iterationAnalysis();
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
void HEkkDual::iterateTasks() {
|
|
1271
|
+
slice_PRICE = 1;
|
|
1272
|
+
|
|
1273
|
+
// Group 1
|
|
1274
|
+
chooseRow();
|
|
1275
|
+
|
|
1276
|
+
// Disable slice when too sparse
|
|
1277
|
+
if (1.0 * row_ep.count * inv_solver_num_row < 0.01) slice_PRICE = 0;
|
|
1278
|
+
|
|
1279
|
+
analysis->simplexTimerStart(Group1Clock);
|
|
1280
|
+
// #pragma omp parallel
|
|
1281
|
+
// #pragma omp single
|
|
1282
|
+
{
|
|
1283
|
+
// #pragma omp task
|
|
1284
|
+
highs::parallel::spawn([&]() {
|
|
1285
|
+
col_DSE.copy(&row_ep);
|
|
1286
|
+
updateFtranDSE(&col_DSE);
|
|
1287
|
+
});
|
|
1288
|
+
// #pragma omp task
|
|
1289
|
+
{
|
|
1290
|
+
if (slice_PRICE)
|
|
1291
|
+
chooseColumnSlice(&row_ep);
|
|
1292
|
+
else
|
|
1293
|
+
chooseColumn(&row_ep);
|
|
1294
|
+
// #pragma omp task
|
|
1295
|
+
highs::parallel::spawn([&]() { updateFtranBFRT(); });
|
|
1296
|
+
// #pragma omp task
|
|
1297
|
+
updateFtran();
|
|
1298
|
+
// #pragma omp taskwait
|
|
1299
|
+
highs::parallel::sync();
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
highs::parallel::sync();
|
|
1303
|
+
}
|
|
1304
|
+
analysis->simplexTimerStop(Group1Clock);
|
|
1305
|
+
|
|
1306
|
+
updateVerify();
|
|
1307
|
+
updateDual();
|
|
1308
|
+
updatePrimal(&col_DSE);
|
|
1309
|
+
updatePivots();
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
void HEkkDual::iterationAnalysisData() {
|
|
1313
|
+
double cost_scale_factor =
|
|
1314
|
+
pow(2.0, -ekk_instance_.options_->cost_scale_factor);
|
|
1315
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
1316
|
+
analysis->simplex_strategy = info.simplex_strategy;
|
|
1317
|
+
analysis->edge_weight_mode = edge_weight_mode;
|
|
1318
|
+
analysis->solve_phase = solve_phase;
|
|
1319
|
+
analysis->simplex_iteration_count = ekk_instance_.iteration_count_;
|
|
1320
|
+
analysis->devex_iteration_count = num_devex_iterations;
|
|
1321
|
+
analysis->pivotal_row_index = row_out;
|
|
1322
|
+
analysis->leaving_variable = variable_out;
|
|
1323
|
+
analysis->entering_variable = variable_in;
|
|
1324
|
+
analysis->rebuild_reason = rebuild_reason;
|
|
1325
|
+
analysis->reduced_rhs_value = 0;
|
|
1326
|
+
analysis->reduced_cost_value = 0;
|
|
1327
|
+
analysis->edge_weight = 0;
|
|
1328
|
+
analysis->primal_delta = delta_primal;
|
|
1329
|
+
analysis->primal_step = theta_primal;
|
|
1330
|
+
analysis->dual_step = theta_dual * cost_scale_factor;
|
|
1331
|
+
analysis->pivot_value_from_column = alpha_col;
|
|
1332
|
+
analysis->pivot_value_from_row = alpha_row;
|
|
1333
|
+
analysis->factor_pivot_threshold = info.factor_pivot_threshold;
|
|
1334
|
+
analysis->numerical_trouble = numericalTrouble;
|
|
1335
|
+
analysis->edge_weight_error = ekk_instance_.edge_weight_error_;
|
|
1336
|
+
analysis->objective_value = info.updated_dual_objective_value;
|
|
1337
|
+
// Since maximization is achieved by minimizing the LP with negated
|
|
1338
|
+
// costs, in phase 2 the dual objective value is negated, so flip
|
|
1339
|
+
// its sign according to the LP sense
|
|
1340
|
+
if (solve_phase == kSolvePhase2)
|
|
1341
|
+
analysis->objective_value *= (HighsInt)ekk_instance_.lp_.sense_;
|
|
1342
|
+
analysis->num_primal_infeasibility = info.num_primal_infeasibilities;
|
|
1343
|
+
analysis->sum_primal_infeasibility = info.sum_primal_infeasibilities;
|
|
1344
|
+
if (solve_phase == kSolvePhase1) {
|
|
1345
|
+
analysis->num_dual_infeasibility =
|
|
1346
|
+
analysis->num_dual_phase_1_lp_dual_infeasibility;
|
|
1347
|
+
analysis->sum_dual_infeasibility =
|
|
1348
|
+
analysis->sum_dual_phase_1_lp_dual_infeasibility;
|
|
1349
|
+
} else {
|
|
1350
|
+
analysis->num_dual_infeasibility = info.num_dual_infeasibilities;
|
|
1351
|
+
analysis->sum_dual_infeasibility = info.sum_dual_infeasibilities;
|
|
1352
|
+
}
|
|
1353
|
+
if ((edge_weight_mode == EdgeWeightMode::kDevex) &&
|
|
1354
|
+
(num_devex_iterations == 0))
|
|
1355
|
+
analysis->num_devex_framework++;
|
|
1356
|
+
analysis->col_aq_density = info.col_aq_density;
|
|
1357
|
+
analysis->row_ep_density = info.row_ep_density;
|
|
1358
|
+
analysis->row_ap_density = info.row_ap_density;
|
|
1359
|
+
analysis->row_DSE_density = info.row_DSE_density;
|
|
1360
|
+
analysis->col_basic_feasibility_change_density =
|
|
1361
|
+
info.col_basic_feasibility_change_density;
|
|
1362
|
+
analysis->row_basic_feasibility_change_density =
|
|
1363
|
+
info.row_basic_feasibility_change_density;
|
|
1364
|
+
analysis->col_BFRT_density = info.col_BFRT_density;
|
|
1365
|
+
analysis->primal_col_density = info.primal_col_density;
|
|
1366
|
+
analysis->dual_col_density = info.dual_col_density;
|
|
1367
|
+
analysis->num_costly_DSE_iteration = info.num_costly_DSE_iteration;
|
|
1368
|
+
analysis->costly_DSE_measure = info.costly_DSE_measure;
|
|
1369
|
+
// analysis-> = info.;
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
void HEkkDual::iterationAnalysis() {
|
|
1373
|
+
// Compute the infeasibility data (expensive) if analysing run-time
|
|
1374
|
+
// data and the log level is at least kIterationReportLogType
|
|
1375
|
+
// (Verbose)
|
|
1376
|
+
const bool make_iteration_report = analysis->analyse_simplex_runtime_data &&
|
|
1377
|
+
ekk_instance_.options_->log_dev_level >=
|
|
1378
|
+
(HighsInt)kIterationReportLogType;
|
|
1379
|
+
if (make_iteration_report)
|
|
1380
|
+
ekk_instance_.computeInfeasibilitiesForReporting(SimplexAlgorithm::kDual,
|
|
1381
|
+
solve_phase);
|
|
1382
|
+
// Possibly report on the iteration
|
|
1383
|
+
iterationAnalysisData();
|
|
1384
|
+
analysis->iterationReport();
|
|
1385
|
+
|
|
1386
|
+
// Possibly switch from DSE to Devex
|
|
1387
|
+
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
|
|
1388
|
+
const bool switch_to_devex = ekk_instance_.switchToDevex();
|
|
1389
|
+
if (switch_to_devex) {
|
|
1390
|
+
edge_weight_mode = EdgeWeightMode::kDevex;
|
|
1391
|
+
initialiseDevexFramework();
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
if (analysis->analyse_simplex_summary_data) analysis->iterationRecord();
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
void HEkkDual::reportRebuild(const HighsInt reason_for_rebuild) {
|
|
1398
|
+
analysis->simplexTimerStart(ReportRebuildClock);
|
|
1399
|
+
iterationAnalysisData();
|
|
1400
|
+
analysis->rebuild_reason = reason_for_rebuild;
|
|
1401
|
+
analysis->rebuild_reason_string =
|
|
1402
|
+
ekk_instance_.rebuildReason(reason_for_rebuild);
|
|
1403
|
+
if (ekk_instance_.options_->output_flag) analysis->invertReport();
|
|
1404
|
+
analysis->simplexTimerStop(ReportRebuildClock);
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
void HEkkDual::chooseRow() {
|
|
1408
|
+
// Choose the index of a row to leave the basis (CHUZR)
|
|
1409
|
+
//
|
|
1410
|
+
// If reinversion is needed then skip this method
|
|
1411
|
+
if (rebuild_reason) return;
|
|
1412
|
+
// if (solve_phase == kSolvePhase2) dualRHS.assessOptimality();
|
|
1413
|
+
// Zero the infeasibility of any taboo rows
|
|
1414
|
+
ekk_instance_.applyTabooRowOut(dualRHS.work_infeasibility, 0);
|
|
1415
|
+
// Choose candidates repeatedly until candidate is OK or optimality is
|
|
1416
|
+
// detected
|
|
1417
|
+
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
|
|
1418
|
+
HighsDebugStatus return_status =
|
|
1419
|
+
ekk_instance_.devDebugDualSteepestEdgeWeights("chooseRow");
|
|
1420
|
+
assert(return_status == HighsDebugStatus::kNotChecked ||
|
|
1421
|
+
return_status == HighsDebugStatus::kOk);
|
|
1422
|
+
}
|
|
1423
|
+
std::vector<double>& edge_weight = ekk_instance_.dual_edge_weight_;
|
|
1424
|
+
for (;;) {
|
|
1425
|
+
// Choose the index of a good row to leave the basis
|
|
1426
|
+
dualRHS.chooseNormal(&row_out);
|
|
1427
|
+
if (row_out == kNoRowChosen) {
|
|
1428
|
+
// No index found so may be dual optimal.
|
|
1429
|
+
rebuild_reason = kRebuildReasonPossiblyOptimal;
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
// Compute pi_p = B^{-T}e_p in row_ep
|
|
1433
|
+
analysis->simplexTimerStart(BtranClock);
|
|
1434
|
+
// Set up RHS for BTRAN
|
|
1435
|
+
row_ep.clear();
|
|
1436
|
+
row_ep.count = 1;
|
|
1437
|
+
row_ep.index[0] = row_out;
|
|
1438
|
+
row_ep.array[row_out] = 1;
|
|
1439
|
+
row_ep.packFlag = true;
|
|
1440
|
+
if (analysis->analyse_simplex_summary_data)
|
|
1441
|
+
analysis->operationRecordBefore(kSimplexNlaBtranEp, row_ep,
|
|
1442
|
+
ekk_instance_.info_.row_ep_density);
|
|
1443
|
+
// Perform BTRAN
|
|
1444
|
+
simplex_nla->btran(row_ep, ekk_instance_.info_.row_ep_density,
|
|
1445
|
+
analysis->pointer_serial_factor_clocks);
|
|
1446
|
+
if (analysis->analyse_simplex_summary_data)
|
|
1447
|
+
analysis->operationRecordAfter(kSimplexNlaBtranEp, row_ep);
|
|
1448
|
+
analysis->simplexTimerStop(BtranClock);
|
|
1449
|
+
// Verify DSE weight
|
|
1450
|
+
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
|
|
1451
|
+
// For DSE, see how accurate the updated weight is
|
|
1452
|
+
// Save the updated weight
|
|
1453
|
+
double updated_edge_weight = edge_weight[row_out];
|
|
1454
|
+
// Compute the weight from row_ep and over-write the updated weight
|
|
1455
|
+
if (ekk_instance_.simplex_in_scaled_space_) {
|
|
1456
|
+
computed_edge_weight = edge_weight[row_out] = row_ep.norm2();
|
|
1457
|
+
} else {
|
|
1458
|
+
computed_edge_weight = edge_weight[row_out] =
|
|
1459
|
+
simplex_nla->rowEp2NormInScaledSpace(row_out, row_ep);
|
|
1460
|
+
}
|
|
1461
|
+
// If the weight error is acceptable then break out of the
|
|
1462
|
+
// loop. All we worry about is accepting rows with weights
|
|
1463
|
+
// which are not too small, since this can make the row look
|
|
1464
|
+
// unreasonably attractive
|
|
1465
|
+
if (acceptDualSteepestEdgeWeight(updated_edge_weight)) break;
|
|
1466
|
+
// Weight error is unacceptable so look for another
|
|
1467
|
+
// candidate. Of course, it's possible that the same
|
|
1468
|
+
// candidate is chosen, but the weight will be correct (so
|
|
1469
|
+
// no infinite loop).
|
|
1470
|
+
} else {
|
|
1471
|
+
// If not using DSE then accept the row by breaking out of
|
|
1472
|
+
// the loop
|
|
1473
|
+
break;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
// Recover the infeasibility of any taboo rows
|
|
1477
|
+
ekk_instance_.unapplyTabooRowOut(dualRHS.work_infeasibility);
|
|
1478
|
+
|
|
1479
|
+
// Index of row to leave the basis has been found
|
|
1480
|
+
//
|
|
1481
|
+
// Assign basic info:
|
|
1482
|
+
//
|
|
1483
|
+
// Record the column (variable) associated with the leaving row
|
|
1484
|
+
variable_out = ekk_instance_.basis_.basicIndex_[row_out];
|
|
1485
|
+
// Record the change in primal variable associated with the move to the bound
|
|
1486
|
+
// being violated
|
|
1487
|
+
if (baseValue[row_out] < baseLower[row_out]) {
|
|
1488
|
+
// Below the lower bound so set delta_primal = value - LB < 0
|
|
1489
|
+
delta_primal = baseValue[row_out] - baseLower[row_out];
|
|
1490
|
+
} else {
|
|
1491
|
+
// Above the upper bound so set delta_primal = value - UB > 0
|
|
1492
|
+
delta_primal = baseValue[row_out] - baseUpper[row_out];
|
|
1493
|
+
}
|
|
1494
|
+
// Set move_out to be -1 if delta_primal<0, otherwise +1 (since
|
|
1495
|
+
// delta_primal>0)
|
|
1496
|
+
move_out = delta_primal < 0 ? -1 : 1;
|
|
1497
|
+
// Update the record of average row_ep (pi_p) density. This ignores
|
|
1498
|
+
// any BTRANs done for skipped candidates
|
|
1499
|
+
const double local_row_ep_density = (double)row_ep.count * inv_solver_num_row;
|
|
1500
|
+
ekk_instance_.updateOperationResultDensity(
|
|
1501
|
+
local_row_ep_density, ekk_instance_.info_.row_ep_density);
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
bool HEkkDual::acceptDualSteepestEdgeWeight(const double updated_edge_weight) {
|
|
1505
|
+
// Accept the updated weight if it is at least a quarter of the
|
|
1506
|
+
// computed weight. Excessively large updated weights don't matter!
|
|
1507
|
+
const bool accept_weight =
|
|
1508
|
+
updated_edge_weight >= kAcceptDseWeightThreshold * computed_edge_weight;
|
|
1509
|
+
// if (analysis->analyse_simplex_summary_data)
|
|
1510
|
+
ekk_instance_.assessDSEWeightError(computed_edge_weight, updated_edge_weight);
|
|
1511
|
+
analysis->dualSteepestEdgeWeightError(computed_edge_weight,
|
|
1512
|
+
updated_edge_weight);
|
|
1513
|
+
return accept_weight;
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
bool HEkkDual::newDevexFramework(const double updated_edge_weight) {
|
|
1517
|
+
// Analyse the Devex weight to determine whether a new framework
|
|
1518
|
+
// should be set up
|
|
1519
|
+
//
|
|
1520
|
+
// There is a new Devex framework if either
|
|
1521
|
+
//
|
|
1522
|
+
// 1) The weight inaccuracy ratio exceeds kMaxAllowedDevexWeightRatio
|
|
1523
|
+
//
|
|
1524
|
+
// 2) There have been max(kMinAbsNumberDevexIterations,
|
|
1525
|
+
// numRow/kMinRlvNumberDevexIterations) Devex iterations
|
|
1526
|
+
//
|
|
1527
|
+
const HighsInt kMinAbsNumberDevexIterations = 25;
|
|
1528
|
+
const double kMinRlvNumberDevexIterations = 1e-2;
|
|
1529
|
+
const double kMaxAllowedDevexWeightRatio = 3.0;
|
|
1530
|
+
|
|
1531
|
+
double devex_ratio = max(updated_edge_weight / computed_edge_weight,
|
|
1532
|
+
computed_edge_weight / updated_edge_weight);
|
|
1533
|
+
HighsInt i_te = solver_num_row / kMinRlvNumberDevexIterations;
|
|
1534
|
+
i_te = max(kMinAbsNumberDevexIterations, i_te);
|
|
1535
|
+
// Square kMaxAllowedDevexWeightRatio due to keeping squared
|
|
1536
|
+
// weights
|
|
1537
|
+
const double accept_ratio_threshold =
|
|
1538
|
+
kMaxAllowedDevexWeightRatio * kMaxAllowedDevexWeightRatio;
|
|
1539
|
+
const bool accept_ratio = devex_ratio <= accept_ratio_threshold;
|
|
1540
|
+
const bool accept_it = num_devex_iterations <= i_te;
|
|
1541
|
+
bool return_new_devex_framework;
|
|
1542
|
+
return_new_devex_framework = !accept_ratio || !accept_it;
|
|
1543
|
+
return return_new_devex_framework;
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
void HEkkDual::chooseColumn(HVector* row_ep) {
|
|
1547
|
+
// Compute pivot row (PRICE) and choose the index of a column to enter the
|
|
1548
|
+
// basis (CHUZC)
|
|
1549
|
+
//
|
|
1550
|
+
// If reinversion is needed then skip this method
|
|
1551
|
+
if (rebuild_reason) return;
|
|
1552
|
+
HighsOptions* options = ekk_instance_.options_;
|
|
1553
|
+
HighsLp& lp = ekk_instance_.lp_;
|
|
1554
|
+
|
|
1555
|
+
HighsInt debug_price_report = kDebugReportOff;
|
|
1556
|
+
const bool debug_price_report_on = false;
|
|
1557
|
+
const bool debug_small_pivot_issue_report_on = false;
|
|
1558
|
+
bool debug_small_pivot_issue_report = false;
|
|
1559
|
+
bool debug_rows_report = false;
|
|
1560
|
+
if (ekk_instance_.debug_iteration_report_) {
|
|
1561
|
+
if (debug_price_report_on) debug_price_report = kDebugReportAll;
|
|
1562
|
+
debug_rows_report = debug_price_report_on;
|
|
1563
|
+
debug_small_pivot_issue_report = debug_small_pivot_issue_report_on;
|
|
1564
|
+
if (debug_price_report != kDebugReportOff || debug_rows_report ||
|
|
1565
|
+
debug_small_pivot_issue_report)
|
|
1566
|
+
printf("HEkkDual::chooseColumn Check iter = %d\n",
|
|
1567
|
+
(int)ekk_instance_.iteration_count_);
|
|
1568
|
+
}
|
|
1569
|
+
//
|
|
1570
|
+
// PRICE
|
|
1571
|
+
//
|
|
1572
|
+
const bool quad_precision = false;
|
|
1573
|
+
ekk_instance_.tableauRowPrice(quad_precision, *row_ep, row_ap,
|
|
1574
|
+
debug_price_report);
|
|
1575
|
+
if (debug_rows_report) {
|
|
1576
|
+
ekk_instance_.simplex_nla_.reportArray("Row a_p", 0, &row_ap, true);
|
|
1577
|
+
ekk_instance_.simplex_nla_.reportArray("Row e_p", lp.num_col_, row_ep,
|
|
1578
|
+
true);
|
|
1579
|
+
}
|
|
1580
|
+
//
|
|
1581
|
+
// CHUZC
|
|
1582
|
+
//
|
|
1583
|
+
// Section 0: Clear data and call createFreemove to set a value of
|
|
1584
|
+
// nonbasicMove for all free columns to prevent their dual values
|
|
1585
|
+
// from being changed.
|
|
1586
|
+
analysis->simplexTimerStart(Chuzc0Clock);
|
|
1587
|
+
dualRow.clear();
|
|
1588
|
+
dualRow.workDelta = delta_primal;
|
|
1589
|
+
dualRow.createFreemove(row_ep);
|
|
1590
|
+
analysis->simplexTimerStop(Chuzc0Clock);
|
|
1591
|
+
//
|
|
1592
|
+
// Section 1: Pack row_ap and row_ep
|
|
1593
|
+
analysis->simplexTimerStart(Chuzc1Clock);
|
|
1594
|
+
// Pack row_ap into the packIndex/Value of HEkkDualRow
|
|
1595
|
+
dualRow.chooseMakepack(&row_ap, 0);
|
|
1596
|
+
// Pack row_ep into the packIndex/Value of HEkkDualRow
|
|
1597
|
+
dualRow.chooseMakepack(row_ep, solver_num_col);
|
|
1598
|
+
const double row_ep_scale =
|
|
1599
|
+
ekk_instance_.getValueScale(dualRow.packCount, dualRow.packValue);
|
|
1600
|
+
analysis->simplexTimerStop(Chuzc1Clock);
|
|
1601
|
+
// Loop until an acceptable pivot is found. Each pass either finds a
|
|
1602
|
+
// pivot, identifies possible unboundedness, or reduced the number
|
|
1603
|
+
// of nonzeros in dualRow.pack_value
|
|
1604
|
+
HighsInt chuzc_pass = 0;
|
|
1605
|
+
for (;;) {
|
|
1606
|
+
//
|
|
1607
|
+
// Section 2: Determine the possible variables - candidates for CHUZC
|
|
1608
|
+
analysis->simplexTimerStart(Chuzc2Clock);
|
|
1609
|
+
dualRow.choosePossible();
|
|
1610
|
+
analysis->simplexTimerStop(Chuzc2Clock);
|
|
1611
|
+
//
|
|
1612
|
+
// Take action if the step to an expanded bound is not positive, or
|
|
1613
|
+
// there are no candidates for CHUZC
|
|
1614
|
+
variable_in = -1;
|
|
1615
|
+
if (dualRow.workTheta <= 0 || dualRow.workCount == 0) {
|
|
1616
|
+
if (chuzc_pass > 0 && debug_small_pivot_issue_report) {
|
|
1617
|
+
printf(
|
|
1618
|
+
" "
|
|
1619
|
+
"Negative step or no candidates after %2d CHUZC passes\n",
|
|
1620
|
+
(int)chuzc_pass);
|
|
1621
|
+
}
|
|
1622
|
+
if (debug_rows_report) {
|
|
1623
|
+
ekk_instance_.simplex_nla_.reportVector(
|
|
1624
|
+
"dualRow.packValue/Index", dualRow.packCount, dualRow.packValue,
|
|
1625
|
+
dualRow.packIndex, true);
|
|
1626
|
+
}
|
|
1627
|
+
rebuild_reason = kRebuildReasonPossiblyDualUnbounded;
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
//
|
|
1631
|
+
// Sections 3 and 4: Perform (bound-flipping) ratio test. This can
|
|
1632
|
+
// fail if the dual values are excessively large
|
|
1633
|
+
bool chooseColumnFail = (dualRow.chooseFinal() != 0);
|
|
1634
|
+
if (chooseColumnFail) {
|
|
1635
|
+
rebuild_reason = kRebuildReasonChooseColumnFail;
|
|
1636
|
+
return;
|
|
1637
|
+
}
|
|
1638
|
+
if (dualRow.workPivot >= 0) {
|
|
1639
|
+
const double growth_tolerance =
|
|
1640
|
+
options->dual_simplex_pivot_growth_tolerance; // kHighsMacheps; //
|
|
1641
|
+
// A pivot has been chosen
|
|
1642
|
+
double alpha_row = dualRow.workAlpha;
|
|
1643
|
+
assert(alpha_row);
|
|
1644
|
+
const double scaled_value = row_ep_scale * alpha_row;
|
|
1645
|
+
if (std::abs(scaled_value) <= growth_tolerance) {
|
|
1646
|
+
if (chuzc_pass == 0 && debug_small_pivot_issue_report)
|
|
1647
|
+
printf(
|
|
1648
|
+
"CHUZC: Solve %6d; Iter %4d; ||e_p|| = %11.4g: Variable %6d "
|
|
1649
|
+
"Pivot %11.4g (dual "
|
|
1650
|
+
"%11.4g; ratio = %11.4g) is small",
|
|
1651
|
+
(int)ekk_instance_.debug_solve_call_num_,
|
|
1652
|
+
(int)ekk_instance_.iteration_count_, 1.0 / row_ep_scale,
|
|
1653
|
+
(int)dualRow.workPivot, dualRow.workAlpha,
|
|
1654
|
+
workDual[dualRow.workPivot],
|
|
1655
|
+
workDual[dualRow.workPivot] / dualRow.workAlpha);
|
|
1656
|
+
// On the first pass, try to make the pivotal row more accurate
|
|
1657
|
+
if (chuzc_pass == 0) {
|
|
1658
|
+
if (debug_small_pivot_issue_report) printf(": improve row\n");
|
|
1659
|
+
ekk_instance_.analysis_.num_improve_choose_column_row_call++;
|
|
1660
|
+
improveChooseColumnRow(row_ep);
|
|
1661
|
+
} else {
|
|
1662
|
+
// Remove the pivot
|
|
1663
|
+
ekk_instance_.analysis_.num_remove_pivot_from_pack++;
|
|
1664
|
+
for (HighsInt i = 0; i < dualRow.packCount; i++) {
|
|
1665
|
+
if (dualRow.packIndex[i] == dualRow.workPivot) {
|
|
1666
|
+
dualRow.packIndex[i] = dualRow.packIndex[dualRow.packCount - 1];
|
|
1667
|
+
dualRow.packValue[i] = dualRow.packValue[dualRow.packCount - 1];
|
|
1668
|
+
dualRow.packCount--;
|
|
1669
|
+
if (chuzc_pass == 0 && debug_small_pivot_issue_report)
|
|
1670
|
+
printf(": removing pivot gives pack count = %6d",
|
|
1671
|
+
(int)dualRow.packCount);
|
|
1672
|
+
break;
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
if (chuzc_pass == 0 && debug_small_pivot_issue_report)
|
|
1676
|
+
printf(" so %s\n", dualRow.packCount > 0 ? "repeat CHUZC"
|
|
1677
|
+
: "consider unbounded");
|
|
1678
|
+
}
|
|
1679
|
+
// Indicate that no pivot has been chosen
|
|
1680
|
+
dualRow.workPivot = -1;
|
|
1681
|
+
} else if (chuzc_pass > 0 && debug_small_pivot_issue_report) {
|
|
1682
|
+
printf(
|
|
1683
|
+
" Variable "
|
|
1684
|
+
"%6d "
|
|
1685
|
+
"Pivot %11.4g (dual "
|
|
1686
|
+
"%11.4g; ratio = %11.4g) is OK after %2d CHUZC passes\n",
|
|
1687
|
+
(int)dualRow.workPivot, dualRow.workAlpha,
|
|
1688
|
+
workDual[dualRow.workPivot],
|
|
1689
|
+
workDual[dualRow.workPivot] / dualRow.workAlpha, (int)chuzc_pass);
|
|
1690
|
+
}
|
|
1691
|
+
} else {
|
|
1692
|
+
// No pivot has been chosen
|
|
1693
|
+
assert(dualRow.workPivot == -1);
|
|
1694
|
+
if (chuzc_pass > 0 && debug_small_pivot_issue_report) {
|
|
1695
|
+
printf(
|
|
1696
|
+
" No pivot "
|
|
1697
|
+
"after %2d CHUZC passes\n",
|
|
1698
|
+
(int)chuzc_pass);
|
|
1699
|
+
}
|
|
1700
|
+
break;
|
|
1701
|
+
}
|
|
1702
|
+
// If a pivot has been chosen, or there are no more packed values
|
|
1703
|
+
// then end CHUZC
|
|
1704
|
+
if (dualRow.workPivot >= 0 || dualRow.packCount <= 0) break;
|
|
1705
|
+
chuzc_pass++;
|
|
1706
|
+
}
|
|
1707
|
+
//
|
|
1708
|
+
// Section 5: Reset the nonbasicMove values for free columns
|
|
1709
|
+
analysis->simplexTimerStart(Chuzc5Clock);
|
|
1710
|
+
dualRow.deleteFreemove();
|
|
1711
|
+
analysis->simplexTimerStop(Chuzc5Clock);
|
|
1712
|
+
// Record values for basis change, checking for numerical problems and update
|
|
1713
|
+
// of dual variables
|
|
1714
|
+
variable_in = dualRow.workPivot; // Index of the column entering the basis
|
|
1715
|
+
alpha_row = dualRow.workAlpha; // Pivot value computed row-wise - used for
|
|
1716
|
+
// numerical checking
|
|
1717
|
+
theta_dual = dualRow.workTheta; // Dual step length
|
|
1718
|
+
|
|
1719
|
+
if (edge_weight_mode == EdgeWeightMode::kDevex && !new_devex_framework) {
|
|
1720
|
+
// When using Devex, unless a new framework is to be used, get the
|
|
1721
|
+
// exact weight for the pivotal row and, based on its accuracy,
|
|
1722
|
+
// determine that a new framework is to be used. In serial
|
|
1723
|
+
// new_devex_framework should only ever be false at this point in
|
|
1724
|
+
// this method, but in PAMI, this method may be called multiple
|
|
1725
|
+
// times in minor iterations and the new framework is set up in
|
|
1726
|
+
// majorUpdate.
|
|
1727
|
+
analysis->simplexTimerStart(DevexWtClock);
|
|
1728
|
+
// Determine the exact Devex weight
|
|
1729
|
+
dualRow.computeDevexWeight();
|
|
1730
|
+
computed_edge_weight = dualRow.computed_edge_weight;
|
|
1731
|
+
computed_edge_weight = max(1.0, computed_edge_weight);
|
|
1732
|
+
analysis->simplexTimerStop(DevexWtClock);
|
|
1733
|
+
}
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
void HEkkDual::improveChooseColumnRow(HVector* row_ep) {
|
|
1738
|
+
HighsLp& lp = ekk_instance_.lp_;
|
|
1739
|
+
const bool debug_price_report_on = false;
|
|
1740
|
+
HighsInt debug_price_report = kDebugReportOff;
|
|
1741
|
+
bool debug_rows_report = false;
|
|
1742
|
+
if (ekk_instance_.debug_iteration_report_) {
|
|
1743
|
+
if (debug_price_report_on) debug_price_report = kDebugReportAll;
|
|
1744
|
+
debug_rows_report = debug_price_report_on;
|
|
1745
|
+
if (debug_price_report != kDebugReportOff)
|
|
1746
|
+
printf("HEkkDual::chooseColumn Check iter = %d\n",
|
|
1747
|
+
(int)ekk_instance_.iteration_count_);
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
analysis->simplexTimerStart(Chuzc5Clock);
|
|
1751
|
+
dualRow.deleteFreemove();
|
|
1752
|
+
analysis->simplexTimerStop(Chuzc5Clock);
|
|
1753
|
+
|
|
1754
|
+
if (debug_rows_report)
|
|
1755
|
+
ekk_instance_.simplex_nla_.reportArray("Row e_p.0", lp.num_col_, row_ep,
|
|
1756
|
+
true);
|
|
1757
|
+
ekk_instance_.unitBtranIterativeRefinement(row_out, *row_ep);
|
|
1758
|
+
if (debug_rows_report)
|
|
1759
|
+
ekk_instance_.simplex_nla_.reportArray("Row e_p.1", lp.num_col_, row_ep,
|
|
1760
|
+
true);
|
|
1761
|
+
|
|
1762
|
+
const bool quad_precision = true;
|
|
1763
|
+
ekk_instance_.tableauRowPrice(quad_precision, *row_ep, row_ap,
|
|
1764
|
+
debug_price_report);
|
|
1765
|
+
if (debug_rows_report) {
|
|
1766
|
+
ekk_instance_.simplex_nla_.reportArray("Row a_p", 0, &row_ap, true);
|
|
1767
|
+
ekk_instance_.simplex_nla_.reportArray("Row e_p", lp.num_col_, row_ep,
|
|
1768
|
+
true);
|
|
1769
|
+
}
|
|
1770
|
+
analysis->simplexTimerStart(Chuzc0Clock);
|
|
1771
|
+
dualRow.clear();
|
|
1772
|
+
dualRow.workDelta = delta_primal;
|
|
1773
|
+
dualRow.createFreemove(row_ep);
|
|
1774
|
+
analysis->simplexTimerStop(Chuzc0Clock);
|
|
1775
|
+
//
|
|
1776
|
+
// Section 1: Pack row_ap and row_ep
|
|
1777
|
+
analysis->simplexTimerStart(Chuzc1Clock);
|
|
1778
|
+
// Pack row_ap into the packIndex/Value of HEkkDualRow
|
|
1779
|
+
dualRow.chooseMakepack(&row_ap, 0);
|
|
1780
|
+
// Pack row_ep into the packIndex/Value of HEkkDualRow
|
|
1781
|
+
dualRow.chooseMakepack(row_ep, solver_num_col);
|
|
1782
|
+
analysis->simplexTimerStop(Chuzc1Clock);
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
void HEkkDual::chooseColumnSlice(HVector* row_ep) {
|
|
1786
|
+
// Choose the index of a column to enter the basis (CHUZC) by
|
|
1787
|
+
// exploiting slices of the pivotal row - for SIP and PAMI
|
|
1788
|
+
//
|
|
1789
|
+
// If reinversion is needed then skip this method
|
|
1790
|
+
if (rebuild_reason) return;
|
|
1791
|
+
|
|
1792
|
+
analysis->simplexTimerStart(Chuzc0Clock);
|
|
1793
|
+
dualRow.clear();
|
|
1794
|
+
dualRow.workDelta = delta_primal;
|
|
1795
|
+
dualRow.createFreemove(row_ep);
|
|
1796
|
+
analysis->simplexTimerStop(Chuzc0Clock);
|
|
1797
|
+
|
|
1798
|
+
// const HighsInt solver_num_row = ekk_instance_.lp_.num_row_;
|
|
1799
|
+
const double local_density = 1.0 * row_ep->count * inv_solver_num_row;
|
|
1800
|
+
bool use_col_price;
|
|
1801
|
+
bool use_row_price_w_switch;
|
|
1802
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
1803
|
+
ekk_instance_.choosePriceTechnique(info.price_strategy, local_density,
|
|
1804
|
+
use_col_price, use_row_price_w_switch);
|
|
1805
|
+
|
|
1806
|
+
if (analysis->analyse_simplex_summary_data) {
|
|
1807
|
+
const HighsInt row_ep_count = row_ep->count;
|
|
1808
|
+
if (use_col_price) {
|
|
1809
|
+
analysis->operationRecordBefore(kSimplexNlaPriceAp, row_ep_count, 0.0);
|
|
1810
|
+
analysis->num_col_price++;
|
|
1811
|
+
} else if (use_row_price_w_switch) {
|
|
1812
|
+
analysis->operationRecordBefore(kSimplexNlaPriceAp, row_ep_count,
|
|
1813
|
+
ekk_instance_.info_.row_ep_density);
|
|
1814
|
+
analysis->num_row_price_with_switch++;
|
|
1815
|
+
} else {
|
|
1816
|
+
analysis->operationRecordBefore(kSimplexNlaPriceAp, row_ep_count,
|
|
1817
|
+
ekk_instance_.info_.row_ep_density);
|
|
1818
|
+
analysis->num_row_price++;
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
analysis->simplexTimerStart(PriceChuzc1Clock);
|
|
1822
|
+
// Row_ep: PACK + CC1
|
|
1823
|
+
|
|
1824
|
+
highs::parallel::spawn([&]() {
|
|
1825
|
+
dualRow.chooseMakepack(row_ep, solver_num_col);
|
|
1826
|
+
dualRow.choosePossible();
|
|
1827
|
+
});
|
|
1828
|
+
|
|
1829
|
+
// Row_ap: PRICE + PACK + CC1
|
|
1830
|
+
highs::parallel::for_each(0, slice_num, [&](HighsInt start, HighsInt end) {
|
|
1831
|
+
const bool quad_precision = false;
|
|
1832
|
+
for (HighsInt i = start; i < end; i++) {
|
|
1833
|
+
slice_row_ap[i].clear();
|
|
1834
|
+
|
|
1835
|
+
if (use_col_price) {
|
|
1836
|
+
// Perform column-wise PRICE
|
|
1837
|
+
slice_a_matrix[i].priceByColumn(quad_precision, slice_row_ap[i],
|
|
1838
|
+
*row_ep);
|
|
1839
|
+
} else if (use_row_price_w_switch) {
|
|
1840
|
+
// Perform hyper-sparse row-wise PRICE, but switch if the density of
|
|
1841
|
+
// row_ap becomes extreme
|
|
1842
|
+
slice_ar_matrix[i].priceByRowWithSwitch(
|
|
1843
|
+
quad_precision, slice_row_ap[i], *row_ep,
|
|
1844
|
+
ekk_instance_.info_.row_ap_density, 0, kHyperPriceDensity);
|
|
1845
|
+
} else {
|
|
1846
|
+
// Perform hyper-sparse row-wise PRICE
|
|
1847
|
+
slice_ar_matrix[i].priceByRow(quad_precision, slice_row_ap[i], *row_ep);
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
slice_dualRow[i].clear();
|
|
1851
|
+
slice_dualRow[i].workDelta = delta_primal;
|
|
1852
|
+
slice_dualRow[i].chooseMakepack(&slice_row_ap[i], slice_start[i]);
|
|
1853
|
+
slice_dualRow[i].choosePossible();
|
|
1854
|
+
}
|
|
1855
|
+
});
|
|
1856
|
+
|
|
1857
|
+
highs::parallel::sync();
|
|
1858
|
+
|
|
1859
|
+
if (analysis->analyse_simplex_summary_data) {
|
|
1860
|
+
// Determine the nonzero count of the whole row
|
|
1861
|
+
HighsInt row_ap_count = 0;
|
|
1862
|
+
for (HighsInt i = 0; i < slice_num; i++)
|
|
1863
|
+
row_ap_count += slice_row_ap[i].count;
|
|
1864
|
+
analysis->operationRecordAfter(kSimplexNlaPriceAp, row_ap_count);
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
// Join CC1 results here
|
|
1868
|
+
for (HighsInt i = 0; i < slice_num; i++) {
|
|
1869
|
+
dualRow.chooseJoinpack(&slice_dualRow[i]);
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
analysis->simplexTimerStop(PriceChuzc1Clock);
|
|
1873
|
+
|
|
1874
|
+
// Infeasible we created before
|
|
1875
|
+
variable_in = -1;
|
|
1876
|
+
if (dualRow.workTheta <= 0 || dualRow.workCount == 0) {
|
|
1877
|
+
rebuild_reason = kRebuildReasonPossiblyDualUnbounded;
|
|
1878
|
+
return;
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
// Choose column 2, This only happens if didn't go out
|
|
1882
|
+
HighsInt return_code = dualRow.chooseFinal();
|
|
1883
|
+
if (return_code) {
|
|
1884
|
+
// Only returns -1, if not zero
|
|
1885
|
+
assert(return_code == -1);
|
|
1886
|
+
if (return_code < 0) {
|
|
1887
|
+
rebuild_reason = kRebuildReasonChooseColumnFail;
|
|
1888
|
+
} else {
|
|
1889
|
+
rebuild_reason = kRebuildReasonPossiblyDualUnbounded;
|
|
1890
|
+
}
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
if (slice_num == 0) {
|
|
1895
|
+
// This check is only done for serial code - since packIndex/Value
|
|
1896
|
+
// is distributed
|
|
1897
|
+
HighsInt num_infeasibility = dualRow.debugChooseColumnInfeasibilities();
|
|
1898
|
+
if (num_infeasibility) {
|
|
1899
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kError,
|
|
1900
|
+
"chooseFinal would create %d dual infeasibilities\n",
|
|
1901
|
+
(int)num_infeasibility);
|
|
1902
|
+
analysis->simplexTimerStop(Chuzc4dClock);
|
|
1903
|
+
rebuild_reason = kRebuildReasonChooseColumnFail;
|
|
1904
|
+
return;
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
analysis->simplexTimerStart(Chuzc5Clock);
|
|
1909
|
+
dualRow.deleteFreemove();
|
|
1910
|
+
analysis->simplexTimerStop(Chuzc5Clock);
|
|
1911
|
+
|
|
1912
|
+
variable_in = dualRow.workPivot;
|
|
1913
|
+
alpha_row = dualRow.workAlpha;
|
|
1914
|
+
theta_dual = dualRow.workTheta;
|
|
1915
|
+
|
|
1916
|
+
if (edge_weight_mode == EdgeWeightMode::kDevex && !new_devex_framework) {
|
|
1917
|
+
// When using Devex, unless a new framework is to be used, get the
|
|
1918
|
+
// exact weight for the pivotal row and, based on its accuracy,
|
|
1919
|
+
// determine that a new framework is to be used. In serial
|
|
1920
|
+
// new_devex_framework should only ever be false at this point in
|
|
1921
|
+
// this method, but in PAMI, this method may be called multiple
|
|
1922
|
+
// times in minor iterations and the new framework is set up in
|
|
1923
|
+
// majorUpdate.
|
|
1924
|
+
analysis->simplexTimerStart(DevexWtClock);
|
|
1925
|
+
// Determine the partial sums of the exact Devex weight
|
|
1926
|
+
// First the partial sum for row_ep
|
|
1927
|
+
dualRow.computeDevexWeight();
|
|
1928
|
+
// Second the partial sums for the slices of row_ap
|
|
1929
|
+
for (HighsInt i = 0; i < slice_num; i++)
|
|
1930
|
+
slice_dualRow[i].computeDevexWeight(i);
|
|
1931
|
+
// Accumulate the partial sums
|
|
1932
|
+
// Initialise with the partial sum for row_ep
|
|
1933
|
+
computed_edge_weight = dualRow.computed_edge_weight;
|
|
1934
|
+
// Update with the partial sum for row_ep
|
|
1935
|
+
for (HighsInt i = 0; i < slice_num; i++)
|
|
1936
|
+
computed_edge_weight += slice_dualRow[i].computed_edge_weight;
|
|
1937
|
+
computed_edge_weight = max(1.0, computed_edge_weight);
|
|
1938
|
+
analysis->simplexTimerStop(DevexWtClock);
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
void HEkkDual::updateFtran() {
|
|
1943
|
+
// Compute the pivotal column (FTRAN)
|
|
1944
|
+
//
|
|
1945
|
+
// If reinversion is needed then skip this method
|
|
1946
|
+
if (rebuild_reason) return;
|
|
1947
|
+
analysis->simplexTimerStart(FtranClock);
|
|
1948
|
+
// Clear the pivotal column and indicate that its values should be packed
|
|
1949
|
+
col_aq.clear();
|
|
1950
|
+
col_aq.packFlag = true;
|
|
1951
|
+
// Get the constraint matrix column by combining just one column
|
|
1952
|
+
// with unit multiplier
|
|
1953
|
+
a_matrix->collectAj(col_aq, variable_in, 1);
|
|
1954
|
+
if (analysis->analyse_simplex_summary_data)
|
|
1955
|
+
analysis->operationRecordBefore(kSimplexNlaFtran, col_aq,
|
|
1956
|
+
ekk_instance_.info_.col_aq_density);
|
|
1957
|
+
// Perform FTRAN
|
|
1958
|
+
simplex_nla->ftran(col_aq, ekk_instance_.info_.col_aq_density,
|
|
1959
|
+
analysis->pointer_serial_factor_clocks);
|
|
1960
|
+
if (analysis->analyse_simplex_summary_data)
|
|
1961
|
+
analysis->operationRecordAfter(kSimplexNlaFtran, col_aq);
|
|
1962
|
+
const double local_col_aq_density = (double)col_aq.count * inv_solver_num_row;
|
|
1963
|
+
ekk_instance_.updateOperationResultDensity(
|
|
1964
|
+
local_col_aq_density, ekk_instance_.info_.col_aq_density);
|
|
1965
|
+
// Save the pivot value computed column-wise - used for numerical checking
|
|
1966
|
+
alpha_col = col_aq.array[row_out];
|
|
1967
|
+
analysis->simplexTimerStop(FtranClock);
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
void HEkkDual::updateFtranBFRT() {
|
|
1971
|
+
// Compute the RHS changes corresponding to the BFRT (FTRAN-BFRT)
|
|
1972
|
+
//
|
|
1973
|
+
// If reinversion is needed then skip this method
|
|
1974
|
+
if (rebuild_reason) return;
|
|
1975
|
+
|
|
1976
|
+
// Only time updateFtranBFRT if dualRow.workCount > 0;
|
|
1977
|
+
// If dualRow.workCount = 0 then dualRow.updateFlip(&col_BFRT)
|
|
1978
|
+
// merely clears col_BFRT so no FTRAN is performed
|
|
1979
|
+
bool time_updateFtranBFRT = dualRow.workCount > 0;
|
|
1980
|
+
|
|
1981
|
+
if (time_updateFtranBFRT) {
|
|
1982
|
+
analysis->simplexTimerStart(FtranBfrtClock);
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase, "Before
|
|
1986
|
+
// update_flip");
|
|
1987
|
+
dualRow.updateFlip(&col_BFRT);
|
|
1988
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase, "After
|
|
1989
|
+
// update_flip");
|
|
1990
|
+
|
|
1991
|
+
if (col_BFRT.count) {
|
|
1992
|
+
if (analysis->analyse_simplex_summary_data)
|
|
1993
|
+
analysis->operationRecordBefore(kSimplexNlaFtranBfrt, col_BFRT,
|
|
1994
|
+
ekk_instance_.info_.col_BFRT_density);
|
|
1995
|
+
simplex_nla->ftran(col_BFRT, ekk_instance_.info_.col_BFRT_density,
|
|
1996
|
+
analysis->pointer_serial_factor_clocks);
|
|
1997
|
+
if (analysis->analyse_simplex_summary_data)
|
|
1998
|
+
analysis->operationRecordAfter(kSimplexNlaFtranBfrt, col_BFRT);
|
|
1999
|
+
}
|
|
2000
|
+
if (time_updateFtranBFRT) {
|
|
2001
|
+
analysis->simplexTimerStop(FtranBfrtClock);
|
|
2002
|
+
}
|
|
2003
|
+
const double local_col_BFRT_density =
|
|
2004
|
+
(double)col_BFRT.count * inv_solver_num_row;
|
|
2005
|
+
ekk_instance_.updateOperationResultDensity(
|
|
2006
|
+
local_col_BFRT_density, ekk_instance_.info_.col_BFRT_density);
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
void HEkkDual::updateFtranDSE(HVector* DSE_Vector) {
|
|
2010
|
+
// Compute the vector required to update DSE weights - being FTRAN
|
|
2011
|
+
// applied to row_ep (FTRAN-DSE)
|
|
2012
|
+
//
|
|
2013
|
+
// When solving the unscaled LP with scaled NLA, have computed
|
|
2014
|
+
//
|
|
2015
|
+
// row_ep = R\bar{B}^{-T}C_B.e_p = cb.R\bar{B}^{-T}e_p
|
|
2016
|
+
//
|
|
2017
|
+
// to get row_ep in the unscaled space.
|
|
2018
|
+
//
|
|
2019
|
+
// To update DSE weights requires \bar{B}^{-1}\bar{B}^{-T}e_p, being
|
|
2020
|
+
//
|
|
2021
|
+
// (1/cp).\bar{B}^{-1}R^{-1}(cb.R\bar{B}^{-T}e_p)
|
|
2022
|
+
//
|
|
2023
|
+
// where cb.R\bar{B}^{-T}e_p is row_ep in the unscaled space.
|
|
2024
|
+
//
|
|
2025
|
+
// Operation R^{-1} is performed here. Operation (1/cp) is performed
|
|
2026
|
+
// when updating weights
|
|
2027
|
+
//
|
|
2028
|
+
// If reinversion is needed then skip this method
|
|
2029
|
+
if (rebuild_reason) return;
|
|
2030
|
+
analysis->simplexTimerStart(FtranDseClock);
|
|
2031
|
+
if (analysis->analyse_simplex_summary_data)
|
|
2032
|
+
analysis->operationRecordBefore(kSimplexNlaFtranDse, *DSE_Vector,
|
|
2033
|
+
ekk_instance_.info_.row_DSE_density);
|
|
2034
|
+
// Apply R{-1}
|
|
2035
|
+
simplex_nla->unapplyBasisMatrixRowScale(*DSE_Vector);
|
|
2036
|
+
|
|
2037
|
+
// Perform FTRAN DSE
|
|
2038
|
+
simplex_nla->ftranInScaledSpace(*DSE_Vector,
|
|
2039
|
+
ekk_instance_.info_.row_DSE_density,
|
|
2040
|
+
analysis->pointer_serial_factor_clocks);
|
|
2041
|
+
if (analysis->analyse_simplex_summary_data)
|
|
2042
|
+
analysis->operationRecordAfter(kSimplexNlaFtranDse, *DSE_Vector);
|
|
2043
|
+
analysis->simplexTimerStop(FtranDseClock);
|
|
2044
|
+
const double local_row_DSE_density =
|
|
2045
|
+
(double)DSE_Vector->count * inv_solver_num_row;
|
|
2046
|
+
ekk_instance_.updateOperationResultDensity(
|
|
2047
|
+
local_row_DSE_density, ekk_instance_.info_.row_DSE_density);
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
void HEkkDual::updateVerify() {
|
|
2051
|
+
// Compare the pivot value computed row-wise and column-wise and
|
|
2052
|
+
// determine whether reinversion is advisable
|
|
2053
|
+
//
|
|
2054
|
+
// If reinversion is needed then skip this method
|
|
2055
|
+
if (rebuild_reason) return;
|
|
2056
|
+
|
|
2057
|
+
// Use the two pivot values to identify numerical trouble
|
|
2058
|
+
if (ekk_instance_.reinvertOnNumericalTrouble(
|
|
2059
|
+
"HEkkDual::updateVerify", numericalTrouble, alpha_col, alpha_row,
|
|
2060
|
+
kNumericalTroubleTolerance)) {
|
|
2061
|
+
rebuild_reason = kRebuildReasonPossiblySingularBasis;
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
void HEkkDual::updateDual() {
|
|
2066
|
+
// Update the dual values
|
|
2067
|
+
//
|
|
2068
|
+
// If reinversion is needed then skip this method
|
|
2069
|
+
if (rebuild_reason) return;
|
|
2070
|
+
|
|
2071
|
+
// Update - dual (shift and back)
|
|
2072
|
+
if (theta_dual == 0) {
|
|
2073
|
+
// Little to do if theta_dual is zero
|
|
2074
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase,
|
|
2075
|
+
// "Before shift_cost");
|
|
2076
|
+
shiftCost(variable_in, -workDual[variable_in]);
|
|
2077
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase,
|
|
2078
|
+
// "After shift_cost");
|
|
2079
|
+
} else {
|
|
2080
|
+
// Update the whole vector of dual values
|
|
2081
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase,
|
|
2082
|
+
// "Before calling dualRow.updateDual");
|
|
2083
|
+
dualRow.updateDual(theta_dual);
|
|
2084
|
+
if (ekk_instance_.info_.simplex_strategy != kSimplexStrategyDualPlain &&
|
|
2085
|
+
slice_PRICE) {
|
|
2086
|
+
// Update the slice-by-slice copy of dual variables
|
|
2087
|
+
for (HighsInt i = 0; i < slice_num; i++)
|
|
2088
|
+
slice_dualRow[i].updateDual(theta_dual);
|
|
2089
|
+
}
|
|
2090
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase,
|
|
2091
|
+
// "After calling dualRow.updateDual");
|
|
2092
|
+
}
|
|
2093
|
+
// Identify the changes in the dual objective
|
|
2094
|
+
double dual_objective_value_change;
|
|
2095
|
+
const double variable_in_delta_dual = workDual[variable_in];
|
|
2096
|
+
const double variable_in_value = workValue[variable_in];
|
|
2097
|
+
const HighsInt variable_in_nonbasicFlag =
|
|
2098
|
+
ekk_instance_.basis_.nonbasicFlag_[variable_in];
|
|
2099
|
+
dual_objective_value_change =
|
|
2100
|
+
variable_in_nonbasicFlag * (-variable_in_value * variable_in_delta_dual);
|
|
2101
|
+
dual_objective_value_change *= ekk_instance_.cost_scale_;
|
|
2102
|
+
ekk_instance_.info_.updated_dual_objective_value +=
|
|
2103
|
+
dual_objective_value_change;
|
|
2104
|
+
// Surely variable_out_nonbasicFlag is always 0 since it's basic - so there's
|
|
2105
|
+
// no dual objective change
|
|
2106
|
+
const HighsInt variable_out_nonbasicFlag =
|
|
2107
|
+
ekk_instance_.basis_.nonbasicFlag_[variable_out];
|
|
2108
|
+
assert(variable_out_nonbasicFlag == 0);
|
|
2109
|
+
if (variable_out_nonbasicFlag) {
|
|
2110
|
+
const double variable_out_delta_dual = workDual[variable_out] - theta_dual;
|
|
2111
|
+
const double variable_out_value = workValue[variable_out];
|
|
2112
|
+
dual_objective_value_change =
|
|
2113
|
+
variable_out_nonbasicFlag *
|
|
2114
|
+
(-variable_out_value * variable_out_delta_dual);
|
|
2115
|
+
dual_objective_value_change *= ekk_instance_.cost_scale_;
|
|
2116
|
+
ekk_instance_.info_.updated_dual_objective_value +=
|
|
2117
|
+
dual_objective_value_change;
|
|
2118
|
+
}
|
|
2119
|
+
workDual[variable_in] = 0;
|
|
2120
|
+
workDual[variable_out] = -theta_dual;
|
|
2121
|
+
|
|
2122
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase, "Before
|
|
2123
|
+
// shift_back");
|
|
2124
|
+
shiftBack(variable_out);
|
|
2125
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase, "After
|
|
2126
|
+
// shift_back");
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
void HEkkDual::updatePrimal(HVector* DSE_Vector) {
|
|
2130
|
+
// Update the primal values and any edge weights
|
|
2131
|
+
//
|
|
2132
|
+
// If reinversion is needed then skip this method
|
|
2133
|
+
if (rebuild_reason) return;
|
|
2134
|
+
std::vector<double>& edge_weight = ekk_instance_.dual_edge_weight_;
|
|
2135
|
+
if (edge_weight_mode == EdgeWeightMode::kDevex) {
|
|
2136
|
+
const double updated_edge_weight = edge_weight[row_out];
|
|
2137
|
+
edge_weight[row_out] = computed_edge_weight;
|
|
2138
|
+
new_devex_framework = newDevexFramework(updated_edge_weight);
|
|
2139
|
+
}
|
|
2140
|
+
// DSE_Vector is either col_DSE = B^{-1}B^{-T}e_p (if using dual
|
|
2141
|
+
// steepest edge weights) or row_ep = B^{-T}e_p.
|
|
2142
|
+
//
|
|
2143
|
+
// Update - primal and weight
|
|
2144
|
+
dualRHS.updatePrimal(&col_BFRT, 1);
|
|
2145
|
+
dualRHS.updateInfeasList(&col_BFRT);
|
|
2146
|
+
double x_out = baseValue[row_out];
|
|
2147
|
+
double l_out = baseLower[row_out];
|
|
2148
|
+
double u_out = baseUpper[row_out];
|
|
2149
|
+
theta_primal = (x_out - (delta_primal < 0 ? l_out : u_out)) / alpha_col;
|
|
2150
|
+
const bool ok_update_primal = dualRHS.updatePrimal(&col_aq, theta_primal);
|
|
2151
|
+
if (!ok_update_primal) {
|
|
2152
|
+
rebuild_reason = kRebuildReasonExcessivePrimalValue;
|
|
2153
|
+
return;
|
|
2154
|
+
}
|
|
2155
|
+
ekk_instance_.updateBadBasisChange(col_aq, theta_primal);
|
|
2156
|
+
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
|
|
2157
|
+
const double pivot_in_scaled_space =
|
|
2158
|
+
ekk_instance_.simplex_nla_.pivotInScaledSpace(&col_aq, variable_in,
|
|
2159
|
+
row_out);
|
|
2160
|
+
if (ekk_instance_.simplex_in_scaled_space_)
|
|
2161
|
+
assert(pivot_in_scaled_space == alpha_col);
|
|
2162
|
+
const double new_pivotal_edge_weight =
|
|
2163
|
+
edge_weight[row_out] / (pivot_in_scaled_space * pivot_in_scaled_space);
|
|
2164
|
+
const double Kai = -2 / pivot_in_scaled_space;
|
|
2165
|
+
ekk_instance_.updateDualSteepestEdgeWeights(row_out, variable_in, &col_aq,
|
|
2166
|
+
new_pivotal_edge_weight, Kai,
|
|
2167
|
+
DSE_Vector->array.data());
|
|
2168
|
+
edge_weight[row_out] = new_pivotal_edge_weight;
|
|
2169
|
+
} else if (edge_weight_mode == EdgeWeightMode::kDevex) {
|
|
2170
|
+
// Pivotal row is for the current basis: weights are required for
|
|
2171
|
+
// the next basis so have to divide the current (exact) weight by
|
|
2172
|
+
// the pivotal value
|
|
2173
|
+
double new_pivotal_edge_weight =
|
|
2174
|
+
edge_weight[row_out] / (alpha_col * alpha_col);
|
|
2175
|
+
new_pivotal_edge_weight = max(1.0, new_pivotal_edge_weight);
|
|
2176
|
+
// nw_wt is max(use_edge_weight_[iRow], NewExactWeight*columnArray[iRow]^2);
|
|
2177
|
+
//
|
|
2178
|
+
// But NewExactWeight is new_pivotal_edge_weight = max(1.0,
|
|
2179
|
+
// edge_weight[row_out] / (alpha * alpha))
|
|
2180
|
+
//
|
|
2181
|
+
// so nw_wt = max(use_edge_weight_[iRow],
|
|
2182
|
+
// new_pivotal_edge_weight*columnArray[iRow]^2);
|
|
2183
|
+
//
|
|
2184
|
+
// Update rest of weights
|
|
2185
|
+
ekk_instance_.updateDualDevexWeights(&col_aq, new_pivotal_edge_weight);
|
|
2186
|
+
edge_weight[row_out] = new_pivotal_edge_weight;
|
|
2187
|
+
num_devex_iterations++;
|
|
2188
|
+
}
|
|
2189
|
+
dualRHS.updateInfeasList(&col_aq);
|
|
2190
|
+
|
|
2191
|
+
// Whether or not dual steepest edge weights are being used, have to
|
|
2192
|
+
// add in DSE_Vector->synthetic_tick_ since this contains the
|
|
2193
|
+
// contribution from forming row_ep = B^{-T}e_p.
|
|
2194
|
+
ekk_instance_.total_synthetic_tick_ += col_aq.synthetic_tick;
|
|
2195
|
+
ekk_instance_.total_synthetic_tick_ += DSE_Vector->synthetic_tick;
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
// Record the shift in the cost of a particular column
|
|
2199
|
+
void HEkkDual::shiftCost(const HighsInt iCol, const double amount) {
|
|
2200
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
2201
|
+
info.costs_shifted = true;
|
|
2202
|
+
assert(info.workShift_[iCol] == 0);
|
|
2203
|
+
if (!amount) return;
|
|
2204
|
+
double use_amount = amount;
|
|
2205
|
+
info.workShift_[iCol] = use_amount;
|
|
2206
|
+
// Analysis
|
|
2207
|
+
const double shift = fabs(use_amount);
|
|
2208
|
+
analysis->net_num_single_cost_shift++;
|
|
2209
|
+
analysis->num_single_cost_shift++;
|
|
2210
|
+
analysis->sum_single_cost_shift += shift;
|
|
2211
|
+
analysis->max_single_cost_shift = max(shift, analysis->max_single_cost_shift);
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
// Undo the shift in the cost of a particular column
|
|
2215
|
+
void HEkkDual::shiftBack(const HighsInt iCol) {
|
|
2216
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
2217
|
+
if (!info.workShift_[iCol]) return;
|
|
2218
|
+
info.workDual_[iCol] -= info.workShift_[iCol];
|
|
2219
|
+
info.workShift_[iCol] = 0;
|
|
2220
|
+
// Analysis
|
|
2221
|
+
analysis->net_num_single_cost_shift--;
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
void HEkkDual::updatePivots() {
|
|
2225
|
+
// UPDATE
|
|
2226
|
+
//
|
|
2227
|
+
// If reinversion is needed then skip this method
|
|
2228
|
+
if (rebuild_reason) return;
|
|
2229
|
+
// Transform the vectors used in updateFactor if the simplex NLA involves
|
|
2230
|
+
// scaling
|
|
2231
|
+
ekk_instance_.transformForUpdate(&col_aq, &row_ep, variable_in, &row_out);
|
|
2232
|
+
//
|
|
2233
|
+
// Update the sets of indices of basic and nonbasic variables
|
|
2234
|
+
//
|
|
2235
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase, "Before
|
|
2236
|
+
// update_pivots");
|
|
2237
|
+
ekk_instance_.updatePivots(variable_in, row_out, move_out);
|
|
2238
|
+
// debugUpdatedObjectiveValue(ekk_instance_, algorithm, solve_phase, "After
|
|
2239
|
+
// update_pivots");
|
|
2240
|
+
//
|
|
2241
|
+
ekk_instance_.iteration_count_++;
|
|
2242
|
+
//
|
|
2243
|
+
// Update the invertible representation of the basis matrix
|
|
2244
|
+
ekk_instance_.updateFactor(&col_aq, &row_ep, &row_out, &rebuild_reason);
|
|
2245
|
+
//
|
|
2246
|
+
// Update the row-wise representation of the nonbasic columns
|
|
2247
|
+
ekk_instance_.updateMatrix(variable_in, variable_out);
|
|
2248
|
+
//
|
|
2249
|
+
// Delete Freelist entry for variable_in
|
|
2250
|
+
dualRow.deleteFreelist(variable_in);
|
|
2251
|
+
//
|
|
2252
|
+
// Update the primal value for the row where the basis change has
|
|
2253
|
+
// occurred, and set the corresponding primal infeasibility value in
|
|
2254
|
+
// dualRHS.work_infeasibility
|
|
2255
|
+
dualRHS.updatePivots(
|
|
2256
|
+
row_out, ekk_instance_.info_.workValue_[variable_in] + theta_primal);
|
|
2257
|
+
|
|
2258
|
+
/*
|
|
2259
|
+
// Determine whether to reinvert based on the synthetic clock
|
|
2260
|
+
bool reinvert_syntheticClock = total_synthetic_tick >= build_synthetic_tick;
|
|
2261
|
+
const bool performed_min_updates =
|
|
2262
|
+
ekk_instance_.info_.update_count >=
|
|
2263
|
+
kSyntheticTickReinversionMinUpdateCount;
|
|
2264
|
+
if (reinvert_syntheticClock && performed_min_updates)
|
|
2265
|
+
rebuild_reason = kRebuildReasonSyntheticClockSaysInvert;
|
|
2266
|
+
*/
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
void HEkkDual::initialiseDevexFramework() {
|
|
2270
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
2271
|
+
// Initialise the Devex framework: reference set is all basic
|
|
2272
|
+
// variables
|
|
2273
|
+
analysis->simplexTimerStart(DevexIzClock);
|
|
2274
|
+
// Resize in case this is the first call
|
|
2275
|
+
ekk_instance_.info_.devex_index_.resize(solver_num_tot);
|
|
2276
|
+
const vector<int8_t>& nonbasicFlag = ekk_instance_.basis_.nonbasicFlag_;
|
|
2277
|
+
// Initialise the devex framework. The devex reference set is
|
|
2278
|
+
// initialise to be the current set of basic variables - and never
|
|
2279
|
+
// changes until a new framework is set up. In a simplex iteration,
|
|
2280
|
+
// to compute the exact Devex weight for the pivotal row requires
|
|
2281
|
+
// summing the squares of the its entries over the indices in the
|
|
2282
|
+
// reference set. This is achieved by summing over all indices, but
|
|
2283
|
+
// multiplying the entry by the value in devex_index before
|
|
2284
|
+
// equating. Thus devex_index contains 1 for indices in the
|
|
2285
|
+
// reference set, and 0 otherwise. This is achieved by setting the
|
|
2286
|
+
// values of devex_index to be 1-nonbasicFlag^2, ASSUMING
|
|
2287
|
+
// |nonbasicFlag|=1 iff the corresponding variable is nonbasic
|
|
2288
|
+
for (HighsInt vr_n = 0; vr_n < solver_num_tot; vr_n++)
|
|
2289
|
+
info.devex_index_[vr_n] = 1 - nonbasicFlag[vr_n] * nonbasicFlag[vr_n];
|
|
2290
|
+
// Set all initial weights to 1, zero the count of iterations with
|
|
2291
|
+
// this Devex framework, increment the number of Devex frameworks
|
|
2292
|
+
// and indicate that there's no need for a new Devex framework
|
|
2293
|
+
ekk_instance_.dual_edge_weight_.assign(solver_num_row, 1.0);
|
|
2294
|
+
num_devex_iterations = 0;
|
|
2295
|
+
new_devex_framework = false;
|
|
2296
|
+
minor_new_devex_framework = false;
|
|
2297
|
+
analysis->simplexTimerStop(DevexIzClock);
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
void HEkkDual::interpretDualEdgeWeightStrategy(
|
|
2301
|
+
const HighsInt dual_edge_weight_strategy) {
|
|
2302
|
+
if (dual_edge_weight_strategy == kSimplexEdgeWeightStrategyChoose) {
|
|
2303
|
+
edge_weight_mode = EdgeWeightMode::kSteepestEdge;
|
|
2304
|
+
allow_dual_steepest_edge_to_devex_switch = true;
|
|
2305
|
+
} else if (dual_edge_weight_strategy == kSimplexEdgeWeightStrategyDantzig) {
|
|
2306
|
+
edge_weight_mode = EdgeWeightMode::kDantzig;
|
|
2307
|
+
} else if (dual_edge_weight_strategy == kSimplexEdgeWeightStrategyDevex) {
|
|
2308
|
+
edge_weight_mode = EdgeWeightMode::kDevex;
|
|
2309
|
+
} else if (dual_edge_weight_strategy ==
|
|
2310
|
+
kSimplexEdgeWeightStrategySteepestEdge) {
|
|
2311
|
+
edge_weight_mode = EdgeWeightMode::kSteepestEdge;
|
|
2312
|
+
allow_dual_steepest_edge_to_devex_switch = false;
|
|
2313
|
+
} else {
|
|
2314
|
+
assert(1 == 0);
|
|
2315
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
2316
|
+
"HEkkDual::interpretDualEdgeWeightStrategy: "
|
|
2317
|
+
"unrecognised dual_edge_weight_strategy = %" HIGHSINT_FORMAT
|
|
2318
|
+
" - using "
|
|
2319
|
+
"dual steepest edge with possible switch to Devex\n",
|
|
2320
|
+
dual_edge_weight_strategy);
|
|
2321
|
+
edge_weight_mode = EdgeWeightMode::kSteepestEdge;
|
|
2322
|
+
allow_dual_steepest_edge_to_devex_switch = true;
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
void HEkkDual::possiblyUseLiDualSteepestEdge() {
|
|
2327
|
+
// Decide whether to use LiDSE by not storing squared primal infeasibilities
|
|
2328
|
+
HighsOptions& options = *ekk_instance_.options_;
|
|
2329
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
2330
|
+
info.store_squared_primal_infeasibility = true;
|
|
2331
|
+
if (options.less_infeasible_DSE_check) {
|
|
2332
|
+
if (isLessInfeasibleDSECandidate(options.log_options, ekk_instance_.lp_)) {
|
|
2333
|
+
// LP is a candidate for LiDSE
|
|
2334
|
+
if (options.less_infeasible_DSE_choose_row)
|
|
2335
|
+
// Use LiDSE
|
|
2336
|
+
info.store_squared_primal_infeasibility = false;
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
void HEkkDual::computeDualInfeasibilitiesWithFixedVariableFlips() {
|
|
2342
|
+
// Computes num/max/sum of dual infeasibilities, ignoring fixed
|
|
2343
|
+
// variables whose infeasibilities can be corrected by flipping at
|
|
2344
|
+
// the fixed value, so that decisions on the dual simplex phase can
|
|
2345
|
+
// be taken. It is driven by the use of nonbasicMove to identify
|
|
2346
|
+
// dual infeasibilities, using the bounds only to identify free
|
|
2347
|
+
// variables. Fixed variables are assumed to have nonbasicMove=0 so
|
|
2348
|
+
// that no dual infeasibility is counted for them. Indeed, when
|
|
2349
|
+
// called from cleanup() at the end of dual phase 1, nonbasicMove
|
|
2350
|
+
// relates to the phase 1 bounds, but workLower and workUpper will
|
|
2351
|
+
// have been set to phase 2 values! Note that there can be no free
|
|
2352
|
+
// variables in dual phase 1.
|
|
2353
|
+
HighsInt num_dual_infeasibility = 0;
|
|
2354
|
+
double max_dual_infeasibility = 0;
|
|
2355
|
+
double sum_dual_infeasibility = 0;
|
|
2356
|
+
HighsLp& lp = ekk_instance_.lp_;
|
|
2357
|
+
SimplexBasis& basis = ekk_instance_.basis_;
|
|
2358
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
2359
|
+
HighsOptions* options = ekk_instance_.options_;
|
|
2360
|
+
const HighsInt num_tot = lp.num_col_ + lp.num_row_;
|
|
2361
|
+
// Possibly verify that nonbasicMove is correct for fixed variables
|
|
2362
|
+
// debugFixedNonbasicMove(ekk_instance_);
|
|
2363
|
+
for (HighsInt iVar = 0; iVar < num_tot; iVar++) {
|
|
2364
|
+
if (!basis.nonbasicFlag_[iVar]) continue;
|
|
2365
|
+
// Nonbasic column
|
|
2366
|
+
const double lower = info.workLower_[iVar];
|
|
2367
|
+
const double upper = info.workUpper_[iVar];
|
|
2368
|
+
const double dual = info.workDual_[iVar];
|
|
2369
|
+
double dual_infeasibility = 0;
|
|
2370
|
+
if (lower == -kHighsInf && upper == kHighsInf) {
|
|
2371
|
+
dual_infeasibility = fabs(dual);
|
|
2372
|
+
} else {
|
|
2373
|
+
dual_infeasibility = -basis.nonbasicMove_[iVar] * dual;
|
|
2374
|
+
}
|
|
2375
|
+
if (dual_infeasibility > 0) {
|
|
2376
|
+
if (dual_infeasibility >= options->dual_feasibility_tolerance)
|
|
2377
|
+
num_dual_infeasibility++;
|
|
2378
|
+
max_dual_infeasibility =
|
|
2379
|
+
std::max(dual_infeasibility, max_dual_infeasibility);
|
|
2380
|
+
sum_dual_infeasibility += dual_infeasibility;
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
info.num_dual_infeasibilities = num_dual_infeasibility;
|
|
2384
|
+
info.max_dual_infeasibility = max_dual_infeasibility;
|
|
2385
|
+
info.sum_dual_infeasibilities = sum_dual_infeasibility;
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
void HEkkDual::correctDualInfeasibilities(HighsInt& free_infeasibility_count) {
|
|
2389
|
+
// Removes dual infeasibilities for all but free variables. For
|
|
2390
|
+
// fixed variables, dual infeasibilities are removed by flipping at
|
|
2391
|
+
// the bound. Otherwise, dual infeasibilities are removed by
|
|
2392
|
+
// shifting costs.
|
|
2393
|
+
HighsLp& lp = ekk_instance_.lp_;
|
|
2394
|
+
SimplexBasis& basis = ekk_instance_.basis_;
|
|
2395
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
2396
|
+
HighsSimplexAnalysis& analysis = ekk_instance_.analysis_;
|
|
2397
|
+
HighsRandom& random = ekk_instance_.random_;
|
|
2398
|
+
HighsOptions* options = ekk_instance_.options_;
|
|
2399
|
+
|
|
2400
|
+
free_infeasibility_count = 0;
|
|
2401
|
+
const double dual_feasibility_tolerance = options->dual_feasibility_tolerance;
|
|
2402
|
+
double flip_dual_objective_value_change = 0;
|
|
2403
|
+
double shift_dual_objective_value_change = 0;
|
|
2404
|
+
HighsInt num_flip = 0;
|
|
2405
|
+
HighsInt num_shift = 0;
|
|
2406
|
+
double sum_flip = 0;
|
|
2407
|
+
double sum_shift = 0;
|
|
2408
|
+
double max_flip = 0;
|
|
2409
|
+
double max_shift = 0;
|
|
2410
|
+
double min_dual_infeasibility_for_flip = kHighsInf;
|
|
2411
|
+
double max_dual_infeasibility_for_flip = 0;
|
|
2412
|
+
HighsInt num_dual_infeasibilities_for_flip = 0;
|
|
2413
|
+
double sum_dual_infeasibilities_for_flip = 0;
|
|
2414
|
+
HighsInt num_dual_infeasibilities_for_shift = 0;
|
|
2415
|
+
double max_dual_infeasibility_for_shift = 0;
|
|
2416
|
+
double sum_dual_infeasibilities_for_shift = 0;
|
|
2417
|
+
const HighsInt num_tot = lp.num_col_ + lp.num_row_;
|
|
2418
|
+
for (HighsInt iVar = 0; iVar < num_tot; iVar++) {
|
|
2419
|
+
if (!basis.nonbasicFlag_[iVar]) continue;
|
|
2420
|
+
// Nonbasic column
|
|
2421
|
+
const double lower = info.workLower_[iVar];
|
|
2422
|
+
const double upper = info.workUpper_[iVar];
|
|
2423
|
+
const double current_dual = info.workDual_[iVar];
|
|
2424
|
+
const HighsInt move = basis.nonbasicMove_[iVar];
|
|
2425
|
+
const bool fixed = lower == upper;
|
|
2426
|
+
const bool boxed = lower > -kHighsInf && upper < kHighsInf;
|
|
2427
|
+
const bool free = lower == -kHighsInf && upper == kHighsInf;
|
|
2428
|
+
double dual_infeasibility = 0;
|
|
2429
|
+
if (free) {
|
|
2430
|
+
dual_infeasibility = fabs(current_dual);
|
|
2431
|
+
if (dual_infeasibility >= dual_feasibility_tolerance)
|
|
2432
|
+
free_infeasibility_count++;
|
|
2433
|
+
continue;
|
|
2434
|
+
}
|
|
2435
|
+
dual_infeasibility = -move * current_dual;
|
|
2436
|
+
if (dual_infeasibility < dual_feasibility_tolerance) continue;
|
|
2437
|
+
// There is a dual infeasibility to remove
|
|
2438
|
+
//
|
|
2439
|
+
// force_phase2 is set true to prevent flipping of non-fixed
|
|
2440
|
+
// (boxed) variables when correcting infeasibilities in the first
|
|
2441
|
+
// set of duals computed after cost perturbation
|
|
2442
|
+
if (fixed || (boxed && !force_phase2)) {
|
|
2443
|
+
// Flip for fixed variables and boxed variables when not forcing phase 2
|
|
2444
|
+
ekk_instance_.flipBound(iVar);
|
|
2445
|
+
// Negative dual at lower bound (move=1): flip to upper
|
|
2446
|
+
// bound so objective contribution is change in value (flip)
|
|
2447
|
+
// times dual, being move*flip*dual
|
|
2448
|
+
//
|
|
2449
|
+
// Positive dual at upper bound (move=-1): flip to lower
|
|
2450
|
+
// bound so objective contribution is change in value
|
|
2451
|
+
// (-flip) times dual, being move*flip*dual
|
|
2452
|
+
const double flip = upper - lower;
|
|
2453
|
+
double local_dual_objective_change = move * flip * current_dual;
|
|
2454
|
+
local_dual_objective_change *= ekk_instance_.cost_scale_;
|
|
2455
|
+
flip_dual_objective_value_change += local_dual_objective_change;
|
|
2456
|
+
num_flip++;
|
|
2457
|
+
max_flip = max(fabs(flip), max_flip);
|
|
2458
|
+
sum_flip += fabs(flip);
|
|
2459
|
+
// Flipping fixed variables is trivial, so only track the
|
|
2460
|
+
// infeasibilities involved when flipping boxed variables
|
|
2461
|
+
if (!fixed) {
|
|
2462
|
+
min_dual_infeasibility_for_flip =
|
|
2463
|
+
std::min(dual_infeasibility, min_dual_infeasibility_for_flip);
|
|
2464
|
+
if (dual_infeasibility >= dual_feasibility_tolerance)
|
|
2465
|
+
num_dual_infeasibilities_for_flip++;
|
|
2466
|
+
sum_dual_infeasibilities_for_flip += dual_infeasibility;
|
|
2467
|
+
max_dual_infeasibility_for_flip =
|
|
2468
|
+
std::max(dual_infeasibility, max_dual_infeasibility_for_flip);
|
|
2469
|
+
}
|
|
2470
|
+
continue;
|
|
2471
|
+
}
|
|
2472
|
+
// Either boxed but not fixed, of one-sided, so shift
|
|
2473
|
+
//
|
|
2474
|
+
// Cost shifting must always be possible
|
|
2475
|
+
assert(info.allow_cost_shifting);
|
|
2476
|
+
// Other variable = shift
|
|
2477
|
+
if (dual_infeasibility >= dual_feasibility_tolerance)
|
|
2478
|
+
num_dual_infeasibilities_for_shift++;
|
|
2479
|
+
sum_dual_infeasibilities_for_shift += dual_infeasibility;
|
|
2480
|
+
max_dual_infeasibility_for_shift =
|
|
2481
|
+
std::max(dual_infeasibility, max_dual_infeasibility_for_shift);
|
|
2482
|
+
info.costs_shifted = true;
|
|
2483
|
+
double shift;
|
|
2484
|
+
if (move == kNonbasicMoveUp) {
|
|
2485
|
+
double new_dual = (1 + random.fraction()) * dual_feasibility_tolerance;
|
|
2486
|
+
shift = new_dual - current_dual;
|
|
2487
|
+
info.workDual_[iVar] = new_dual;
|
|
2488
|
+
info.workCost_[iVar] = info.workCost_[iVar] + shift;
|
|
2489
|
+
} else {
|
|
2490
|
+
double new_dual = -(1 + random.fraction()) * dual_feasibility_tolerance;
|
|
2491
|
+
shift = new_dual - current_dual;
|
|
2492
|
+
info.workDual_[iVar] = new_dual;
|
|
2493
|
+
info.workCost_[iVar] = info.workCost_[iVar] + shift;
|
|
2494
|
+
}
|
|
2495
|
+
double local_dual_objective_change = shift * info.workValue_[iVar];
|
|
2496
|
+
local_dual_objective_change *= ekk_instance_.cost_scale_;
|
|
2497
|
+
shift_dual_objective_value_change += local_dual_objective_change;
|
|
2498
|
+
num_shift++;
|
|
2499
|
+
max_shift = max(fabs(shift), max_shift);
|
|
2500
|
+
sum_shift += fabs(shift);
|
|
2501
|
+
const std::string direction = move == kNonbasicMoveUp ? " up" : "down";
|
|
2502
|
+
highsLogDev(options->log_options, HighsLogType::kVerbose,
|
|
2503
|
+
"Move %s: cost shift = %g; objective change = %g\n",
|
|
2504
|
+
direction.c_str(), shift, local_dual_objective_change);
|
|
2505
|
+
}
|
|
2506
|
+
analysis.num_correct_dual_primal_flip += num_flip;
|
|
2507
|
+
analysis.max_correct_dual_primal_flip =
|
|
2508
|
+
max(max_flip, analysis.max_correct_dual_primal_flip);
|
|
2509
|
+
analysis.min_correct_dual_primal_flip_dual_infeasibility =
|
|
2510
|
+
std::min(min_dual_infeasibility_for_flip,
|
|
2511
|
+
analysis.min_correct_dual_primal_flip_dual_infeasibility);
|
|
2512
|
+
if (num_flip && force_phase2) {
|
|
2513
|
+
highsLogDev(
|
|
2514
|
+
options->log_options, HighsLogType::kDetailed,
|
|
2515
|
+
"Performed num / max / sum = %" HIGHSINT_FORMAT
|
|
2516
|
+
" / %g / %g flip(s) for num / min / max / sum dual infeasibility of "
|
|
2517
|
+
"%" HIGHSINT_FORMAT " / %g / %g / %g; objective change = %g\n",
|
|
2518
|
+
num_flip, max_flip, sum_flip, num_dual_infeasibilities_for_flip,
|
|
2519
|
+
min_dual_infeasibility_for_flip, max_dual_infeasibility_for_flip,
|
|
2520
|
+
sum_dual_infeasibilities_for_flip, flip_dual_objective_value_change);
|
|
2521
|
+
}
|
|
2522
|
+
analysis.num_correct_dual_cost_shift += num_shift;
|
|
2523
|
+
analysis.max_correct_dual_cost_shift =
|
|
2524
|
+
max(max_shift, analysis.max_correct_dual_cost_shift);
|
|
2525
|
+
analysis.max_correct_dual_cost_shift_dual_infeasibility =
|
|
2526
|
+
max(max_dual_infeasibility_for_shift,
|
|
2527
|
+
analysis.max_correct_dual_cost_shift_dual_infeasibility);
|
|
2528
|
+
if (num_shift) {
|
|
2529
|
+
highsLogDev(
|
|
2530
|
+
options->log_options, HighsLogType::kDetailed,
|
|
2531
|
+
"Performed num / max / sum = %" HIGHSINT_FORMAT
|
|
2532
|
+
" / %g / %g shift(s) for num / max / sum dual infeasibility of "
|
|
2533
|
+
"%" HIGHSINT_FORMAT " / %g / %g; objective change = %g\n",
|
|
2534
|
+
num_shift, max_shift, sum_shift, num_dual_infeasibilities_for_shift,
|
|
2535
|
+
max_dual_infeasibility_for_shift, sum_dual_infeasibilities_for_shift,
|
|
2536
|
+
shift_dual_objective_value_change);
|
|
2537
|
+
}
|
|
2538
|
+
force_phase2 = false;
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
bool HEkkDual::proofOfPrimalInfeasibility() {
|
|
2542
|
+
return ekk_instance_.proofOfPrimalInfeasibility(row_ep, move_out, row_out);
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
void HEkkDual::saveDualRay() {
|
|
2546
|
+
assert(row_out >= 0);
|
|
2547
|
+
assert(move_out != kNoRaySign);
|
|
2548
|
+
ekk_instance_.dual_ray_record_.clear();
|
|
2549
|
+
ekk_instance_.dual_ray_record_.index = row_out;
|
|
2550
|
+
ekk_instance_.dual_ray_record_.sign = move_out;
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
void HEkkDual::assessPhase1Optimality() {
|
|
2554
|
+
// Should only be called when optimal in phase 1 (row_out == kNoRowChosen)
|
|
2555
|
+
// with nonzero dual activity, and after a fresh rebuild - so
|
|
2556
|
+
// "final" decisions can be made.
|
|
2557
|
+
assert(solve_phase == kSolvePhase1);
|
|
2558
|
+
assert(row_out == kNoRowChosen);
|
|
2559
|
+
assert(ekk_instance_.info_.dual_objective_value);
|
|
2560
|
+
assert(ekk_instance_.status_.has_fresh_rebuild);
|
|
2561
|
+
|
|
2562
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
2563
|
+
HighsModelStatus& model_status = ekk_instance_.model_status_;
|
|
2564
|
+
double& dual_objective_value = info.dual_objective_value;
|
|
2565
|
+
// There are (possibly insignificant) LP dual infeasibilities that
|
|
2566
|
+
// can't be removed by dual Phase 1, so clean up any perturbations
|
|
2567
|
+
// before concluding dual infeasibility
|
|
2568
|
+
//
|
|
2569
|
+
// Interesting for Devs to know if this method is called at all
|
|
2570
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
2571
|
+
"Optimal in phase 1 but not jumping to phase 2 since "
|
|
2572
|
+
"dual objective is %10.4g: Costs perturbed = %" HIGHSINT_FORMAT
|
|
2573
|
+
"\n",
|
|
2574
|
+
dual_objective_value, info.costs_perturbed);
|
|
2575
|
+
if (info.costs_perturbed) {
|
|
2576
|
+
// Clean up perturbation
|
|
2577
|
+
cleanup();
|
|
2578
|
+
assessPhase1OptimalityUnperturbed();
|
|
2579
|
+
} else {
|
|
2580
|
+
assert(dualInfeasCount == 0);
|
|
2581
|
+
assert(dual_objective_value != 0);
|
|
2582
|
+
assessPhase1OptimalityUnperturbed();
|
|
2583
|
+
}
|
|
2584
|
+
if (dualInfeasCount > 0) {
|
|
2585
|
+
// Must still be solve_phase = kSolvePhase1 since dual
|
|
2586
|
+
// infeasibilities with respect to phase 1 bounds mean that primal
|
|
2587
|
+
// values must change, so primal feasibility is unknown
|
|
2588
|
+
assert(solve_phase == kSolvePhase1);
|
|
2589
|
+
} else {
|
|
2590
|
+
// Optimal in dual phase 1, so either dual feasible wrt Phase 2
|
|
2591
|
+
// bounds and going to phase 2, or identified dual infeasibility and exiting
|
|
2592
|
+
assert(solve_phase == kSolvePhase2 ||
|
|
2593
|
+
(solve_phase == kSolvePhaseExit &&
|
|
2594
|
+
model_status == HighsModelStatus::kUnboundedOrInfeasible));
|
|
2595
|
+
if (solve_phase == kSolvePhase2) {
|
|
2596
|
+
// Reset the duals, if necessary shifting costs of free variables
|
|
2597
|
+
// so that their duals are zero
|
|
2598
|
+
exitPhase1ResetDuals();
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
|
|
2603
|
+
void HEkkDual::assessPhase1OptimalityUnperturbed() {
|
|
2604
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
2605
|
+
HighsModelStatus& model_status = ekk_instance_.model_status_;
|
|
2606
|
+
double& dual_objective_value = info.dual_objective_value;
|
|
2607
|
+
assert(!info.costs_perturbed);
|
|
2608
|
+
if (dualInfeasCount == 0) {
|
|
2609
|
+
// No dual infeasibilities with respect to phase 1 bounds.
|
|
2610
|
+
if (dual_objective_value == 0) {
|
|
2611
|
+
// No dual infeasibilities with respect to phase 2 bounds so
|
|
2612
|
+
// go to phase 2
|
|
2613
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
2614
|
+
"LP is dual feasible wrt Phase 2 bounds after removing cost "
|
|
2615
|
+
"perturbations so go to phase 2\n");
|
|
2616
|
+
solve_phase = kSolvePhase2;
|
|
2617
|
+
} else {
|
|
2618
|
+
// Nonzero dual objective value: could be insignificant dual
|
|
2619
|
+
// infeasibilities
|
|
2620
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
2621
|
+
"LP is dual feasible wrt Phase 1 bounds after removing cost "
|
|
2622
|
+
"perturbations: "
|
|
2623
|
+
"dual objective is %10.4g\n",
|
|
2624
|
+
dual_objective_value);
|
|
2625
|
+
ekk_instance_.computeSimplexLpDualInfeasible();
|
|
2626
|
+
const HighsInt num_lp_dual_infeasibilities =
|
|
2627
|
+
ekk_instance_.analysis_.num_dual_phase_1_lp_dual_infeasibility;
|
|
2628
|
+
if (num_lp_dual_infeasibilities == 0) {
|
|
2629
|
+
highsLogDev(
|
|
2630
|
+
ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
2631
|
+
"LP is dual feasible wrt Phase 2 bounds after removing cost "
|
|
2632
|
+
"perturbations so go to phase 2\n");
|
|
2633
|
+
solve_phase = kSolvePhase2;
|
|
2634
|
+
} else {
|
|
2635
|
+
// LP is dual infeasible if the dual objective is sufficiently
|
|
2636
|
+
// negative, so no conclusions on the primal LP can be deduced
|
|
2637
|
+
// - could be primal unbounded or primal infeasible.
|
|
2638
|
+
//
|
|
2639
|
+
// Indicate the conclusion of dual infeasibility by setting
|
|
2640
|
+
// the scaled model status
|
|
2641
|
+
reportOnPossibleLpDualInfeasibility();
|
|
2642
|
+
model_status = HighsModelStatus::kUnboundedOrInfeasible;
|
|
2643
|
+
solve_phase = kSolvePhaseExit;
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
} else {
|
|
2647
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
2648
|
+
"LP has %d dual feasibilities wrt Phase 1 bounds after "
|
|
2649
|
+
"removing cost perturbations "
|
|
2650
|
+
"so return to phase 1\n",
|
|
2651
|
+
dualInfeasCount);
|
|
2652
|
+
assert(solve_phase == kSolvePhase1);
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
void HEkkDual::exitPhase1ResetDuals() {
|
|
2657
|
+
const HighsLp& lp = ekk_instance_.lp_;
|
|
2658
|
+
const SimplexBasis& basis = ekk_instance_.basis_;
|
|
2659
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
2660
|
+
// This use of costs_alt_perturbed is not executed by ctest
|
|
2661
|
+
//
|
|
2662
|
+
// assert(99==2);
|
|
2663
|
+
if (info.costs_perturbed) {
|
|
2664
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
2665
|
+
"Costs are already perturbed in exitPhase1ResetDuals\n");
|
|
2666
|
+
} else {
|
|
2667
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kDetailed,
|
|
2668
|
+
"Re-perturbing costs when optimal in phase 1\n");
|
|
2669
|
+
ekk_instance_.initialiseCost(SimplexAlgorithm::kDual, kSolvePhase2, true);
|
|
2670
|
+
ekk_instance_.computeDual();
|
|
2671
|
+
}
|
|
2672
|
+
|
|
2673
|
+
const HighsInt numTot = lp.num_col_ + lp.num_row_;
|
|
2674
|
+
HighsInt num_shift = 0;
|
|
2675
|
+
double sum_shift = 0;
|
|
2676
|
+
for (HighsInt iVar = 0; iVar < numTot; iVar++) {
|
|
2677
|
+
if (basis.nonbasicFlag_[iVar]) {
|
|
2678
|
+
double lp_lower;
|
|
2679
|
+
double lp_upper;
|
|
2680
|
+
if (iVar < lp.num_col_) {
|
|
2681
|
+
lp_lower = lp.col_lower_[iVar];
|
|
2682
|
+
lp_upper = lp.col_upper_[iVar];
|
|
2683
|
+
} else {
|
|
2684
|
+
HighsInt iRow = iVar - lp.num_col_;
|
|
2685
|
+
lp_lower = lp.row_lower_[iRow];
|
|
2686
|
+
lp_upper = lp.row_upper_[iRow];
|
|
2687
|
+
}
|
|
2688
|
+
if (lp_lower <= -kHighsInf && lp_upper >= kHighsInf) {
|
|
2689
|
+
const double shift = -info.workDual_[iVar];
|
|
2690
|
+
info.workDual_[iVar] = 0;
|
|
2691
|
+
info.workCost_[iVar] = info.workCost_[iVar] + shift;
|
|
2692
|
+
num_shift++;
|
|
2693
|
+
sum_shift += fabs(shift);
|
|
2694
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kVerbose,
|
|
2695
|
+
"Variable %" HIGHSINT_FORMAT
|
|
2696
|
+
" is free: shift cost to zero dual of %g\n",
|
|
2697
|
+
iVar, shift);
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
if (num_shift) {
|
|
2702
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kDetailed,
|
|
2703
|
+
"Performed %" HIGHSINT_FORMAT
|
|
2704
|
+
" cost shift(s) for free variables to zero "
|
|
2705
|
+
"dual values: total = %g\n",
|
|
2706
|
+
num_shift, sum_shift);
|
|
2707
|
+
info.costs_shifted = true;
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2711
|
+
void HEkkDual::reportOnPossibleLpDualInfeasibility() {
|
|
2712
|
+
HighsSimplexInfo& info = ekk_instance_.info_;
|
|
2713
|
+
HighsSimplexAnalysis& analysis = ekk_instance_.analysis_;
|
|
2714
|
+
assert(solve_phase == kSolvePhase1);
|
|
2715
|
+
assert(row_out == kNoRowChosen);
|
|
2716
|
+
// assert(info.dual_objective_value < 0);
|
|
2717
|
+
assert(!info.costs_perturbed);
|
|
2718
|
+
std::string lp_dual_status;
|
|
2719
|
+
if (analysis.num_dual_phase_1_lp_dual_infeasibility) {
|
|
2720
|
+
lp_dual_status = "infeasible";
|
|
2721
|
+
} else {
|
|
2722
|
+
lp_dual_status = "feasible";
|
|
2723
|
+
}
|
|
2724
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
2725
|
+
"LP is dual %s with dual phase 1 objective %10.4g and num / "
|
|
2726
|
+
"max / sum dual infeasibilities = %" HIGHSINT_FORMAT
|
|
2727
|
+
" / %9.4g / %9.4g\n",
|
|
2728
|
+
lp_dual_status.c_str(), info.dual_objective_value,
|
|
2729
|
+
analysis.num_dual_phase_1_lp_dual_infeasibility,
|
|
2730
|
+
analysis.max_dual_phase_1_lp_dual_infeasibility,
|
|
2731
|
+
analysis.sum_dual_phase_1_lp_dual_infeasibility);
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2734
|
+
bool HEkkDual::dualInfoOk(const HighsLp& lp) const {
|
|
2735
|
+
HighsInt lp_num_col = lp.num_col_;
|
|
2736
|
+
HighsInt lp_num_row = lp.num_row_;
|
|
2737
|
+
bool dimensions_ok;
|
|
2738
|
+
dimensions_ok = lp_num_col == solver_num_col && lp_num_row == solver_num_row;
|
|
2739
|
+
assert(dimensions_ok);
|
|
2740
|
+
if (!dimensions_ok) {
|
|
2741
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kError,
|
|
2742
|
+
"LP-Solver dimension incompatibility (%" HIGHSINT_FORMAT
|
|
2743
|
+
", %" HIGHSINT_FORMAT ") != (%" HIGHSINT_FORMAT
|
|
2744
|
+
", %" HIGHSINT_FORMAT ")\n",
|
|
2745
|
+
lp_num_col, solver_num_col, lp_num_row, solver_num_row);
|
|
2746
|
+
return false;
|
|
2747
|
+
}
|
|
2748
|
+
dimensions_ok = lp_num_col == simplex_nla->lp_->num_col_ &&
|
|
2749
|
+
lp_num_row == simplex_nla->lp_->num_row_;
|
|
2750
|
+
assert(dimensions_ok);
|
|
2751
|
+
if (!dimensions_ok) {
|
|
2752
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kError,
|
|
2753
|
+
"LP-Factor dimension incompatibility (%" HIGHSINT_FORMAT
|
|
2754
|
+
", %" HIGHSINT_FORMAT ") != (%" HIGHSINT_FORMAT
|
|
2755
|
+
", %" HIGHSINT_FORMAT ")\n",
|
|
2756
|
+
lp_num_col, simplex_nla->lp_->num_col_, lp_num_row,
|
|
2757
|
+
simplex_nla->lp_->num_row_);
|
|
2758
|
+
return false;
|
|
2759
|
+
}
|
|
2760
|
+
return true;
|
|
2761
|
+
}
|
|
2762
|
+
|
|
2763
|
+
bool HEkkDual::bailoutOnDualObjective() {
|
|
2764
|
+
if (ekk_instance_.solve_bailout_) {
|
|
2765
|
+
// Bailout has already been decided: check that it's for one of these
|
|
2766
|
+
// reasons
|
|
2767
|
+
assert(ekk_instance_.model_status_ == HighsModelStatus::kTimeLimit ||
|
|
2768
|
+
ekk_instance_.model_status_ == HighsModelStatus::kIterationLimit ||
|
|
2769
|
+
ekk_instance_.model_status_ == HighsModelStatus::kObjectiveBound);
|
|
2770
|
+
} else if (ekk_instance_.lp_.sense_ == ObjSense::kMinimize &&
|
|
2771
|
+
solve_phase == kSolvePhase2) {
|
|
2772
|
+
if (ekk_instance_.info_.updated_dual_objective_value >
|
|
2773
|
+
ekk_instance_.options_->objective_bound)
|
|
2774
|
+
ekk_instance_.solve_bailout_ = reachedExactObjectiveBound();
|
|
2775
|
+
}
|
|
2776
|
+
return ekk_instance_.solve_bailout_;
|
|
2777
|
+
}
|
|
2778
|
+
|
|
2779
|
+
bool HEkkDual::reachedExactObjectiveBound() {
|
|
2780
|
+
// Solving a minimization in dual simplex phase 2, and dual
|
|
2781
|
+
// objective exceeds the prescribed upper bound. However, costs
|
|
2782
|
+
// will be perturbed, so need to check whether exact dual
|
|
2783
|
+
// objective value exceeds the prescribed upper bound. This can be
|
|
2784
|
+
// a relatively expensive calculation, so determine whether to do
|
|
2785
|
+
// it according to the sparsity of the pivotal row
|
|
2786
|
+
bool reached_exact_objective_bound = false;
|
|
2787
|
+
double use_row_ap_density =
|
|
2788
|
+
std::min(std::max(ekk_instance_.info_.row_ap_density, 0.01), 1.0);
|
|
2789
|
+
HighsInt check_frequency = 1.0 / use_row_ap_density;
|
|
2790
|
+
assert(check_frequency > 0);
|
|
2791
|
+
|
|
2792
|
+
bool check_exact_dual_objective_value =
|
|
2793
|
+
ekk_instance_.info_.update_count % check_frequency == 0;
|
|
2794
|
+
|
|
2795
|
+
if (check_exact_dual_objective_value) {
|
|
2796
|
+
const double objective_bound = ekk_instance_.options_->objective_bound;
|
|
2797
|
+
const double perturbed_dual_objective_value =
|
|
2798
|
+
ekk_instance_.info_.updated_dual_objective_value;
|
|
2799
|
+
const double perturbed_value_residual =
|
|
2800
|
+
perturbed_dual_objective_value - objective_bound;
|
|
2801
|
+
HVector dual_col;
|
|
2802
|
+
HVector dual_row;
|
|
2803
|
+
const double exact_dual_objective_value =
|
|
2804
|
+
computeExactDualObjectiveValue(dual_col, dual_row);
|
|
2805
|
+
const double exact_value_residual =
|
|
2806
|
+
exact_dual_objective_value - objective_bound;
|
|
2807
|
+
std::string action;
|
|
2808
|
+
if (exact_dual_objective_value > objective_bound) {
|
|
2809
|
+
highsLogDev(
|
|
2810
|
+
ekk_instance_.options_->log_options, HighsLogType::kDetailed,
|
|
2811
|
+
"HEkkDual::solvePhase2: %12g = Objective > ObjectiveUB = %12g\n",
|
|
2812
|
+
ekk_instance_.info_.updated_dual_objective_value, objective_bound);
|
|
2813
|
+
action = "Have DualUB bailout";
|
|
2814
|
+
if (ekk_instance_.info_.costs_perturbed ||
|
|
2815
|
+
ekk_instance_.info_.costs_shifted) {
|
|
2816
|
+
// Remove cost perturbation/shifting
|
|
2817
|
+
ekk_instance_.initialiseCost(SimplexAlgorithm::kDual, kSolvePhase2);
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
// Set the duals as computed in the computeExactDualObjective call
|
|
2821
|
+
for (HighsInt i = 0; i < solver_num_col; i++)
|
|
2822
|
+
ekk_instance_.info_.workDual_[i] =
|
|
2823
|
+
ekk_instance_.info_.workCost_[i] - dual_row.array[i];
|
|
2824
|
+
for (HighsInt i = solver_num_col; i < solver_num_tot; i++)
|
|
2825
|
+
ekk_instance_.info_.workDual_[i] = -dual_col.array[i - solver_num_col];
|
|
2826
|
+
|
|
2827
|
+
// Since the computeExactDualObjectiveValue() call succeeded, if there are
|
|
2828
|
+
// any dual infeasibilities they can be removed by a bound flip
|
|
2829
|
+
force_phase2 = false;
|
|
2830
|
+
correctDualInfeasibilities(dualInfeasCount);
|
|
2831
|
+
|
|
2832
|
+
// no shifts should have occurred
|
|
2833
|
+
assert(!ekk_instance_.info_.costs_shifted);
|
|
2834
|
+
reached_exact_objective_bound = true;
|
|
2835
|
+
ekk_instance_.model_status_ = HighsModelStatus::kObjectiveBound;
|
|
2836
|
+
} else {
|
|
2837
|
+
action = "No DualUB bailout";
|
|
2838
|
+
}
|
|
2839
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
2840
|
+
"%s on iteration %" HIGHSINT_FORMAT
|
|
2841
|
+
": Density %11.4g; Frequency %" HIGHSINT_FORMAT
|
|
2842
|
+
": "
|
|
2843
|
+
"Residual(Perturbed = %g; Exact = %g)\n",
|
|
2844
|
+
action.c_str(), ekk_instance_.iteration_count_,
|
|
2845
|
+
use_row_ap_density, check_frequency, perturbed_value_residual,
|
|
2846
|
+
exact_value_residual);
|
|
2847
|
+
}
|
|
2848
|
+
return reached_exact_objective_bound;
|
|
2849
|
+
}
|
|
2850
|
+
|
|
2851
|
+
double HEkkDual::computeExactDualObjectiveValue(HVector& dual_col,
|
|
2852
|
+
HVector& dual_row) {
|
|
2853
|
+
const HighsLp& lp = ekk_instance_.lp_;
|
|
2854
|
+
const SimplexBasis& basis = ekk_instance_.basis_;
|
|
2855
|
+
const HighsSimplexInfo& info = ekk_instance_.info_;
|
|
2856
|
+
// Create a local buffer for the pi vector
|
|
2857
|
+
dual_col.setup(lp.num_row_);
|
|
2858
|
+
dual_col.clear();
|
|
2859
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
2860
|
+
HighsInt iVar = basis.basicIndex_[iRow];
|
|
2861
|
+
if (iVar < lp.num_col_) {
|
|
2862
|
+
const double value = lp.col_cost_[iVar];
|
|
2863
|
+
if (value) {
|
|
2864
|
+
dual_col.array[iRow] = value;
|
|
2865
|
+
dual_col.index[dual_col.count++] = iRow;
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
// Create a local buffer for the dual vector
|
|
2870
|
+
const HighsInt numTot = lp.num_col_ + lp.num_row_;
|
|
2871
|
+
dual_row.setup(lp.num_col_);
|
|
2872
|
+
dual_row.clear();
|
|
2873
|
+
if (dual_col.count) {
|
|
2874
|
+
const bool quad_precision = false;
|
|
2875
|
+
const double expected_density = 1;
|
|
2876
|
+
simplex_nla->btran(dual_col, expected_density);
|
|
2877
|
+
lp.a_matrix_.priceByColumn(quad_precision, dual_row, dual_col);
|
|
2878
|
+
}
|
|
2879
|
+
// Compute dual infeasibilities
|
|
2880
|
+
ekk_instance_.computeSimplexDualInfeasible();
|
|
2881
|
+
if (info.num_dual_infeasibilities > 0)
|
|
2882
|
+
highsLogDev(ekk_instance_.options_->log_options, HighsLogType::kInfo,
|
|
2883
|
+
"When computing exact dual objective, the unperturbed costs "
|
|
2884
|
+
"yield num / max / sum dual "
|
|
2885
|
+
"infeasibilities = %d / %g / %g\n",
|
|
2886
|
+
(int)info.num_dual_infeasibilities, info.max_dual_infeasibility,
|
|
2887
|
+
info.sum_dual_infeasibilities);
|
|
2888
|
+
HighsCDouble dual_objective = lp.offset_;
|
|
2889
|
+
double norm_dual = 0;
|
|
2890
|
+
double norm_delta_dual = 0;
|
|
2891
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
2892
|
+
if (!basis.nonbasicFlag_[iCol]) continue;
|
|
2893
|
+
double exact_dual = lp.col_cost_[iCol] - dual_row.array[iCol];
|
|
2894
|
+
// The active value must be decided based on the exact dual. For a nonbasic
|
|
2895
|
+
// column the bound that must be used may flip due to cost perturbation
|
|
2896
|
+
// flipping the sign of its dual and for a basic variable we may need to add
|
|
2897
|
+
// to the dual objective using one of the bounds when its dual is not zero.
|
|
2898
|
+
double active_value;
|
|
2899
|
+
if (exact_dual > ekk_instance_.options_->small_matrix_value)
|
|
2900
|
+
active_value = lp.col_lower_[iCol];
|
|
2901
|
+
else if (exact_dual < -ekk_instance_.options_->small_matrix_value)
|
|
2902
|
+
active_value = lp.col_upper_[iCol];
|
|
2903
|
+
else
|
|
2904
|
+
active_value = info.workValue_[iCol];
|
|
2905
|
+
|
|
2906
|
+
// when the active value is infinite the dual objective lower bound is
|
|
2907
|
+
// -infinity
|
|
2908
|
+
if (highs_isInfinity(fabs(active_value))) return -kHighsInf;
|
|
2909
|
+
|
|
2910
|
+
double residual = fabs(exact_dual - info.workDual_[iCol]);
|
|
2911
|
+
norm_dual += fabs(exact_dual);
|
|
2912
|
+
norm_delta_dual += residual;
|
|
2913
|
+
if (residual > 1e10)
|
|
2914
|
+
highsLogDev(
|
|
2915
|
+
ekk_instance_.options_->log_options, HighsLogType::kWarning,
|
|
2916
|
+
"Col %4" HIGHSINT_FORMAT
|
|
2917
|
+
": ExactDual = %11.4g; WorkDual = %11.4g; Residual = %11.4g\n",
|
|
2918
|
+
iCol, exact_dual, info.workDual_[iCol], residual);
|
|
2919
|
+
dual_objective += active_value * exact_dual;
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
for (HighsInt iVar = lp.num_col_; iVar < numTot; iVar++) {
|
|
2923
|
+
if (!basis.nonbasicFlag_[iVar]) continue;
|
|
2924
|
+
HighsInt iRow = iVar - lp.num_col_;
|
|
2925
|
+
double exact_dual = dual_col.array[iRow];
|
|
2926
|
+
// Similarly to the column case above the active value must be decided based
|
|
2927
|
+
// on the exact dual. For a nonbasic row the bound that must be used
|
|
2928
|
+
// may flip due to cost perturbation flipping the sign of its dual and for a
|
|
2929
|
+
// basic variable we may need to add to the dual objective using one of the
|
|
2930
|
+
// bounds when its dual is not zero.
|
|
2931
|
+
double active_value;
|
|
2932
|
+
if (exact_dual > ekk_instance_.options_->small_matrix_value)
|
|
2933
|
+
active_value = lp.row_lower_[iRow];
|
|
2934
|
+
else if (exact_dual < -ekk_instance_.options_->small_matrix_value)
|
|
2935
|
+
active_value = lp.row_upper_[iRow];
|
|
2936
|
+
else
|
|
2937
|
+
active_value = -info.workValue_[iVar];
|
|
2938
|
+
|
|
2939
|
+
// when the active value is infinite the dual objective lower bound is
|
|
2940
|
+
// -infinity
|
|
2941
|
+
if (highs_isInfinity(fabs(active_value))) return -kHighsInf;
|
|
2942
|
+
|
|
2943
|
+
double residual = fabs(exact_dual + info.workDual_[iVar]);
|
|
2944
|
+
norm_dual += fabs(exact_dual);
|
|
2945
|
+
norm_delta_dual += residual;
|
|
2946
|
+
if (residual > 1e10)
|
|
2947
|
+
highsLogDev(
|
|
2948
|
+
ekk_instance_.options_->log_options, HighsLogType::kWarning,
|
|
2949
|
+
"Row %4" HIGHSINT_FORMAT
|
|
2950
|
+
": ExactDual = %11.4g; WorkDual = %11.4g; Residual = %11.4g\n",
|
|
2951
|
+
iRow, exact_dual, info.workDual_[iVar], residual);
|
|
2952
|
+
dual_objective += active_value * exact_dual;
|
|
2953
|
+
}
|
|
2954
|
+
double relative_delta = norm_delta_dual / std::max(norm_dual, 1.0);
|
|
2955
|
+
if (relative_delta > 1e-3)
|
|
2956
|
+
highsLogDev(
|
|
2957
|
+
ekk_instance_.options_->log_options, HighsLogType::kWarning,
|
|
2958
|
+
"||exact dual vector|| = %g; ||delta dual vector|| = %g: ratio = %g\n",
|
|
2959
|
+
norm_dual, norm_delta_dual, relative_delta);
|
|
2960
|
+
return double(dual_objective);
|
|
2961
|
+
}
|
|
2962
|
+
|
|
2963
|
+
HighsDebugStatus HEkkDual::debugDualSimplex(const std::string message,
|
|
2964
|
+
const bool initialise) {
|
|
2965
|
+
HighsDebugStatus return_status =
|
|
2966
|
+
ekk_instance_.debugSimplex(message, algorithm, solve_phase, initialise);
|
|
2967
|
+
if (return_status == HighsDebugStatus::kLogicalError) return return_status;
|
|
2968
|
+
if (initialise) return return_status;
|
|
2969
|
+
return HighsDebugStatus::kOk;
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
bool HEkkDual::isBadBasisChange() {
|
|
2973
|
+
return ekk_instance_.isBadBasisChange(SimplexAlgorithm::kDual, variable_in,
|
|
2974
|
+
row_out, rebuild_reason);
|
|
2975
|
+
}
|
|
2976
|
+
|
|
2977
|
+
void HEkkDual::assessPossiblyDualUnbounded() {
|
|
2978
|
+
assert(rebuild_reason == kRebuildReasonPossiblyDualUnbounded);
|
|
2979
|
+
if (solve_phase != kSolvePhase2) return;
|
|
2980
|
+
if (!ekk_instance_.status_.has_fresh_rebuild) return;
|
|
2981
|
+
// Appears to be dual unbounded in phase 2 after fresh
|
|
2982
|
+
// rebuild. Normally this implies primal infeasibility, but only
|
|
2983
|
+
// allow this to be claimed if the proof of primal infeasibility
|
|
2984
|
+
// is true.
|
|
2985
|
+
//
|
|
2986
|
+
const bool proof_of_infeasibility = proofOfPrimalInfeasibility();
|
|
2987
|
+
if (proof_of_infeasibility) {
|
|
2988
|
+
// There is a proof of primal infeasibility
|
|
2989
|
+
solve_phase = kSolvePhaseExit;
|
|
2990
|
+
// Save dual ray information
|
|
2991
|
+
saveDualRay();
|
|
2992
|
+
// Model status should be unset?
|
|
2993
|
+
assert(ekk_instance_.model_status_ == HighsModelStatus::kNotset);
|
|
2994
|
+
ekk_instance_.model_status_ = HighsModelStatus::kInfeasible;
|
|
2995
|
+
} else {
|
|
2996
|
+
// No proof of primal infeasibility, so assume dual unbounded
|
|
2997
|
+
// claim is spurious. Make row_out taboo, and prevent rebuild
|
|
2998
|
+
ekk_instance_.addBadBasisChange(
|
|
2999
|
+
row_out, variable_out, variable_in,
|
|
3000
|
+
BadBasisChangeReason::kFailedInfeasibilityProof, true);
|
|
3001
|
+
rebuild_reason = kRebuildReasonNo;
|
|
3002
|
+
}
|
|
3003
|
+
}
|