lpsolver 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/README.md +104 -26
- data/ext/lpsolver/Makefile +269 -0
- data/ext/lpsolver/ext.c +353 -0
- data/ext/lpsolver/ext.o +0 -0
- data/ext/lpsolver/extconf.rb +79 -0
- data/ext/lpsolver/native.so +0 -0
- data/ext/lpsolver-highs/AUTHORS +7 -0
- data/ext/lpsolver-highs/BUILD.bazel +243 -0
- data/ext/lpsolver-highs/CITATION.cff +29 -0
- data/ext/lpsolver-highs/CMakeCache.txt +406 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeCCompiler.cmake +81 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeCXXCompiler.cmake +101 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeDetermineCompilerABI_C.bin +0 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeDetermineCompilerABI_CXX.bin +0 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeSystem.cmake +15 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CompilerIdC/CMakeCCompilerId.c +904 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CompilerIdC/a.out +0 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CompilerIdCXX/CMakeCXXCompilerId.cpp +919 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CompilerIdCXX/a.out +0 -0
- data/ext/lpsolver-highs/CMakeFiles/CMakeConfigureLog.yaml +576 -0
- data/ext/lpsolver-highs/CMakeFiles/cmake.check_cache +1 -0
- data/ext/lpsolver-highs/CMakeLists.txt +983 -0
- data/ext/lpsolver-highs/CODE_OF_CONDUCT.md +128 -0
- data/ext/lpsolver-highs/CONTRIBUTING.md +31 -0
- data/ext/lpsolver-highs/FEATURES.md +61 -0
- data/ext/lpsolver-highs/LICENSE.txt +21 -0
- data/ext/lpsolver-highs/MODULE.bazel +38 -0
- data/ext/lpsolver-highs/README.md +281 -0
- data/ext/lpsolver-highs/THIRD_PARTY_NOTICES.md +78 -0
- data/ext/lpsolver-highs/Version.txt +4 -0
- data/ext/lpsolver-highs/WORKSPACE +33 -0
- data/ext/lpsolver-highs/app/CMakeLists.txt +110 -0
- data/ext/lpsolver-highs/app/HighsRuntimeOptions.h +292 -0
- data/ext/lpsolver-highs/app/RunHighs.cpp +147 -0
- data/ext/lpsolver-highs/app/highs_webdemo_shell.html +73 -0
- data/ext/lpsolver-highs/build/bin/highs +0 -0
- data/ext/lpsolver-highs/build/include/highs/HConfig.h +22 -0
- data/ext/lpsolver-highs/build/include/highs/Highs.h +1812 -0
- data/ext/lpsolver-highs/build/include/highs/interfaces/highs_c_api.h +2651 -0
- data/ext/lpsolver-highs/build/include/highs/io/Filereader.h +45 -0
- data/ext/lpsolver-highs/build/include/highs/io/FilereaderLp.h +49 -0
- data/ext/lpsolver-highs/build/include/highs/io/FilereaderMps.h +27 -0
- data/ext/lpsolver-highs/build/include/highs/io/HMPSIO.h +78 -0
- data/ext/lpsolver-highs/build/include/highs/io/HMpsFF.h +245 -0
- data/ext/lpsolver-highs/build/include/highs/io/HighsIO.h +118 -0
- data/ext/lpsolver-highs/build/include/highs/io/LoadOptions.h +24 -0
- data/ext/lpsolver-highs/build/include/highs/io/filereaderlp/builder.hpp +25 -0
- data/ext/lpsolver-highs/build/include/highs/io/filereaderlp/def.hpp +19 -0
- data/ext/lpsolver-highs/build/include/highs/io/filereaderlp/model.hpp +68 -0
- data/ext/lpsolver-highs/build/include/highs/io/filereaderlp/reader.hpp +10 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/IpxSolution.h +32 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/IpxWrapper.h +106 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu.h +161 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_factorize.h +247 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_get_factors.h +108 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_initialize.h +119 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_factorize.h +34 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_free.h +19 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_get_factors.h +34 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_initialize.h +46 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_solve_dense.h +29 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_solve_for_update.h +42 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_solve_sparse.h +32 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_update.h +31 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_object.h +30 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_solve_dense.h +75 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_solve_for_update.h +169 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_solve_sparse.h +112 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_update.h +125 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/lu_def.h +39 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/lu_file.h +21 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/lu_internal.h +220 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/lu_list.h +173 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/basiclu_kernel.h +20 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/basiclu_wrapper.h +47 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/basis.h +350 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/conjugate_residuals.h +74 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/control.h +167 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/crossover.h +157 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/diagonal_precond.h +45 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/forrest_tomlin.h +102 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/guess_basis.h +21 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/indexed_vector.h +113 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/info.h +27 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipm.h +94 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_c.h +47 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_config.h +9 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_info.h +111 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_internal.h +89 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_parameters.h +76 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_status.h +57 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/iterate.h +331 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/kkt_solver.h +70 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/kkt_solver_basis.h +66 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/kkt_solver_diag.h +48 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/linear_operator.h +26 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/lp_solver.h +204 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/lu_factorization.h +79 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/lu_update.h +129 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/maxvolume.h +54 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/model.h +413 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/multistream.h +52 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/normal_matrix.h +44 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/power_method.h +44 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/sparse_matrix.h +195 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/sparse_utils.h +58 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/splitted_normal_matrix.h +63 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/starting_basis.h +39 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/symbolic_invert.h +29 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/timer.h +25 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/utils.h +37 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HConst.h +430 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HStruct.h +213 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsAnalysis.h +23 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsCallback.h +104 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsCallbackStruct.h +70 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsDebug.h +34 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsIis.h +139 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsInfo.h +421 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsInfoDebug.h +27 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsLp.h +97 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsLpSolverObject.h +47 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsLpUtils.h +330 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsModelUtils.h +129 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsOptions.h +1715 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsRanging.h +43 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsSolution.h +179 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsSolutionDebug.h +87 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsSolve.h +29 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsStatus.h +29 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsCliqueTable.h +329 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsConflictPool.h +109 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsCutGeneration.h +108 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsCutPool.h +168 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsDebugSol.h +133 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsDomain.h +657 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsDomainChange.h +48 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsDynamicRowMatrix.h +104 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsGFkSolve.h +439 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsImplications.h +194 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsLpAggregator.h +50 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsLpRelaxation.h +361 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsMipAnalysis.h +71 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsMipSolver.h +159 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsMipSolverData.h +313 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsModkSeparator.h +60 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsNodeQueue.h +312 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsObjectiveFunction.h +71 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsPathSeparator.h +39 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsPrimalHeuristics.h +75 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsPseudocost.h +366 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsRedcostFixing.h +42 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsSearch.h +241 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsSeparation.h +41 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsSeparator.h +60 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsTableauSeparator.h +34 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsTransformedLp.h +63 -0
- data/ext/lpsolver-highs/build/include/highs/mip/MipTimer.h +544 -0
- data/ext/lpsolver-highs/build/include/highs/mip/feasibilityjump.hh +800 -0
- data/ext/lpsolver-highs/build/include/highs/model/HighsHessian.h +54 -0
- data/ext/lpsolver-highs/build/include/highs/model/HighsHessianUtils.h +47 -0
- data/ext/lpsolver-highs/build/include/highs/model/HighsModel.h +42 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsBinarySemaphore.h +108 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsCacheAlign.h +82 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsCombinable.h +116 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsMutex.h +124 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsParallel.h +128 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsRaceTimer.h +38 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsSchedulerConstants.h +19 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsSpinMutex.h +48 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsSplitDeque.h +606 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsTask.h +170 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsTaskExecutor.h +217 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/CupdlpWrapper.h +108 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/HiPdlpTimer.h +155 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/HiPdlpWrapper.h +26 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_cs.h +40 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_defs.h +447 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_linalg.h +189 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_proj.h +19 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_restart.h +31 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_scaling.h +26 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_solver.h +105 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_step.h +37 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_utils.c +1850 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/defs.hpp +222 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/linalg.hpp +61 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/logger.hpp +80 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/pdhg.hpp +358 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/restart.hpp +96 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/scaling.hpp +74 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/solver_results.hpp +65 -0
- data/ext/lpsolver-highs/build/include/highs/pdqsort/pdqsort.h +532 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/HPresolve.h +505 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/HPresolveAnalysis.h +52 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/HighsPostsolveStack.h +943 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/HighsSymmetry.h +284 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/ICrash.h +124 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/ICrashUtil.h +62 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/ICrashX.h +23 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/PresolveComponent.h +90 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/a_asm.hpp +77 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/a_quass.hpp +22 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/basis.hpp +159 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/crashsolution.hpp +20 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/dantzigpricing.hpp +80 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/devexpricing.hpp +108 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/eventhandler.hpp +30 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/factor.hpp +408 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/feasibility_bounded.hpp +114 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/feasibility_highs.hpp +301 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/gradient.hpp +46 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/instance.hpp +70 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/matrix.hpp +342 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/perturbation.hpp +15 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/pricing.hpp +22 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/qpconst.hpp +34 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/qpvector.hpp +242 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/quass.hpp +27 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/ratiotest.hpp +26 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/runtime.hpp +45 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/scaling.hpp +15 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/settings.hpp +84 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/snippets.hpp +36 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/statistics.hpp +30 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/steepestedgepricing.hpp +173 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HApp.h +550 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkk.h +419 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkkDual.h +513 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkkDualRHS.h +134 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkkDualRow.h +201 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkkPrimal.h +191 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HSimplex.h +42 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HSimplexDebug.h +48 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HSimplexNla.h +158 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HSimplexReport.h +21 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HighsSimplexAnalysis.h +500 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/SimplexConst.h +273 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/SimplexStruct.h +263 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/SimplexTimer.h +414 -0
- data/ext/lpsolver-highs/build/include/highs/test_kkt/DevKkt.h +143 -0
- data/ext/lpsolver-highs/build/include/highs/test_kkt/KktCh2.h +79 -0
- data/ext/lpsolver-highs/build/include/highs/util/FactorTimer.h +199 -0
- data/ext/lpsolver-highs/build/include/highs/util/HFactor.h +587 -0
- data/ext/lpsolver-highs/build/include/highs/util/HFactorConst.h +81 -0
- data/ext/lpsolver-highs/build/include/highs/util/HFactorDebug.h +55 -0
- data/ext/lpsolver-highs/build/include/highs/util/HSet.h +89 -0
- data/ext/lpsolver-highs/build/include/highs/util/HVector.h +22 -0
- data/ext/lpsolver-highs/build/include/highs/util/HVectorBase.h +102 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsCDouble.h +323 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsComponent.h +53 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsDataStack.h +83 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsDisjointSets.h +107 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsHash.h +1274 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsHashTree.h +1461 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsInt.h +36 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsIntegers.h +212 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsLinearSumBounds.h +203 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsMatrixPic.h +37 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsMatrixSlice.h +561 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsMatrixUtils.h +57 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsMemoryAllocation.h +63 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsRandom.h +242 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsRbTree.h +452 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsSort.h +131 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsSparseMatrix.h +151 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsSparseVectorSum.h +95 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsSplay.h +135 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsTimer.h +385 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsUtils.h +272 -0
- data/ext/lpsolver-highs/build/include/highs/util/stringutil.h +46 -0
- data/ext/lpsolver-highs/build/include/highs/zstr/strict_fstream.hpp +237 -0
- data/ext/lpsolver-highs/build/include/highs/zstr/zstr.hpp +473 -0
- data/ext/lpsolver-highs/build/include/highs_export.h +43 -0
- data/ext/lpsolver-highs/build/lib/cmake/highs/highs-config-version.cmake +65 -0
- data/ext/lpsolver-highs/build/lib/cmake/highs/highs-config.cmake +36 -0
- data/ext/lpsolver-highs/build/lib/cmake/highs/highs-targets-release.cmake +19 -0
- data/ext/lpsolver-highs/build/lib/cmake/highs/highs-targets.cmake +111 -0
- data/ext/lpsolver-highs/build/lib/libhighs.a +0 -0
- data/ext/lpsolver-highs/build/lib/pkgconfig/highs.pc +12 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/AUTHORS +7 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/CITATION.cff +29 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/CODE_OF_CONDUCT.md +128 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/CONTRIBUTING.md +31 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/FEATURES.md +61 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/LICENSE.txt +21 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/README.md +281 -0
- data/ext/lpsolver-highs/build_webdemo.sh +46 -0
- data/ext/lpsolver-highs/check/Avgas.cpp +245 -0
- data/ext/lpsolver-highs/check/Avgas.h +44 -0
- data/ext/lpsolver-highs/check/CMakeLists.txt +573 -0
- data/ext/lpsolver-highs/check/HCheckConfig.h.bazel.in +6 -0
- data/ext/lpsolver-highs/check/HCheckConfig.h.in +12 -0
- data/ext/lpsolver-highs/check/HCheckConfig.h.meson.in +6 -0
- data/ext/lpsolver-highs/check/SpecialLps.h +405 -0
- data/ext/lpsolver-highs/check/TestAlienBasis.cpp +720 -0
- data/ext/lpsolver-highs/check/TestBasis.cpp +359 -0
- data/ext/lpsolver-highs/check/TestBasisSolves.cpp +669 -0
- data/ext/lpsolver-highs/check/TestCAPI.c +2513 -0
- data/ext/lpsolver-highs/check/TestCallbacks.cpp +608 -0
- data/ext/lpsolver-highs/check/TestCheckSolution.cpp +740 -0
- data/ext/lpsolver-highs/check/TestCrossover.cpp +111 -0
- data/ext/lpsolver-highs/check/TestDualize.cpp +172 -0
- data/ext/lpsolver-highs/check/TestEkk.cpp +100 -0
- data/ext/lpsolver-highs/check/TestFactor.cpp +389 -0
- data/ext/lpsolver-highs/check/TestFilereader.cpp +568 -0
- data/ext/lpsolver-highs/check/TestFortranAPI.f90 +65 -0
- data/ext/lpsolver-highs/check/TestHSet.cpp +80 -0
- data/ext/lpsolver-highs/check/TestHighsCDouble.cpp +109 -0
- data/ext/lpsolver-highs/check/TestHighsGFkSolve.cpp +102 -0
- data/ext/lpsolver-highs/check/TestHighsHash.cpp +126 -0
- data/ext/lpsolver-highs/check/TestHighsHessian.cpp +329 -0
- data/ext/lpsolver-highs/check/TestHighsIntegers.cpp +42 -0
- data/ext/lpsolver-highs/check/TestHighsModel.cpp +134 -0
- data/ext/lpsolver-highs/check/TestHighsParallel.cpp +277 -0
- data/ext/lpsolver-highs/check/TestHighsRbTree.cpp +109 -0
- data/ext/lpsolver-highs/check/TestHighsSparseMatrix.cpp +126 -0
- data/ext/lpsolver-highs/check/TestHighsVersion.cpp +61 -0
- data/ext/lpsolver-highs/check/TestHipo.cpp +122 -0
- data/ext/lpsolver-highs/check/TestICrash.cpp +46 -0
- data/ext/lpsolver-highs/check/TestIO.cpp +163 -0
- data/ext/lpsolver-highs/check/TestIis.cpp +1063 -0
- data/ext/lpsolver-highs/check/TestInfo.cpp +116 -0
- data/ext/lpsolver-highs/check/TestIpm.cpp +226 -0
- data/ext/lpsolver-highs/check/TestIpx.cpp +96 -0
- data/ext/lpsolver-highs/check/TestLPFileFormat.cpp +22 -0
- data/ext/lpsolver-highs/check/TestLogging.cpp +69 -0
- data/ext/lpsolver-highs/check/TestLpModification.cpp +2497 -0
- data/ext/lpsolver-highs/check/TestLpOrientation.cpp +121 -0
- data/ext/lpsolver-highs/check/TestLpSolvers.cpp +555 -0
- data/ext/lpsolver-highs/check/TestLpValidation.cpp +689 -0
- data/ext/lpsolver-highs/check/TestMain.cpp +6 -0
- data/ext/lpsolver-highs/check/TestMipSolver.cpp +1406 -0
- data/ext/lpsolver-highs/check/TestModelProperties.cpp +143 -0
- data/ext/lpsolver-highs/check/TestMultiObjective.cpp +198 -0
- data/ext/lpsolver-highs/check/TestNames.cpp +187 -0
- data/ext/lpsolver-highs/check/TestOptions.cpp +544 -0
- data/ext/lpsolver-highs/check/TestPdlp.cpp +327 -0
- data/ext/lpsolver-highs/check/TestPdlpHi.cpp +40 -0
- data/ext/lpsolver-highs/check/TestPresolve.cpp +912 -0
- data/ext/lpsolver-highs/check/TestQpSolver.cpp +1345 -0
- data/ext/lpsolver-highs/check/TestRanging.cpp +558 -0
- data/ext/lpsolver-highs/check/TestRays.cpp +1010 -0
- data/ext/lpsolver-highs/check/TestSemiVariables.cpp +329 -0
- data/ext/lpsolver-highs/check/TestSetup.cpp +12 -0
- data/ext/lpsolver-highs/check/TestSort.cpp +247 -0
- data/ext/lpsolver-highs/check/TestSpecialLps.cpp +775 -0
- data/ext/lpsolver-highs/check/TestThrow.cpp +83 -0
- data/ext/lpsolver-highs/check/TestTspSolver.cpp +19 -0
- data/ext/lpsolver-highs/check/TestUserScale.cpp +444 -0
- data/ext/lpsolver-highs/check/cublas_example.cpp +76 -0
- data/ext/lpsolver-highs/check/cublas_gpu_start.cpp +88 -0
- data/ext/lpsolver-highs/check/hipo_test_option_files/hipo_options_0 +1 -0
- data/ext/lpsolver-highs/check/instances/1448.lp +1 -0
- data/ext/lpsolver-highs/check/instances/1449a.lp +1 -0
- data/ext/lpsolver-highs/check/instances/1449b.lp +1 -0
- data/ext/lpsolver-highs/check/instances/1451.lp +8 -0
- data/ext/lpsolver-highs/check/instances/2122.lp +1822 -0
- data/ext/lpsolver-highs/check/instances/2171.mps +717 -0
- data/ext/lpsolver-highs/check/instances/25fv47.mps +6919 -0
- data/ext/lpsolver-highs/check/instances/2821-duplicate.mps +31 -0
- data/ext/lpsolver-highs/check/instances/2821-qmatrix.mps +31 -0
- data/ext/lpsolver-highs/check/instances/2821-quadobj.mps +29 -0
- data/ext/lpsolver-highs/check/instances/2821-summation.mps +30 -0
- data/ext/lpsolver-highs/check/instances/2821.mps +29 -0
- data/ext/lpsolver-highs/check/instances/2894.mps +89 -0
- data/ext/lpsolver-highs/check/instances/80bau3b.mps +23732 -0
- data/ext/lpsolver-highs/check/instances/WithInf.set +3 -0
- data/ext/lpsolver-highs/check/instances/adlittle.mps +335 -0
- data/ext/lpsolver-highs/check/instances/afiro.mps +83 -0
- data/ext/lpsolver-highs/check/instances/avgas.mps +51 -0
- data/ext/lpsolver-highs/check/instances/bell5.mps +384 -0
- data/ext/lpsolver-highs/check/instances/bgetam.mps +2112 -0
- data/ext/lpsolver-highs/check/instances/blending.mps +13 -0
- data/ext/lpsolver-highs/check/instances/box1.mps +1085 -0
- data/ext/lpsolver-highs/check/instances/chip.mps +13 -0
- data/ext/lpsolver-highs/check/instances/comment.mps +23 -0
- data/ext/lpsolver-highs/check/instances/cplex1.mps +9674 -0
- data/ext/lpsolver-highs/check/instances/dD2e.mps +10 -0
- data/ext/lpsolver-highs/check/instances/dcmulti.mps +2310 -0
- data/ext/lpsolver-highs/check/instances/e226.mps +1733 -0
- data/ext/lpsolver-highs/check/instances/egout-ac.mps +473 -0
- data/ext/lpsolver-highs/check/instances/egout.mps +403 -0
- data/ext/lpsolver-highs/check/instances/etamacro.mps +2084 -0
- data/ext/lpsolver-highs/check/instances/ex72a.mps +849 -0
- data/ext/lpsolver-highs/check/instances/fixed-binary.lp +11 -0
- data/ext/lpsolver-highs/check/instances/flugpl.mps +111 -0
- data/ext/lpsolver-highs/check/instances/flugpl_illegal_integer.sol +24 -0
- data/ext/lpsolver-highs/check/instances/flugpl_integer.sol +25 -0
- data/ext/lpsolver-highs/check/instances/forest6.mps +261 -0
- data/ext/lpsolver-highs/check/instances/galenet.mps +34 -0
- data/ext/lpsolver-highs/check/instances/gams10am.mps +478 -0
- data/ext/lpsolver-highs/check/instances/garbage.ems +3 -0
- data/ext/lpsolver-highs/check/instances/garbage.lp +3 -0
- data/ext/lpsolver-highs/check/instances/garbage.mps +3 -0
- data/ext/lpsolver-highs/check/instances/gas11.mps +2924 -0
- data/ext/lpsolver-highs/check/instances/gesa2.mps +5459 -0
- data/ext/lpsolver-highs/check/instances/greenbea.mps +19215 -0
- data/ext/lpsolver-highs/check/instances/gt2.mps +534 -0
- data/ext/lpsolver-highs/check/instances/infeasible-mip0.mps +140 -0
- data/ext/lpsolver-highs/check/instances/infeasible-mip1.mps +371 -0
- data/ext/lpsolver-highs/check/instances/israel.mps +1490 -0
- data/ext/lpsolver-highs/check/instances/issue-2095.mps +836 -0
- data/ext/lpsolver-highs/check/instances/issue-2173.mps +3331 -0
- data/ext/lpsolver-highs/check/instances/issue-2204.mps +143 -0
- data/ext/lpsolver-highs/check/instances/issue-2290.mps +158 -0
- data/ext/lpsolver-highs/check/instances/issue-2388.lp +76 -0
- data/ext/lpsolver-highs/check/instances/issue-2402.mps +435 -0
- data/ext/lpsolver-highs/check/instances/issue-2446.mps +9154 -0
- data/ext/lpsolver-highs/check/instances/issue-2585.lp +16 -0
- data/ext/lpsolver-highs/check/instances/issue-2874-3.mps +97 -0
- data/ext/lpsolver-highs/check/instances/klein1.mps +422 -0
- data/ext/lpsolver-highs/check/instances/lseu.mps +371 -0
- data/ext/lpsolver-highs/check/instances/model.xyz +1 -0
- data/ext/lpsolver-highs/check/instances/nan0.mps +13 -0
- data/ext/lpsolver-highs/check/instances/nan1.mps +13 -0
- data/ext/lpsolver-highs/check/instances/nan2.mps +13 -0
- data/ext/lpsolver-highs/check/instances/no-newline-eof.lp +5 -0
- data/ext/lpsolver-highs/check/instances/p01.mps +909 -0
- data/ext/lpsolver-highs/check/instances/p0548.mps +1992 -0
- data/ext/lpsolver-highs/check/instances/primal1.mps +3909 -0
- data/ext/lpsolver-highs/check/instances/qap04.mps +606 -0
- data/ext/lpsolver-highs/check/instances/qcqp.lp +8 -0
- data/ext/lpsolver-highs/check/instances/qjh.lp +9 -0
- data/ext/lpsolver-highs/check/instances/qjh.mps +18 -0
- data/ext/lpsolver-highs/check/instances/qjh_qmatrix.mps +19 -0
- data/ext/lpsolver-highs/check/instances/qjh_quadobj.mps +18 -0
- data/ext/lpsolver-highs/check/instances/qjh_quadobj_qmatrix.mps +25 -0
- data/ext/lpsolver-highs/check/instances/qjh_uncon.lp +10 -0
- data/ext/lpsolver-highs/check/instances/qjh_uncon.mps +17 -0
- data/ext/lpsolver-highs/check/instances/qpinfeasible.lp +8 -0
- data/ext/lpsolver-highs/check/instances/qptestnw.lp +7 -0
- data/ext/lpsolver-highs/check/instances/qpunbounded.lp +5 -0
- data/ext/lpsolver-highs/check/instances/refinery.mps +1882 -0
- data/ext/lpsolver-highs/check/instances/rgn.mps +559 -0
- data/ext/lpsolver-highs/check/instances/scrs8.mps +2717 -0
- data/ext/lpsolver-highs/check/instances/sctest.mps +66 -0
- data/ext/lpsolver-highs/check/instances/semi-continuous.lp +13 -0
- data/ext/lpsolver-highs/check/instances/semi-continuous.mps +24 -0
- data/ext/lpsolver-highs/check/instances/semi-integer.lp +15 -0
- data/ext/lpsolver-highs/check/instances/semi-integer.mps +22 -0
- data/ext/lpsolver-highs/check/instances/shell.mps +4039 -0
- data/ext/lpsolver-highs/check/instances/silly-names.mps +14 -0
- data/ext/lpsolver-highs/check/instances/small_mip.mps +87 -0
- data/ext/lpsolver-highs/check/instances/smalllp.mps +21 -0
- data/ext/lpsolver-highs/check/instances/sp150x300d.mps +1983 -0
- data/ext/lpsolver-highs/check/instances/stair.mps +2499 -0
- data/ext/lpsolver-highs/check/instances/standata.mps +2317 -0
- data/ext/lpsolver-highs/check/instances/standgub.mps +2428 -0
- data/ext/lpsolver-highs/check/instances/standmps.mps +2695 -0
- data/ext/lpsolver-highs/check/instances/test.mps +53 -0
- data/ext/lpsolver-highs/check/instances/vol1.mps +1895 -0
- data/ext/lpsolver-highs/check/instances/warnings.mps +68 -0
- data/ext/lpsolver-highs/check/instances/woodinfe.mps +216 -0
- data/ext/lpsolver-highs/check/matrix_multiplication.hpp +49 -0
- data/ext/lpsolver-highs/check/meson.build +92 -0
- data/ext/lpsolver-highs/check/pythontest.py +11 -0
- data/ext/lpsolver-highs/check/sample_options_file +8 -0
- data/ext/lpsolver-highs/cmake/CheckAtomic.cmake +74 -0
- data/ext/lpsolver-highs/cmake/FindCUDAConf.cmake +44 -0
- data/ext/lpsolver-highs/cmake/FindHipoDeps.cmake +351 -0
- data/ext/lpsolver-highs/cmake/README.md +243 -0
- data/ext/lpsolver-highs/cmake/cpp-highs.cmake +243 -0
- data/ext/lpsolver-highs/cmake/dotnet.cmake +94 -0
- data/ext/lpsolver-highs/cmake/highs-config.cmake.in +22 -0
- data/ext/lpsolver-highs/cmake/python-highs.cmake +74 -0
- data/ext/lpsolver-highs/cmake/set-version.cmake +26 -0
- data/ext/lpsolver-highs/cmake/sources-python.cmake +461 -0
- data/ext/lpsolver-highs/cmake/sources.cmake +618 -0
- data/ext/lpsolver-highs/docs/HiGHS_CopyrightHeader.pl +78 -0
- data/ext/lpsolver-highs/docs/HiGHS_CopyrightHeaderUpdateAll +32 -0
- data/ext/lpsolver-highs/docs/Project.toml +7 -0
- data/ext/lpsolver-highs/docs/README.md +27 -0
- data/ext/lpsolver-highs/docs/c_api_gen/HConfig.h +1 -0
- data/ext/lpsolver-highs/docs/c_api_gen/build.jl +48 -0
- data/ext/lpsolver-highs/docs/make.jl +115 -0
- data/ext/lpsolver-highs/docs/src/assets/logo.png +0 -0
- data/ext/lpsolver-highs/docs/src/callbacks.md +171 -0
- data/ext/lpsolver-highs/docs/src/executable.md +88 -0
- data/ext/lpsolver-highs/docs/src/guide/advanced.md +66 -0
- data/ext/lpsolver-highs/docs/src/guide/basic.md +116 -0
- data/ext/lpsolver-highs/docs/src/guide/further.md +193 -0
- data/ext/lpsolver-highs/docs/src/guide/gpu.md +58 -0
- data/ext/lpsolver-highs/docs/src/guide/index.md +18 -0
- data/ext/lpsolver-highs/docs/src/guide/kkt.md +219 -0
- data/ext/lpsolver-highs/docs/src/guide/numerics.md +55 -0
- data/ext/lpsolver-highs/docs/src/index.md +86 -0
- data/ext/lpsolver-highs/docs/src/installation.md +130 -0
- data/ext/lpsolver-highs/docs/src/interfaces/c_api.md +6 -0
- data/ext/lpsolver-highs/docs/src/interfaces/cpp/examples.md +1 -0
- data/ext/lpsolver-highs/docs/src/interfaces/cpp/index.md +29 -0
- data/ext/lpsolver-highs/docs/src/interfaces/cpp/library.md +107 -0
- data/ext/lpsolver-highs/docs/src/interfaces/csharp.md +55 -0
- data/ext/lpsolver-highs/docs/src/interfaces/fortran.md +11 -0
- data/ext/lpsolver-highs/docs/src/interfaces/julia/index.md +130 -0
- data/ext/lpsolver-highs/docs/src/interfaces/other.md +41 -0
- data/ext/lpsolver-highs/docs/src/interfaces/python/example-py.md +275 -0
- data/ext/lpsolver-highs/docs/src/interfaces/python/index.md +91 -0
- data/ext/lpsolver-highs/docs/src/interfaces/python/model-py.md +90 -0
- data/ext/lpsolver-highs/docs/src/options/definitions.md +529 -0
- data/ext/lpsolver-highs/docs/src/options/intro.md +46 -0
- data/ext/lpsolver-highs/docs/src/parallel.md +88 -0
- data/ext/lpsolver-highs/docs/src/solvers.md +168 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsHessian.md +9 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsIis.md +16 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsLp.md +19 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsModel.md +6 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsSparseMatrix.md +10 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/index.md +11 -0
- data/ext/lpsolver-highs/docs/src/structures/enums.md +114 -0
- data/ext/lpsolver-highs/docs/src/structures/index.md +12 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/HighsBasis.md +8 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/HighsInfo.md +148 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/HighsLinearObjective.md +11 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/HighsSolution.md +10 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/index.md +10 -0
- data/ext/lpsolver-highs/docs/src/terminology.md +163 -0
- data/ext/lpsolver-highs/examples/CMakeLists.txt +26 -0
- data/ext/lpsolver-highs/examples/Docs.py +104 -0
- data/ext/lpsolver-highs/examples/branch-and-price.py +465 -0
- data/ext/lpsolver-highs/examples/call_highs_from_c.c +685 -0
- data/ext/lpsolver-highs/examples/call_highs_from_c_minimal.c +659 -0
- data/ext/lpsolver-highs/examples/call_highs_from_cpp.cpp +178 -0
- data/ext/lpsolver-highs/examples/call_highs_from_csharp.cs +83 -0
- data/ext/lpsolver-highs/examples/call_highs_from_fortran.f90 +579 -0
- data/ext/lpsolver-highs/examples/call_highs_from_python.py +448 -0
- data/ext/lpsolver-highs/examples/call_highs_from_python_highspy.py +71 -0
- data/ext/lpsolver-highs/examples/call_highs_from_python_mps.py +59 -0
- data/ext/lpsolver-highs/examples/callback_gap.py +71 -0
- data/ext/lpsolver-highs/examples/chip.py +43 -0
- data/ext/lpsolver-highs/examples/chip0.py +29 -0
- data/ext/lpsolver-highs/examples/distillation.py +77 -0
- data/ext/lpsolver-highs/examples/knapsack.py +43 -0
- data/ext/lpsolver-highs/examples/minimal.py +11 -0
- data/ext/lpsolver-highs/examples/multi_objective.py +139 -0
- data/ext/lpsolver-highs/examples/multiple_objective.py +120 -0
- data/ext/lpsolver-highs/examples/network_flow.py +37 -0
- data/ext/lpsolver-highs/examples/nqueens.py +29 -0
- data/ext/lpsolver-highs/examples/plot_highs_log.py +134 -0
- data/ext/lpsolver-highs/extern/CLI11.hpp +11546 -0
- data/ext/lpsolver-highs/extern/LICENCE_1_0.txt +23 -0
- data/ext/lpsolver-highs/extern/amd/License.txt +35 -0
- data/ext/lpsolver-highs/extern/amd/SuiteSparse_config.c +54 -0
- data/ext/lpsolver-highs/extern/amd/SuiteSparse_config.h +56 -0
- data/ext/lpsolver-highs/extern/amd/amd.h +357 -0
- data/ext/lpsolver-highs/extern/amd/amd_1.c +172 -0
- data/ext/lpsolver-highs/extern/amd/amd_2.c +1761 -0
- data/ext/lpsolver-highs/extern/amd/amd_aat.c +179 -0
- data/ext/lpsolver-highs/extern/amd/amd_control.c +65 -0
- data/ext/lpsolver-highs/extern/amd/amd_defaults.c +37 -0
- data/ext/lpsolver-highs/extern/amd/amd_info.c +120 -0
- data/ext/lpsolver-highs/extern/amd/amd_internal.h +137 -0
- data/ext/lpsolver-highs/extern/amd/amd_order.c +195 -0
- data/ext/lpsolver-highs/extern/amd/amd_post_tree.c +105 -0
- data/ext/lpsolver-highs/extern/amd/amd_postorder.c +140 -0
- data/ext/lpsolver-highs/extern/amd/amd_preprocess.c +107 -0
- data/ext/lpsolver-highs/extern/amd/amd_valid.c +93 -0
- data/ext/lpsolver-highs/extern/amd/changes.txt +8 -0
- data/ext/lpsolver-highs/extern/catch.hpp +18861 -0
- data/ext/lpsolver-highs/extern/metis/Changes.txt +31 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/GKlib.h +62 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/error.c +21 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_arch.h +64 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_defs.h +19 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_macros.h +50 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mkblas.h +51 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mkmemory.h +80 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mkpqueue.h +329 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mkrandom.h +89 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mksort.h +271 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_ms_inttypes.h +41 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_ms_stat.h +22 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_ms_stdint.h +41 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_proto.h +50 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_struct.h +66 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_types.h +15 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/mcore.c +176 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/memory.c +23 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/random.c +37 -0
- data/ext/lpsolver-highs/extern/metis/LICENSE.txt +18 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/auxapi.c +27 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/balance.c +491 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/bucketsort.c +44 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/coarsen.c +895 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/compress.c +231 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/contig.c +83 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/defs.h +39 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/fm.c +527 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/gklib.c +55 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/gklib_defs.h +33 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/graph.c +268 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/initpart.c +385 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/macros.h +59 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/mcutil.c +162 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/metislib.h +35 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/mmd.c +598 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/ometis.c +661 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/options.c +260 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/proto.h +172 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/refine.c +99 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/separator.c +57 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/sfm.c +581 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/srefine.c +152 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/stdheaders.h +29 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/struct.h +117 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/util.c +59 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/wspace.c +91 -0
- data/ext/lpsolver-highs/extern/metis/metis.h +271 -0
- data/ext/lpsolver-highs/extern/pdqsort/license.txt +16 -0
- data/ext/lpsolver-highs/extern/pdqsort/pdqsort.h +532 -0
- data/ext/lpsolver-highs/extern/rcm/LICENSE +19 -0
- data/ext/lpsolver-highs/extern/rcm/rcm.cpp +873 -0
- data/ext/lpsolver-highs/extern/rcm/rcm.h +22 -0
- data/ext/lpsolver-highs/extern/zstr/LICENSE +21 -0
- data/ext/lpsolver-highs/extern/zstr/strict_fstream.hpp +237 -0
- data/ext/lpsolver-highs/extern/zstr/zstr.hpp +473 -0
- data/ext/lpsolver-highs/flake.lock +61 -0
- data/ext/lpsolver-highs/flake.nix +73 -0
- data/ext/lpsolver-highs/highs/CMakeLists.txt +499 -0
- data/ext/lpsolver-highs/highs/HConfig.h.bazel.in +25 -0
- data/ext/lpsolver-highs/highs/HConfig.h.in +22 -0
- data/ext/lpsolver-highs/highs/HConfig.h.meson.in +17 -0
- data/ext/lpsolver-highs/highs/Highs.h +1812 -0
- data/ext/lpsolver-highs/highs/HighsRun.md +143 -0
- data/ext/lpsolver-highs/highs/highs_bindings.cpp +1826 -0
- data/ext/lpsolver-highs/highs/highspy/__init__.py +93 -0
- data/ext/lpsolver-highs/highs/highspy/__init__.pyi +91 -0
- data/ext/lpsolver-highs/highs/highspy/_core/__init__.pyi +1058 -0
- data/ext/lpsolver-highs/highs/highspy/_core/cb.pyi +118 -0
- data/ext/lpsolver-highs/highs/highspy/_core/simplex_constants.pyi +472 -0
- data/ext/lpsolver-highs/highs/highspy/highs.py +2430 -0
- data/ext/lpsolver-highs/highs/interfaces/highs_c_api.cpp +1812 -0
- data/ext/lpsolver-highs/highs/interfaces/highs_c_api.h +2651 -0
- data/ext/lpsolver-highs/highs/interfaces/highs_csharp_api.cs +1142 -0
- data/ext/lpsolver-highs/highs/interfaces/highs_fortran_api.f90 +873 -0
- data/ext/lpsolver-highs/highs/io/Filereader.cpp +87 -0
- data/ext/lpsolver-highs/highs/io/Filereader.h +45 -0
- data/ext/lpsolver-highs/highs/io/FilereaderLp.cpp +539 -0
- data/ext/lpsolver-highs/highs/io/FilereaderLp.h +49 -0
- data/ext/lpsolver-highs/highs/io/FilereaderMps.cpp +86 -0
- data/ext/lpsolver-highs/highs/io/FilereaderMps.h +27 -0
- data/ext/lpsolver-highs/highs/io/HMPSIO.cpp +1001 -0
- data/ext/lpsolver-highs/highs/io/HMPSIO.h +78 -0
- data/ext/lpsolver-highs/highs/io/HMpsFF.cpp +2113 -0
- data/ext/lpsolver-highs/highs/io/HMpsFF.h +245 -0
- data/ext/lpsolver-highs/highs/io/HighsIO.cpp +371 -0
- data/ext/lpsolver-highs/highs/io/HighsIO.h +118 -0
- data/ext/lpsolver-highs/highs/io/LoadOptions.cpp +60 -0
- data/ext/lpsolver-highs/highs/io/LoadOptions.h +24 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/LICENSE +19 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/builder.hpp +25 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/def.hpp +19 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/model.hpp +68 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/reader.cpp +1375 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/reader.hpp +10 -0
- data/ext/lpsolver-highs/highs/ipm/IpxSolution.h +32 -0
- data/ext/lpsolver-highs/highs/ipm/IpxWrapper.cpp +1526 -0
- data/ext/lpsolver-highs/highs/ipm/IpxWrapper.h +106 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu.h +161 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_factorize.c +132 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_factorize.h +247 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_get_factors.c +148 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_get_factors.h +108 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_initialize.c +24 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_initialize.h +119 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_factorize.h +34 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_free.h +19 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_get_factors.h +34 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_initialize.h +46 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_solve_dense.h +29 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_solve_for_update.h +42 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_solve_sparse.h +32 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_update.h +31 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_object.c +325 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_object.h +30 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_dense.c +46 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_dense.h +75 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_for_update.c +79 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_for_update.h +169 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_sparse.c +63 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_sparse.h +112 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_update.c +44 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_update.h +125 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_build_factors.c +441 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_condest.c +124 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_def.h +39 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_dfs.c +141 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_factorize_bump.c +56 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_file.c +184 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_file.h +21 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_garbage_perm.c +53 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_initialize.c +56 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_internal.c +352 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_internal.h +220 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_list.h +173 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_markowitz.c +188 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_matrix_norm.c +51 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_pivot.c +1247 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_residual_test.c +155 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_setup_bump.c +198 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_singletons.c +511 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_dense.c +129 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_for_update.c +360 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_sparse.c +284 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_symbolic.c +48 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_triangular.c +140 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_update.c +908 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/Auxiliary.cpp +301 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/Auxiliary.h +104 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/IntConfig.h +27 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/KrylovMethods.cpp +193 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/KrylovMethods.h +30 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/Log.cpp +60 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/Log.h +62 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/OrderingPrint.h +10 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/VectorOperations.cpp +117 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/VectorOperations.h +59 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/mycblas.h +85 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Analyse.cpp +1367 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Analyse.h +122 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/CallAndTimeBlas.cpp +114 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/CallAndTimeBlas.h +46 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/CliqueStack.cpp +82 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/CliqueStack.h +83 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DataCollector.cpp +326 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DataCollector.h +86 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DenseFact.h +48 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DenseFactHybrid.cpp +279 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DenseFactKernel.cpp +284 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DgemmParallel.cpp +38 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DgemmParallel.h +32 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FactorHiGHS.cpp +57 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FactorHiGHS.h +112 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FactorHiGHSSettings.h +63 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Factorise.cpp +405 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Factorise.h +85 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FormatHandler.cpp +46 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FormatHandler.h +95 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/HybridHybridFormatHandler.cpp +238 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/HybridHybridFormatHandler.h +31 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/HybridSolveHandler.cpp +272 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/HybridSolveHandler.h +26 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/KrylovMethodsIpm.cpp +83 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/KrylovMethodsIpm.h +45 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Numeric.cpp +54 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Numeric.h +46 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/ReturnValues.h +19 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/SolveHandler.cpp +10 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/SolveHandler.h +48 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Swaps.cpp +70 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Swaps.h +19 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Symbolic.cpp +101 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Symbolic.h +220 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Timing.h +114 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Control.cpp +38 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Control.h +41 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/FactorHiGHSSolver.cpp +887 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/FactorHiGHSSolver.h +92 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Info.h +58 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/IpmData.cpp +8 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/IpmData.h +37 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Iterate.cpp +640 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Iterate.h +172 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/LinearSolver.h +81 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/LogHighs.cpp +71 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/LogHighs.h +33 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Model.cpp +403 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Model.h +136 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Options.h +35 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Parameters.h +63 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/PreProcess.cpp +646 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/PreProcess.h +94 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Refine.cpp +214 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Solver.cpp +1346 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Solver.h +338 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Status.h +88 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basiclu_kernel.cc +71 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basiclu_kernel.h +20 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basiclu_wrapper.cc +299 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basiclu_wrapper.h +47 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basis.cc +966 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basis.h +350 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/conjugate_residuals.cc +217 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/conjugate_residuals.h +74 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/control.cc +151 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/control.h +167 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/crossover.cc +479 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/crossover.h +157 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/diagonal_precond.cc +70 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/diagonal_precond.h +45 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/forrest_tomlin.cc +360 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/forrest_tomlin.h +102 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/guess_basis.cc +233 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/guess_basis.h +21 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/indexed_vector.cc +30 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/indexed_vector.h +113 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/info.cc +124 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/info.h +27 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipm.cc +897 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipm.h +94 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_c.cc +83 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_c.h +47 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_config.h +9 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_info.h +111 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_internal.h +89 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_parameters.h +76 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_status.h +57 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/iterate.cc +683 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/iterate.h +331 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver.cc +23 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver.h +70 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver_basis.cc +387 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver_basis.h +66 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver_diag.cc +120 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver_diag.h +48 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/linear_operator.cc +10 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/linear_operator.h +26 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lp_solver.cc +686 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lp_solver.h +204 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lu_factorization.cc +131 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lu_factorization.h +79 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lu_update.cc +62 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lu_update.h +129 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/maxvolume.cc +337 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/maxvolume.h +54 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/model.cc +1528 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/model.h +413 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/multistream.h +52 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/normal_matrix.cc +126 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/normal_matrix.h +44 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/power_method.h +44 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/sparse_matrix.cc +382 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/sparse_matrix.h +195 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/sparse_utils.cc +92 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/sparse_utils.h +58 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/splitted_normal_matrix.cc +117 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/splitted_normal_matrix.h +63 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/starting_basis.cc +182 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/starting_basis.h +39 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/symbolic_invert.cc +183 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/symbolic_invert.h +29 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/timer.cc +16 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/timer.h +25 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/utils.cc +95 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/utils.h +37 -0
- data/ext/lpsolver-highs/highs/lp_data/HConst.h +430 -0
- data/ext/lpsolver-highs/highs/lp_data/HStruct.h +213 -0
- data/ext/lpsolver-highs/highs/lp_data/Highs.cpp +4949 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsAnalysis.h +23 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsCallback.cpp +323 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsCallback.h +104 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsCallbackStruct.h +70 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsDebug.cpp +54 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsDebug.h +34 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsDeprecated.cpp +181 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsIis.cpp +1290 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsIis.h +139 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInfo.cpp +426 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInfo.h +421 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInfoDebug.cpp +175 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInfoDebug.h +27 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInterface.cpp +4344 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLp.cpp +564 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLp.h +97 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLpSolverObject.h +47 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLpUtils.cpp +3794 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLpUtils.h +330 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsModelUtils.cpp +1650 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsModelUtils.h +129 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsOptions.cpp +1176 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsOptions.h +1715 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsRanging.cpp +733 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsRanging.h +43 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolution.cpp +2194 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolution.h +179 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolutionDebug.cpp +490 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolutionDebug.h +87 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolve.cpp +747 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolve.h +29 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsStatus.cpp +48 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsStatus.h +29 -0
- data/ext/lpsolver-highs/highs/lp_data/Iis.md +113 -0
- data/ext/lpsolver-highs/highs/meson.build +433 -0
- data/ext/lpsolver-highs/highs/mip/HighsCliqueTable.cpp +2236 -0
- data/ext/lpsolver-highs/highs/mip/HighsCliqueTable.h +329 -0
- data/ext/lpsolver-highs/highs/mip/HighsConflictPool.cpp +201 -0
- data/ext/lpsolver-highs/highs/mip/HighsConflictPool.h +109 -0
- data/ext/lpsolver-highs/highs/mip/HighsCutGeneration.cpp +1491 -0
- data/ext/lpsolver-highs/highs/mip/HighsCutGeneration.h +108 -0
- data/ext/lpsolver-highs/highs/mip/HighsCutPool.cpp +526 -0
- data/ext/lpsolver-highs/highs/mip/HighsCutPool.h +168 -0
- data/ext/lpsolver-highs/highs/mip/HighsDebugSol.cpp +313 -0
- data/ext/lpsolver-highs/highs/mip/HighsDebugSol.h +133 -0
- data/ext/lpsolver-highs/highs/mip/HighsDomain.cpp +3861 -0
- data/ext/lpsolver-highs/highs/mip/HighsDomain.h +657 -0
- data/ext/lpsolver-highs/highs/mip/HighsDomainChange.h +48 -0
- data/ext/lpsolver-highs/highs/mip/HighsDynamicRowMatrix.cpp +199 -0
- data/ext/lpsolver-highs/highs/mip/HighsDynamicRowMatrix.h +104 -0
- data/ext/lpsolver-highs/highs/mip/HighsFeasibilityJump.cpp +139 -0
- data/ext/lpsolver-highs/highs/mip/HighsGFkSolve.cpp +106 -0
- data/ext/lpsolver-highs/highs/mip/HighsGFkSolve.h +439 -0
- data/ext/lpsolver-highs/highs/mip/HighsImplications.cpp +915 -0
- data/ext/lpsolver-highs/highs/mip/HighsImplications.h +194 -0
- data/ext/lpsolver-highs/highs/mip/HighsLpAggregator.cpp +56 -0
- data/ext/lpsolver-highs/highs/mip/HighsLpAggregator.h +50 -0
- data/ext/lpsolver-highs/highs/mip/HighsLpRelaxation.cpp +1609 -0
- data/ext/lpsolver-highs/highs/mip/HighsLpRelaxation.h +361 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipAnalysis.cpp +313 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipAnalysis.h +71 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipSolver.cpp +1002 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipSolver.h +159 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipSolverData.cpp +2936 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipSolverData.h +313 -0
- data/ext/lpsolver-highs/highs/mip/HighsModkSeparator.cpp +267 -0
- data/ext/lpsolver-highs/highs/mip/HighsModkSeparator.h +60 -0
- data/ext/lpsolver-highs/highs/mip/HighsNodeQueue.cpp +443 -0
- data/ext/lpsolver-highs/highs/mip/HighsNodeQueue.h +312 -0
- data/ext/lpsolver-highs/highs/mip/HighsObjectiveFunction.cpp +124 -0
- data/ext/lpsolver-highs/highs/mip/HighsObjectiveFunction.h +71 -0
- data/ext/lpsolver-highs/highs/mip/HighsPathSeparator.cpp +549 -0
- data/ext/lpsolver-highs/highs/mip/HighsPathSeparator.h +39 -0
- data/ext/lpsolver-highs/highs/mip/HighsPrimalHeuristics.cpp +1673 -0
- data/ext/lpsolver-highs/highs/mip/HighsPrimalHeuristics.h +75 -0
- data/ext/lpsolver-highs/highs/mip/HighsPseudocost.cpp +129 -0
- data/ext/lpsolver-highs/highs/mip/HighsPseudocost.h +366 -0
- data/ext/lpsolver-highs/highs/mip/HighsRedcostFixing.cpp +316 -0
- data/ext/lpsolver-highs/highs/mip/HighsRedcostFixing.h +42 -0
- data/ext/lpsolver-highs/highs/mip/HighsSearch.cpp +1881 -0
- data/ext/lpsolver-highs/highs/mip/HighsSearch.h +241 -0
- data/ext/lpsolver-highs/highs/mip/HighsSeparation.cpp +186 -0
- data/ext/lpsolver-highs/highs/mip/HighsSeparation.h +41 -0
- data/ext/lpsolver-highs/highs/mip/HighsSeparator.cpp +39 -0
- data/ext/lpsolver-highs/highs/mip/HighsSeparator.h +60 -0
- data/ext/lpsolver-highs/highs/mip/HighsTableauSeparator.cpp +244 -0
- data/ext/lpsolver-highs/highs/mip/HighsTableauSeparator.h +34 -0
- data/ext/lpsolver-highs/highs/mip/HighsTransformedLp.cpp +563 -0
- data/ext/lpsolver-highs/highs/mip/HighsTransformedLp.h +63 -0
- data/ext/lpsolver-highs/highs/mip/MipTimer.h +544 -0
- data/ext/lpsolver-highs/highs/mip/feasibilityjump.hh +800 -0
- data/ext/lpsolver-highs/highs/model/HighsHessian.cpp +263 -0
- data/ext/lpsolver-highs/highs/model/HighsHessian.h +54 -0
- data/ext/lpsolver-highs/highs/model/HighsHessianUtils.cpp +584 -0
- data/ext/lpsolver-highs/highs/model/HighsHessianUtils.h +47 -0
- data/ext/lpsolver-highs/highs/model/HighsModel.cpp +46 -0
- data/ext/lpsolver-highs/highs/model/HighsModel.h +42 -0
- data/ext/lpsolver-highs/highs/parallel/HighsBinarySemaphore.h +108 -0
- data/ext/lpsolver-highs/highs/parallel/HighsCacheAlign.h +82 -0
- data/ext/lpsolver-highs/highs/parallel/HighsCombinable.h +116 -0
- data/ext/lpsolver-highs/highs/parallel/HighsMutex.h +124 -0
- data/ext/lpsolver-highs/highs/parallel/HighsParallel.h +128 -0
- data/ext/lpsolver-highs/highs/parallel/HighsRaceTimer.h +38 -0
- data/ext/lpsolver-highs/highs/parallel/HighsSchedulerConstants.h +19 -0
- data/ext/lpsolver-highs/highs/parallel/HighsSpinMutex.h +48 -0
- data/ext/lpsolver-highs/highs/parallel/HighsSplitDeque.h +606 -0
- data/ext/lpsolver-highs/highs/parallel/HighsTask.h +170 -0
- data/ext/lpsolver-highs/highs/parallel/HighsTaskExecutor.cpp +43 -0
- data/ext/lpsolver-highs/highs/parallel/HighsTaskExecutor.h +217 -0
- data/ext/lpsolver-highs/highs/pdlp/CupdlpWrapper.cpp +848 -0
- data/ext/lpsolver-highs/highs/pdlp/CupdlpWrapper.h +108 -0
- data/ext/lpsolver-highs/highs/pdlp/HiPdlpTimer.h +155 -0
- data/ext/lpsolver-highs/highs/pdlp/HiPdlpWrapper.cpp +141 -0
- data/ext/lpsolver-highs/highs/pdlp/HiPdlpWrapper.h +26 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/Diff +12 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/Meld +7 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/Merge +2 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/README.md +95 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/CMakeLists.txt +58 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/cupdlp_cuda_kernels.cu +338 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/cupdlp_cuda_kernels.cuh +319 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/cupdlp_cudalinalg.cu +386 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/cupdlp_cudalinalg.cuh +149 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/test_cublas.c +154 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/test_cuda_linalg.c +79 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp.h +16 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_cs.c +214 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_cs.h +40 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_defs.h +447 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_linalg.c +802 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_linalg.h +189 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_proj.c +148 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_proj.h +19 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_restart.c +124 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_restart.h +31 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_scaling.c +425 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_scaling.h +26 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_solver.c +1498 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_solver.h +105 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_step.c +478 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_step.h +37 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_utils.c +1850 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_utils.h +212 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/glbopts.h +342 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/defs.hpp +222 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/linalg.cc +231 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/linalg.hpp +61 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/logger.cc +225 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/logger.hpp +80 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdhg.cc +2798 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdhg.cu +497 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdhg.hpp +358 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdhg_kernels.hpp +77 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdlp_gpu_debug.hpp +62 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/restart.cc +132 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/restart.hpp +96 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/scaling.cc +307 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/scaling.hpp +74 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/solver_results.hpp +65 -0
- data/ext/lpsolver-highs/highs/presolve/HPresolve.cpp +8511 -0
- data/ext/lpsolver-highs/highs/presolve/HPresolve.h +505 -0
- data/ext/lpsolver-highs/highs/presolve/HPresolveAnalysis.cpp +239 -0
- data/ext/lpsolver-highs/highs/presolve/HPresolveAnalysis.h +52 -0
- data/ext/lpsolver-highs/highs/presolve/HighsPostsolveStack.cpp +1368 -0
- data/ext/lpsolver-highs/highs/presolve/HighsPostsolveStack.h +943 -0
- data/ext/lpsolver-highs/highs/presolve/HighsSymmetry.cpp +1921 -0
- data/ext/lpsolver-highs/highs/presolve/HighsSymmetry.h +284 -0
- data/ext/lpsolver-highs/highs/presolve/ICrash.cpp +474 -0
- data/ext/lpsolver-highs/highs/presolve/ICrash.h +124 -0
- data/ext/lpsolver-highs/highs/presolve/ICrashUtil.cpp +267 -0
- data/ext/lpsolver-highs/highs/presolve/ICrashUtil.h +62 -0
- data/ext/lpsolver-highs/highs/presolve/ICrashX.cpp +173 -0
- data/ext/lpsolver-highs/highs/presolve/ICrashX.h +23 -0
- data/ext/lpsolver-highs/highs/presolve/PresolveComponent.cpp +45 -0
- data/ext/lpsolver-highs/highs/presolve/PresolveComponent.h +90 -0
- data/ext/lpsolver-highs/highs/qpsolver/README.md +185 -0
- data/ext/lpsolver-highs/highs/qpsolver/a_asm.cpp +139 -0
- data/ext/lpsolver-highs/highs/qpsolver/a_asm.hpp +77 -0
- data/ext/lpsolver-highs/highs/qpsolver/a_quass.cpp +194 -0
- data/ext/lpsolver-highs/highs/qpsolver/a_quass.hpp +22 -0
- data/ext/lpsolver-highs/highs/qpsolver/basis.cpp +443 -0
- data/ext/lpsolver-highs/highs/qpsolver/basis.hpp +159 -0
- data/ext/lpsolver-highs/highs/qpsolver/crashsolution.hpp +20 -0
- data/ext/lpsolver-highs/highs/qpsolver/dantzigpricing.hpp +80 -0
- data/ext/lpsolver-highs/highs/qpsolver/devexharrispricing.hpp +98 -0
- data/ext/lpsolver-highs/highs/qpsolver/devexpricing.hpp +108 -0
- data/ext/lpsolver-highs/highs/qpsolver/eventhandler.hpp +30 -0
- data/ext/lpsolver-highs/highs/qpsolver/factor.hpp +408 -0
- data/ext/lpsolver-highs/highs/qpsolver/feasibility_bounded.hpp +114 -0
- data/ext/lpsolver-highs/highs/qpsolver/feasibility_highs.hpp +301 -0
- data/ext/lpsolver-highs/highs/qpsolver/gradient.hpp +46 -0
- data/ext/lpsolver-highs/highs/qpsolver/instance.hpp +70 -0
- data/ext/lpsolver-highs/highs/qpsolver/matrix.hpp +342 -0
- data/ext/lpsolver-highs/highs/qpsolver/perturbation.cpp +41 -0
- data/ext/lpsolver-highs/highs/qpsolver/perturbation.hpp +15 -0
- data/ext/lpsolver-highs/highs/qpsolver/pricing.hpp +22 -0
- data/ext/lpsolver-highs/highs/qpsolver/qpconst.hpp +34 -0
- data/ext/lpsolver-highs/highs/qpsolver/qpvector.hpp +242 -0
- data/ext/lpsolver-highs/highs/qpsolver/quass.cpp +551 -0
- data/ext/lpsolver-highs/highs/qpsolver/quass.hpp +27 -0
- data/ext/lpsolver-highs/highs/qpsolver/ratiotest.cpp +146 -0
- data/ext/lpsolver-highs/highs/qpsolver/ratiotest.hpp +26 -0
- data/ext/lpsolver-highs/highs/qpsolver/reducedcosts.hpp +46 -0
- data/ext/lpsolver-highs/highs/qpsolver/reducedgradient.hpp +95 -0
- data/ext/lpsolver-highs/highs/qpsolver/runtime.hpp +45 -0
- data/ext/lpsolver-highs/highs/qpsolver/scaling.cpp +123 -0
- data/ext/lpsolver-highs/highs/qpsolver/scaling.hpp +15 -0
- data/ext/lpsolver-highs/highs/qpsolver/settings.hpp +84 -0
- data/ext/lpsolver-highs/highs/qpsolver/snippets.hpp +36 -0
- data/ext/lpsolver-highs/highs/qpsolver/statistics.hpp +30 -0
- data/ext/lpsolver-highs/highs/qpsolver/steepestedgepricing.hpp +173 -0
- data/ext/lpsolver-highs/highs/simplex/HApp.h +550 -0
- data/ext/lpsolver-highs/highs/simplex/HEkk.cpp +4404 -0
- data/ext/lpsolver-highs/highs/simplex/HEkk.h +419 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkControl.cpp +146 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDebug.cpp +1722 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDual.cpp +3003 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDual.h +513 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualMulti.cpp +1020 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualRHS.cpp +535 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualRHS.h +134 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualRow.cpp +697 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualRow.h +201 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkInterface.cpp +26 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkPrimal.cpp +2984 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkPrimal.h +191 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplex.cpp +330 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplex.h +42 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexDebug.cpp +145 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexDebug.h +48 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNla.cpp +517 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNla.h +158 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNlaDebug.cpp +373 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNlaFreeze.cpp +28 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNlaProductForm.cpp +113 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexReport.cpp +77 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexReport.h +21 -0
- data/ext/lpsolver-highs/highs/simplex/HighsSimplexAnalysis.cpp +1495 -0
- data/ext/lpsolver-highs/highs/simplex/HighsSimplexAnalysis.h +500 -0
- data/ext/lpsolver-highs/highs/simplex/SimplexConst.h +273 -0
- data/ext/lpsolver-highs/highs/simplex/SimplexStruct.h +263 -0
- data/ext/lpsolver-highs/highs/simplex/SimplexTimer.h +414 -0
- data/ext/lpsolver-highs/highs/test_kkt/DevKkt.cpp +469 -0
- data/ext/lpsolver-highs/highs/test_kkt/DevKkt.h +143 -0
- data/ext/lpsolver-highs/highs/test_kkt/KktCh2.cpp +305 -0
- data/ext/lpsolver-highs/highs/test_kkt/KktCh2.h +79 -0
- data/ext/lpsolver-highs/highs/util/FactorTimer.h +199 -0
- data/ext/lpsolver-highs/highs/util/HFactor.cpp +2597 -0
- data/ext/lpsolver-highs/highs/util/HFactor.h +587 -0
- data/ext/lpsolver-highs/highs/util/HFactorConst.h +81 -0
- data/ext/lpsolver-highs/highs/util/HFactorDebug.cpp +231 -0
- data/ext/lpsolver-highs/highs/util/HFactorDebug.h +55 -0
- data/ext/lpsolver-highs/highs/util/HFactorExtend.cpp +229 -0
- data/ext/lpsolver-highs/highs/util/HFactorRefactor.cpp +304 -0
- data/ext/lpsolver-highs/highs/util/HFactorUtils.cpp +122 -0
- data/ext/lpsolver-highs/highs/util/HSet.cpp +197 -0
- data/ext/lpsolver-highs/highs/util/HSet.h +89 -0
- data/ext/lpsolver-highs/highs/util/HVector.h +22 -0
- data/ext/lpsolver-highs/highs/util/HVectorBase.cpp +271 -0
- data/ext/lpsolver-highs/highs/util/HVectorBase.h +102 -0
- data/ext/lpsolver-highs/highs/util/HighsCDouble.h +323 -0
- data/ext/lpsolver-highs/highs/util/HighsComponent.h +53 -0
- data/ext/lpsolver-highs/highs/util/HighsDataStack.h +83 -0
- data/ext/lpsolver-highs/highs/util/HighsDisjointSets.h +107 -0
- data/ext/lpsolver-highs/highs/util/HighsHash.cpp +10 -0
- data/ext/lpsolver-highs/highs/util/HighsHash.h +1274 -0
- data/ext/lpsolver-highs/highs/util/HighsHashTree.h +1461 -0
- data/ext/lpsolver-highs/highs/util/HighsInt.h +36 -0
- data/ext/lpsolver-highs/highs/util/HighsIntegers.h +212 -0
- data/ext/lpsolver-highs/highs/util/HighsLinearSumBounds.cpp +267 -0
- data/ext/lpsolver-highs/highs/util/HighsLinearSumBounds.h +203 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixPic.cpp +146 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixPic.h +37 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixSlice.h +561 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixUtils.cpp +407 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixUtils.h +57 -0
- data/ext/lpsolver-highs/highs/util/HighsMemoryAllocation.h +63 -0
- data/ext/lpsolver-highs/highs/util/HighsRandom.h +242 -0
- data/ext/lpsolver-highs/highs/util/HighsRbTree.h +452 -0
- data/ext/lpsolver-highs/highs/util/HighsSort.cpp +364 -0
- data/ext/lpsolver-highs/highs/util/HighsSort.h +131 -0
- data/ext/lpsolver-highs/highs/util/HighsSparseMatrix.cpp +1746 -0
- data/ext/lpsolver-highs/highs/util/HighsSparseMatrix.h +151 -0
- data/ext/lpsolver-highs/highs/util/HighsSparseVectorSum.h +95 -0
- data/ext/lpsolver-highs/highs/util/HighsSplay.h +135 -0
- data/ext/lpsolver-highs/highs/util/HighsTimer.h +385 -0
- data/ext/lpsolver-highs/highs/util/HighsUtils.cpp +1259 -0
- data/ext/lpsolver-highs/highs/util/HighsUtils.h +272 -0
- data/ext/lpsolver-highs/highs/util/stringutil.cpp +131 -0
- data/ext/lpsolver-highs/highs/util/stringutil.h +46 -0
- data/ext/lpsolver-highs/highs.pc.in +12 -0
- data/ext/lpsolver-highs/meson.build +198 -0
- data/ext/lpsolver-highs/meson_options.txt +31 -0
- data/ext/lpsolver-highs/nuget/HiGHS_Logo.png +0 -0
- data/ext/lpsolver-highs/nuget/Highs.csproj +25 -0
- data/ext/lpsolver-highs/nuget/Highs.csproj.in +36 -0
- data/ext/lpsolver-highs/nuget/HowToAlternative.md +77 -0
- data/ext/lpsolver-highs/nuget/README.md +38 -0
- data/ext/lpsolver-highs/nuget/arm-toolchain.cmake +15 -0
- data/ext/lpsolver-highs/nuget/build_linux-arm.sh +13 -0
- data/ext/lpsolver-highs/nuget/build_linux.sh +10 -0
- data/ext/lpsolver-highs/nuget/build_windows.ps1 +27 -0
- data/ext/lpsolver-highs/nuget/generatePackage.ps1 +28 -0
- data/ext/lpsolver-highs/pyproject.toml +221 -0
- data/ext/lpsolver-highs/subprojects/pybind11.wrap +13 -0
- data/ext/lpsolver-highs/tests/test_highspy.py +2310 -0
- data/ext/lpsolver-highs/version.rc.in +50 -0
- data/lib/lpsolver/highs +0 -0
- data/lib/lpsolver/model.rb +35 -7
- data/lib/lpsolver/native.so +0 -0
- data/lib/lpsolver/native_model.rb +261 -0
- data/lib/lpsolver/solution.rb +93 -8
- data/lib/lpsolver/version.rb +1 -1
- data/lpsolver.gemspec +4 -1
- metadata +1176 -4
|
@@ -0,0 +1,4404 @@
|
|
|
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/HEkk.cpp
|
|
9
|
+
* @brief
|
|
10
|
+
*/
|
|
11
|
+
#include "simplex/HEkk.h"
|
|
12
|
+
|
|
13
|
+
#include "lp_data/HighsLpSolverObject.h"
|
|
14
|
+
#include "lp_data/HighsLpUtils.h"
|
|
15
|
+
#include "lp_data/HighsModelUtils.h"
|
|
16
|
+
#include "lp_data/HighsSolutionDebug.h"
|
|
17
|
+
#include "parallel/HighsParallel.h"
|
|
18
|
+
#include "simplex/HEkkDual.h"
|
|
19
|
+
#include "simplex/HEkkPrimal.h"
|
|
20
|
+
#include "simplex/HSimplexDebug.h"
|
|
21
|
+
#include "simplex/HSimplexReport.h"
|
|
22
|
+
#include "simplex/SimplexTimer.h"
|
|
23
|
+
|
|
24
|
+
using std::fabs;
|
|
25
|
+
using std::max;
|
|
26
|
+
using std::min;
|
|
27
|
+
|
|
28
|
+
// using std::cout;
|
|
29
|
+
// using std::endl;
|
|
30
|
+
|
|
31
|
+
void HEkk::clear() {
|
|
32
|
+
// Clears Ekk entirely. Clears all associated pointers, data scalars
|
|
33
|
+
// and vectors, and the status values.
|
|
34
|
+
this->clearEkkLp();
|
|
35
|
+
this->clearEkkDualize();
|
|
36
|
+
this->clearEkkData();
|
|
37
|
+
this->clearEkkDualEdgeWeightData();
|
|
38
|
+
this->clearEkkPointers();
|
|
39
|
+
this->basis_.clear();
|
|
40
|
+
this->simplex_nla_.clear();
|
|
41
|
+
this->clearEkkAllStatus();
|
|
42
|
+
this->clearRayRecords();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
void HEkk::clearEkkAllStatus() {
|
|
46
|
+
// Clears the Ekk status entirely. Functionally junks all
|
|
47
|
+
// information relating to the simplex solve, but doesn't clear the
|
|
48
|
+
// associated data scalars and vectors.
|
|
49
|
+
HighsSimplexStatus& status = this->status_;
|
|
50
|
+
status.initialised_for_new_lp = false;
|
|
51
|
+
status.initialised_for_solve = false;
|
|
52
|
+
this->clearNlaStatus();
|
|
53
|
+
this->clearEkkDataStatus();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
void HEkk::clearEkkDataStatus() {
|
|
57
|
+
// Just clears the Ekk status values associated with Ekk-specific
|
|
58
|
+
// data: doesn't clear "initialised_for_new_lp", "initialised_for_solve" or
|
|
59
|
+
// NLA status
|
|
60
|
+
HighsSimplexStatus& status = this->status_;
|
|
61
|
+
status.has_ar_matrix = false;
|
|
62
|
+
status.has_dual_steepest_edge_weights = false;
|
|
63
|
+
status.has_fresh_rebuild = false;
|
|
64
|
+
status.has_dual_objective_value = false;
|
|
65
|
+
status.has_primal_objective_value = false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void HEkk::clearNlaStatus() {
|
|
69
|
+
// Clears Ekk status values associated with NLA. Functionally junks
|
|
70
|
+
// NLA, but doesn't clear the associated data scalars and vectors
|
|
71
|
+
HighsSimplexStatus& status = this->status_;
|
|
72
|
+
status.has_basis = false;
|
|
73
|
+
status.has_nla = false;
|
|
74
|
+
clearNlaInvertStatus();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
void HEkk::clearNlaInvertStatus() {
|
|
78
|
+
this->status_.has_invert = false;
|
|
79
|
+
this->status_.has_fresh_invert = false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
void HEkk::clearRayRecords() {
|
|
83
|
+
this->dual_ray_record_.clear();
|
|
84
|
+
this->primal_ray_record_.clear();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
void HEkk::clearEkkPointers() {
|
|
88
|
+
this->callback_ = nullptr;
|
|
89
|
+
this->options_ = nullptr;
|
|
90
|
+
this->timer_ = nullptr;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
void HEkk::clearEkkLp() {
|
|
94
|
+
this->lp_.clear();
|
|
95
|
+
lp_name_ = "";
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
void HEkk::clearEkkDualize() {
|
|
99
|
+
this->original_col_cost_.clear();
|
|
100
|
+
this->original_col_lower_.clear();
|
|
101
|
+
this->original_col_upper_.clear();
|
|
102
|
+
this->original_row_lower_.clear();
|
|
103
|
+
this->original_row_upper_.clear();
|
|
104
|
+
this->upper_bound_col_.clear();
|
|
105
|
+
this->upper_bound_row_.clear();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
void HEkk::clearEkkDualEdgeWeightData() {
|
|
109
|
+
this->dual_edge_weight_.clear();
|
|
110
|
+
this->scattered_dual_edge_weight_.clear();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
void HEkk::clearEkkData() {
|
|
114
|
+
// Clears Ekk-specific data scalars and vectors. Doesn't clear
|
|
115
|
+
// status, as this is done elsewhere
|
|
116
|
+
//
|
|
117
|
+
// Doesn't clear the LP, simplex NLA or simplex basis as part of
|
|
118
|
+
// clearing Ekk data, so that the simplex basis and HFactor instance
|
|
119
|
+
// are maintained
|
|
120
|
+
//
|
|
121
|
+
// analysis_; No clear yet
|
|
122
|
+
|
|
123
|
+
this->clearEkkDataInfo();
|
|
124
|
+
model_status_ = HighsModelStatus::kNotset;
|
|
125
|
+
// random_; Has no data
|
|
126
|
+
|
|
127
|
+
this->simplex_in_scaled_space_ = false;
|
|
128
|
+
this->ar_matrix_.clear();
|
|
129
|
+
this->scaled_a_matrix_.clear();
|
|
130
|
+
|
|
131
|
+
this->cost_scale_ = 1;
|
|
132
|
+
this->iteration_count_ = 0;
|
|
133
|
+
this->dual_simplex_cleanup_level_ = 0;
|
|
134
|
+
this->dual_simplex_phase1_cleanup_level_ = 0;
|
|
135
|
+
|
|
136
|
+
this->previous_iteration_cycling_detected = -kHighsIInf;
|
|
137
|
+
|
|
138
|
+
this->solve_bailout_ = false;
|
|
139
|
+
this->called_return_from_solve_ = false;
|
|
140
|
+
this->exit_algorithm_ = SimplexAlgorithm::kNone;
|
|
141
|
+
this->return_primal_solution_status_ = 0;
|
|
142
|
+
this->return_dual_solution_status_ = 0;
|
|
143
|
+
|
|
144
|
+
this->proof_index_.clear();
|
|
145
|
+
this->proof_value_.clear();
|
|
146
|
+
|
|
147
|
+
this->clearRayRecords();
|
|
148
|
+
|
|
149
|
+
this->build_synthetic_tick_ = 0.0;
|
|
150
|
+
this->total_synthetic_tick_ = 0.0;
|
|
151
|
+
|
|
152
|
+
// Clear values used for debugging
|
|
153
|
+
this->debug_solve_call_num_ = 0;
|
|
154
|
+
this->debug_basis_id_ = 0;
|
|
155
|
+
this->time_report_ = false;
|
|
156
|
+
this->debug_initial_build_synthetic_tick_ = 0;
|
|
157
|
+
this->debug_solve_report_ = false;
|
|
158
|
+
this->debug_iteration_report_ = false;
|
|
159
|
+
this->debug_basis_report_ = false;
|
|
160
|
+
this->debug_dual_feasible = false;
|
|
161
|
+
this->debug_max_relative_dual_steepest_edge_weight_error = 0;
|
|
162
|
+
|
|
163
|
+
clearBadBasisChange();
|
|
164
|
+
|
|
165
|
+
this->primal_phase1_dual_.clear();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
void HEkk::clearEkkDataInfo() {
|
|
169
|
+
HighsSimplexInfo& info = this->info_;
|
|
170
|
+
info.workCost_.clear();
|
|
171
|
+
info.workDual_.clear();
|
|
172
|
+
info.workShift_.clear();
|
|
173
|
+
info.workLower_.clear();
|
|
174
|
+
info.workUpper_.clear();
|
|
175
|
+
info.workRange_.clear();
|
|
176
|
+
info.workValue_.clear();
|
|
177
|
+
info.workLowerShift_.clear();
|
|
178
|
+
info.workUpperShift_.clear();
|
|
179
|
+
info.baseLower_.clear();
|
|
180
|
+
info.baseUpper_.clear();
|
|
181
|
+
info.baseValue_.clear();
|
|
182
|
+
info.numTotRandomValue_.clear();
|
|
183
|
+
info.numTotPermutation_.clear();
|
|
184
|
+
info.numColPermutation_.clear();
|
|
185
|
+
info.devex_index_.clear();
|
|
186
|
+
info.pivot_.clear();
|
|
187
|
+
info.index_chosen_.clear();
|
|
188
|
+
info.phase1_backtracking_test_done = false;
|
|
189
|
+
info.phase2_backtracking_test_done = false;
|
|
190
|
+
info.backtracking_ = false;
|
|
191
|
+
info.valid_backtracking_basis_ = false;
|
|
192
|
+
info.backtracking_basis_.clear();
|
|
193
|
+
info.backtracking_basis_costs_shifted_ = false;
|
|
194
|
+
info.backtracking_basis_costs_perturbed_ = false;
|
|
195
|
+
info.backtracking_basis_bounds_shifted_ = false;
|
|
196
|
+
info.backtracking_basis_bounds_perturbed_ = false;
|
|
197
|
+
info.backtracking_basis_workShift_.clear();
|
|
198
|
+
info.backtracking_basis_workLowerShift_.clear();
|
|
199
|
+
info.backtracking_basis_workUpperShift_.clear();
|
|
200
|
+
info.backtracking_basis_edge_weight_.clear();
|
|
201
|
+
info.simplex_strategy = 0;
|
|
202
|
+
info.dual_edge_weight_strategy = 0;
|
|
203
|
+
info.primal_edge_weight_strategy = 0;
|
|
204
|
+
info.price_strategy = 0;
|
|
205
|
+
info.dual_simplex_cost_perturbation_multiplier = 1;
|
|
206
|
+
info.primal_simplex_phase1_cost_perturbation_multiplier = 1;
|
|
207
|
+
info.primal_simplex_bound_perturbation_multiplier = 1;
|
|
208
|
+
info.allow_dual_steepest_edge_to_devex_switch = 0;
|
|
209
|
+
info.dual_steepest_edge_weight_log_error_threshold = 0;
|
|
210
|
+
info.run_quiet = false;
|
|
211
|
+
info.store_squared_primal_infeasibility = false;
|
|
212
|
+
info.report_simplex_inner_clock = false;
|
|
213
|
+
info.report_simplex_outer_clock = false;
|
|
214
|
+
info.report_simplex_phases_clock = false;
|
|
215
|
+
info.report_HFactor_clock = false;
|
|
216
|
+
info.analyse_lp = false;
|
|
217
|
+
info.analyse_iterations = false;
|
|
218
|
+
info.analyse_invert_form = false;
|
|
219
|
+
|
|
220
|
+
info.allow_cost_shifting = true;
|
|
221
|
+
info.allow_cost_perturbation = true;
|
|
222
|
+
info.allow_bound_perturbation = true;
|
|
223
|
+
info.costs_shifted = false;
|
|
224
|
+
info.costs_perturbed = false;
|
|
225
|
+
info.bounds_shifted = false;
|
|
226
|
+
info.bounds_perturbed = false;
|
|
227
|
+
|
|
228
|
+
info.num_primal_infeasibilities = kHighsIllegalInfeasibilityCount;
|
|
229
|
+
info.max_primal_infeasibility = kHighsIllegalInfeasibilityMeasure;
|
|
230
|
+
info.sum_primal_infeasibilities = kHighsIllegalInfeasibilityMeasure;
|
|
231
|
+
info.num_dual_infeasibilities = kHighsIllegalInfeasibilityCount;
|
|
232
|
+
info.max_dual_infeasibility = kHighsIllegalInfeasibilityMeasure;
|
|
233
|
+
info.sum_dual_infeasibilities = kHighsIllegalInfeasibilityMeasure;
|
|
234
|
+
info.dual_phase1_iteration_count = 0;
|
|
235
|
+
info.dual_phase2_iteration_count = 0;
|
|
236
|
+
info.primal_phase1_iteration_count = 0;
|
|
237
|
+
info.primal_phase2_iteration_count = 0;
|
|
238
|
+
info.primal_bound_swap = 0;
|
|
239
|
+
info.min_concurrency = 1;
|
|
240
|
+
info.num_concurrency = 1;
|
|
241
|
+
info.max_concurrency = kSimplexConcurrencyLimit;
|
|
242
|
+
info.multi_iteration = 0;
|
|
243
|
+
info.update_count = 0;
|
|
244
|
+
info.dual_objective_value = 0;
|
|
245
|
+
info.primal_objective_value = 0;
|
|
246
|
+
info.updated_dual_objective_value = 0;
|
|
247
|
+
info.updated_primal_objective_value = 0;
|
|
248
|
+
info.num_basic_logicals = 0;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
void HEkk::clearEkkControlInfo() {
|
|
252
|
+
HighsSimplexInfo& info = this->info_;
|
|
253
|
+
info.control_iteration_count0 = 0;
|
|
254
|
+
info.col_aq_density = 0.0;
|
|
255
|
+
info.row_ep_density = 0.0;
|
|
256
|
+
info.row_ap_density = 0.0;
|
|
257
|
+
info.row_DSE_density = 0.0;
|
|
258
|
+
info.col_steepest_edge_density = 0.0;
|
|
259
|
+
info.col_basic_feasibility_change_density = 0.0;
|
|
260
|
+
info.row_basic_feasibility_change_density = 0.0;
|
|
261
|
+
info.col_BFRT_density = 0.0;
|
|
262
|
+
info.primal_col_density = 0.0;
|
|
263
|
+
info.dual_col_density = 0.0;
|
|
264
|
+
info.costly_DSE_frequency = 0;
|
|
265
|
+
info.num_costly_DSE_iteration = 0;
|
|
266
|
+
info.costly_DSE_measure = 0;
|
|
267
|
+
info.average_log_low_DSE_weight_error = 0;
|
|
268
|
+
info.average_log_high_DSE_weight_error = 0;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
void HEkk::clearEkkNlaInfo() {
|
|
272
|
+
HighsSimplexInfo& info = this->info_;
|
|
273
|
+
info.factor_pivot_threshold = 0;
|
|
274
|
+
info.update_limit = 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
void HEkk::invalidate() {
|
|
278
|
+
this->status_.initialised_for_new_lp = false;
|
|
279
|
+
assert(!this->status_.is_dualized);
|
|
280
|
+
assert(!this->status_.is_permuted);
|
|
281
|
+
this->status_.initialised_for_solve = false;
|
|
282
|
+
this->invalidateBasisMatrix();
|
|
283
|
+
this->simplex_stats_.initialise();
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
void HEkk::invalidateBasisMatrix() {
|
|
287
|
+
// When the constraint matrix changes - dimensions or just (basic)
|
|
288
|
+
// values, the simplex NLA becomes invalid, the simplex basis is
|
|
289
|
+
// no longer valid, and
|
|
290
|
+
this->status_.has_nla = false;
|
|
291
|
+
invalidateBasis();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
void HEkk::invalidateBasis() {
|
|
295
|
+
// Invalidate the basis of the simplex LP, and all its other
|
|
296
|
+
// basis-related properties
|
|
297
|
+
this->status_.has_basis = false;
|
|
298
|
+
this->invalidateBasisArtifacts();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
void HEkk::invalidateBasisArtifacts() {
|
|
302
|
+
// Invalidate the artifacts of the basis of the simplex LP
|
|
303
|
+
this->status_.has_ar_matrix = false;
|
|
304
|
+
this->status_.has_dual_steepest_edge_weights = false;
|
|
305
|
+
this->status_.has_invert = false;
|
|
306
|
+
this->status_.has_fresh_invert = false;
|
|
307
|
+
this->status_.has_fresh_rebuild = false;
|
|
308
|
+
this->status_.has_dual_objective_value = false;
|
|
309
|
+
this->status_.has_primal_objective_value = false;
|
|
310
|
+
this->clearRayRecords();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
void HEkk::updateStatus(LpAction action) {
|
|
314
|
+
assert(!this->status_.is_dualized);
|
|
315
|
+
assert(!this->status_.is_permuted);
|
|
316
|
+
switch (action) {
|
|
317
|
+
case LpAction::kScale:
|
|
318
|
+
this->invalidateBasisMatrix();
|
|
319
|
+
break;
|
|
320
|
+
case LpAction::kNewCosts:
|
|
321
|
+
this->status_.has_fresh_rebuild = false;
|
|
322
|
+
this->status_.has_dual_objective_value = false;
|
|
323
|
+
this->status_.has_primal_objective_value = false;
|
|
324
|
+
break;
|
|
325
|
+
case LpAction::kNewBounds:
|
|
326
|
+
this->status_.has_fresh_rebuild = false;
|
|
327
|
+
this->status_.has_dual_objective_value = false;
|
|
328
|
+
this->status_.has_primal_objective_value = false;
|
|
329
|
+
break;
|
|
330
|
+
case LpAction::kNewBasis:
|
|
331
|
+
this->invalidateBasis();
|
|
332
|
+
break;
|
|
333
|
+
case LpAction::kNewCols:
|
|
334
|
+
this->clear();
|
|
335
|
+
// this->invalidateBasisArtifacts();
|
|
336
|
+
break;
|
|
337
|
+
case LpAction::kNewRows:
|
|
338
|
+
if (kExtendInvertWhenAddingRows) {
|
|
339
|
+
// Just clear Ekk data
|
|
340
|
+
this->clearEkkData();
|
|
341
|
+
} else {
|
|
342
|
+
// Clear everything
|
|
343
|
+
this->clear();
|
|
344
|
+
}
|
|
345
|
+
// this->invalidateBasisArtifacts();
|
|
346
|
+
break;
|
|
347
|
+
case LpAction::kDelCols:
|
|
348
|
+
this->clear();
|
|
349
|
+
// this->invalidateBasis();
|
|
350
|
+
break;
|
|
351
|
+
case LpAction::kDelNonbasicCols:
|
|
352
|
+
this->clear();
|
|
353
|
+
// this->invalidateBasis();
|
|
354
|
+
break;
|
|
355
|
+
case LpAction::kDelRows:
|
|
356
|
+
this->clear();
|
|
357
|
+
// this->invalidateBasis();
|
|
358
|
+
break;
|
|
359
|
+
case LpAction::kDelRowsBasisOk:
|
|
360
|
+
assert(1 == 0);
|
|
361
|
+
// info.lp_ = true;
|
|
362
|
+
break;
|
|
363
|
+
case LpAction::kScaledCol:
|
|
364
|
+
this->invalidateBasisMatrix();
|
|
365
|
+
break;
|
|
366
|
+
case LpAction::kScaledRow:
|
|
367
|
+
this->invalidateBasisMatrix();
|
|
368
|
+
break;
|
|
369
|
+
case LpAction::kBacktracking:
|
|
370
|
+
this->status_.has_ar_matrix = false;
|
|
371
|
+
this->status_.has_fresh_rebuild = false;
|
|
372
|
+
this->status_.has_dual_objective_value = false;
|
|
373
|
+
this->status_.has_primal_objective_value = false;
|
|
374
|
+
break;
|
|
375
|
+
default:
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
void HEkk::setNlaPointersForLpAndScale(const HighsLp& lp) {
|
|
381
|
+
assert(status_.has_nla);
|
|
382
|
+
simplex_nla_.setLpAndScalePointers(&lp);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
void HEkk::setNlaPointersForTrans(const HighsLp& lp) {
|
|
386
|
+
assert(status_.has_nla);
|
|
387
|
+
assert(status_.has_basis);
|
|
388
|
+
simplex_nla_.setLpAndScalePointers(&lp);
|
|
389
|
+
simplex_nla_.basic_index_ = basis_.basicIndex_.data();
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
void HEkk::setNlaRefactorInfo() {
|
|
393
|
+
simplex_nla_.factor_.refactor_info_ = this->hot_start_.refactor_info;
|
|
394
|
+
simplex_nla_.factor_.refactor_info_.use = true;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
void HEkk::btran(HVector& rhs, const double expected_density) {
|
|
398
|
+
assert(status_.has_nla);
|
|
399
|
+
simplex_nla_.btran(rhs, expected_density);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
void HEkk::ftran(HVector& rhs, const double expected_density) {
|
|
403
|
+
assert(status_.has_nla);
|
|
404
|
+
simplex_nla_.ftran(rhs, expected_density);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
void HEkk::moveLp(HighsLpSolverObject& solver_object) {
|
|
408
|
+
// Move the incumbent LP to EKK
|
|
409
|
+
HighsLp& incumbent_lp = solver_object.lp_;
|
|
410
|
+
this->lp_ = std::move(incumbent_lp);
|
|
411
|
+
incumbent_lp.is_moved_ = true;
|
|
412
|
+
//
|
|
413
|
+
// Invalidate the row-wise matrix
|
|
414
|
+
this->status_.has_ar_matrix = false;
|
|
415
|
+
//
|
|
416
|
+
// The simplex algorithm runs in the same space as the LP that has
|
|
417
|
+
// just been moved in. This is a scaled space if the LP is scaled.
|
|
418
|
+
this->simplex_in_scaled_space_ = this->lp_.is_scaled_;
|
|
419
|
+
//
|
|
420
|
+
// Update other EKK pointers. Currently just pointers to the
|
|
421
|
+
// HighsOptions and HighsTimer members of the Highs class that are
|
|
422
|
+
// communicated by reference via the HighsLpSolverObject instance.
|
|
423
|
+
this->setPointers(&solver_object.callback_, &solver_object.options_,
|
|
424
|
+
&solver_object.timer_);
|
|
425
|
+
// Initialise Ekk if this has not been done. Ekk isn't initialised
|
|
426
|
+
// if moveLp hasn't been called for this instance of HiGHS, or if
|
|
427
|
+
// the Ekk instance is junked due to removing rows from the LP
|
|
428
|
+
this->initialiseEkk();
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
void HEkk::setPointers(HighsCallback* callback, HighsOptions* options,
|
|
432
|
+
HighsTimer* timer) {
|
|
433
|
+
this->callback_ = callback;
|
|
434
|
+
this->options_ = options;
|
|
435
|
+
this->timer_ = timer;
|
|
436
|
+
this->analysis_.timer_ = this->timer_;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
HighsSparseMatrix* HEkk::getScaledAMatrixPointer() {
|
|
440
|
+
// Return a pointer to either the constraint matrix or a scaled copy
|
|
441
|
+
// (that is a member of the HEkk class), with the latter returned if
|
|
442
|
+
// the LP has scaling factors but is unscaled.
|
|
443
|
+
HighsSparseMatrix* local_scaled_a_matrix = &(this->lp_.a_matrix_);
|
|
444
|
+
if (this->lp_.scale_.has_scaling && !this->lp_.is_scaled_) {
|
|
445
|
+
scaled_a_matrix_ = this->lp_.a_matrix_;
|
|
446
|
+
scaled_a_matrix_.applyScale(this->lp_.scale_);
|
|
447
|
+
local_scaled_a_matrix = &scaled_a_matrix_;
|
|
448
|
+
}
|
|
449
|
+
return local_scaled_a_matrix;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
HighsStatus HEkk::dualize() {
|
|
453
|
+
assert(lp_.a_matrix_.isColwise());
|
|
454
|
+
original_num_col_ = lp_.num_col_;
|
|
455
|
+
original_num_row_ = lp_.num_row_;
|
|
456
|
+
original_num_nz_ = lp_.a_matrix_.numNz();
|
|
457
|
+
original_offset_ = lp_.offset_;
|
|
458
|
+
original_col_cost_ = lp_.col_cost_;
|
|
459
|
+
original_col_lower_ = lp_.col_lower_;
|
|
460
|
+
original_col_upper_ = lp_.col_upper_;
|
|
461
|
+
original_row_lower_ = lp_.row_lower_;
|
|
462
|
+
original_row_upper_ = lp_.row_upper_;
|
|
463
|
+
// Reserve space for simple dual
|
|
464
|
+
lp_.col_cost_.reserve(original_num_row_);
|
|
465
|
+
lp_.col_lower_.reserve(original_num_row_);
|
|
466
|
+
lp_.col_upper_.reserve(original_num_row_);
|
|
467
|
+
lp_.row_lower_.reserve(original_num_col_);
|
|
468
|
+
lp_.row_upper_.reserve(original_num_col_);
|
|
469
|
+
// Invalidate the original data
|
|
470
|
+
lp_.col_cost_.resize(0);
|
|
471
|
+
lp_.col_lower_.resize(0);
|
|
472
|
+
lp_.col_upper_.resize(0);
|
|
473
|
+
lp_.row_lower_.resize(0);
|
|
474
|
+
lp_.row_upper_.resize(0);
|
|
475
|
+
// The bulk of the constraint matrix of the dual LP is the transpose
|
|
476
|
+
// of the primal constraint matrix. This is obtained row-wise by
|
|
477
|
+
// copying the matrix and flipping the dimensions
|
|
478
|
+
HighsSparseMatrix dual_matrix = lp_.a_matrix_;
|
|
479
|
+
dual_matrix.num_row_ = original_num_col_;
|
|
480
|
+
dual_matrix.num_col_ = original_num_row_;
|
|
481
|
+
dual_matrix.format_ = MatrixFormat::kRowwise;
|
|
482
|
+
// The primal_bound_value vector accumulates the values of the
|
|
483
|
+
// finite bounds on variables - or zero for a free variable - used
|
|
484
|
+
// later to compute the offset and shift for the costs. Many of
|
|
485
|
+
// these components will be zero - all for the case x>=0 - so
|
|
486
|
+
// maintain a list of the nonzeros and corresponding indices. Don't
|
|
487
|
+
// reserve space since they may not be needed
|
|
488
|
+
vector<double> primal_bound_value;
|
|
489
|
+
vector<HighsInt> primal_bound_index;
|
|
490
|
+
const double inf = kHighsInf;
|
|
491
|
+
for (HighsInt iCol = 0; iCol < original_num_col_; iCol++) {
|
|
492
|
+
const double cost = original_col_cost_[iCol];
|
|
493
|
+
const double lower = original_col_lower_[iCol];
|
|
494
|
+
const double upper = original_col_upper_[iCol];
|
|
495
|
+
double primal_bound = inf;
|
|
496
|
+
double row_lower = inf;
|
|
497
|
+
double row_upper = -inf;
|
|
498
|
+
if (lower == upper) {
|
|
499
|
+
// Fixed
|
|
500
|
+
primal_bound = lower;
|
|
501
|
+
// Dual activity a^Ty is free, implying dual for primal column
|
|
502
|
+
// (slack for dual row) is free
|
|
503
|
+
row_lower = -inf;
|
|
504
|
+
row_upper = inf;
|
|
505
|
+
} else if (!highs_isInfinity(-lower)) {
|
|
506
|
+
// Finite lower bound so boxed or lower
|
|
507
|
+
if (!highs_isInfinity(upper)) {
|
|
508
|
+
// Finite upper bound so boxed
|
|
509
|
+
//
|
|
510
|
+
// Treat as lower
|
|
511
|
+
primal_bound = lower;
|
|
512
|
+
// Dual activity a^Ty is bounded above by cost, implying dual
|
|
513
|
+
// for primal column (slack for dual row) is non-negative
|
|
514
|
+
row_lower = -inf;
|
|
515
|
+
row_upper = cost;
|
|
516
|
+
// Treat upper bound as additional constraint
|
|
517
|
+
upper_bound_col_.push_back(iCol);
|
|
518
|
+
} else {
|
|
519
|
+
// Lower (since upper bound is infinite)
|
|
520
|
+
primal_bound = lower;
|
|
521
|
+
// Dual activity a^Ty is bounded above by cost, implying dual
|
|
522
|
+
// for primal column (slack for dual row) is non-negative
|
|
523
|
+
row_lower = -inf;
|
|
524
|
+
row_upper = cost;
|
|
525
|
+
}
|
|
526
|
+
} else if (!highs_isInfinity(upper)) {
|
|
527
|
+
// Upper
|
|
528
|
+
primal_bound = upper;
|
|
529
|
+
// Dual activity a^Ty is bounded below by cost, implying dual
|
|
530
|
+
// for primal column (slack for dual row) is non-positive
|
|
531
|
+
row_lower = cost;
|
|
532
|
+
row_upper = inf;
|
|
533
|
+
} else {
|
|
534
|
+
// FREE
|
|
535
|
+
//
|
|
536
|
+
// Dual activity a^Ty is fixed by cost, implying dual for primal
|
|
537
|
+
// column (slack for dual row) is fixed at zero
|
|
538
|
+
primal_bound = 0;
|
|
539
|
+
row_lower = cost;
|
|
540
|
+
row_upper = cost;
|
|
541
|
+
}
|
|
542
|
+
assert(row_lower < inf);
|
|
543
|
+
assert(row_upper > -inf);
|
|
544
|
+
assert(primal_bound < inf);
|
|
545
|
+
lp_.row_lower_.push_back(row_lower);
|
|
546
|
+
lp_.row_upper_.push_back(row_upper);
|
|
547
|
+
if (primal_bound) {
|
|
548
|
+
primal_bound_value.push_back(primal_bound);
|
|
549
|
+
primal_bound_index.push_back(iCol);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
for (HighsInt iRow = 0; iRow < original_num_row_; iRow++) {
|
|
553
|
+
double lower = original_row_lower_[iRow];
|
|
554
|
+
double upper = original_row_upper_[iRow];
|
|
555
|
+
double col_cost = inf;
|
|
556
|
+
double col_lower = inf;
|
|
557
|
+
double col_upper = -inf;
|
|
558
|
+
if (lower == upper) {
|
|
559
|
+
// Equality constraint
|
|
560
|
+
//
|
|
561
|
+
// Dual variable has primal RHS as cost and is free
|
|
562
|
+
col_cost = lower;
|
|
563
|
+
col_lower = -inf;
|
|
564
|
+
col_upper = inf;
|
|
565
|
+
} else if (!highs_isInfinity(-lower)) {
|
|
566
|
+
// Finite lower bound so boxed or lower
|
|
567
|
+
if (!highs_isInfinity(upper)) {
|
|
568
|
+
// Finite upper bound so boxed
|
|
569
|
+
//
|
|
570
|
+
// Treat as lower
|
|
571
|
+
col_cost = lower;
|
|
572
|
+
col_lower = 0;
|
|
573
|
+
col_upper = inf;
|
|
574
|
+
// Treat upper bound as additional constraint
|
|
575
|
+
upper_bound_row_.push_back(iRow);
|
|
576
|
+
} else {
|
|
577
|
+
// Lower (since upper bound is infinite)
|
|
578
|
+
col_cost = lower;
|
|
579
|
+
col_lower = 0;
|
|
580
|
+
col_upper = inf;
|
|
581
|
+
}
|
|
582
|
+
} else if (!highs_isInfinity(upper)) {
|
|
583
|
+
// Upper
|
|
584
|
+
col_cost = upper;
|
|
585
|
+
col_lower = -inf;
|
|
586
|
+
col_upper = 0;
|
|
587
|
+
} else {
|
|
588
|
+
// FREE
|
|
589
|
+
// Shouldn't get free rows, but handle them anyway
|
|
590
|
+
col_cost = 0;
|
|
591
|
+
col_lower = 0;
|
|
592
|
+
col_upper = 0;
|
|
593
|
+
}
|
|
594
|
+
assert(col_lower < inf);
|
|
595
|
+
assert(col_upper > -inf);
|
|
596
|
+
assert(col_cost < inf);
|
|
597
|
+
lp_.col_cost_.push_back(col_cost);
|
|
598
|
+
lp_.col_lower_.push_back(col_lower);
|
|
599
|
+
lp_.col_upper_.push_back(col_upper);
|
|
600
|
+
}
|
|
601
|
+
vector<HighsInt>& start = lp_.a_matrix_.start_;
|
|
602
|
+
vector<HighsInt>& index = lp_.a_matrix_.index_;
|
|
603
|
+
vector<double>& value = lp_.a_matrix_.value_;
|
|
604
|
+
// Boxed variables and constraints yield extra columns in the dual LP
|
|
605
|
+
HighsSparseMatrix extra_columns;
|
|
606
|
+
extra_columns.ensureColwise();
|
|
607
|
+
extra_columns.num_row_ = original_num_col_;
|
|
608
|
+
HighsInt num_upper_bound_col = upper_bound_col_.size();
|
|
609
|
+
HighsInt num_upper_bound_row = upper_bound_row_.size();
|
|
610
|
+
double one = 1;
|
|
611
|
+
for (HighsInt iX = 0; iX < num_upper_bound_col; iX++) {
|
|
612
|
+
HighsInt iCol = upper_bound_col_[iX];
|
|
613
|
+
const double upper = original_col_upper_[iCol];
|
|
614
|
+
extra_columns.addVec(1, &iCol, &one);
|
|
615
|
+
lp_.col_cost_.push_back(upper);
|
|
616
|
+
lp_.col_lower_.push_back(-inf);
|
|
617
|
+
lp_.col_upper_.push_back(0);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if (num_upper_bound_row) {
|
|
621
|
+
// Need to identify the submatrix of constraint matrix rows
|
|
622
|
+
// corresponding to those with a row index in
|
|
623
|
+
// upper_bound_row_. When identifying numbers of entries in each
|
|
624
|
+
// row of submatrix, use indirection to get corresponding row
|
|
625
|
+
// index, with a dummy row for rows not in the submatrix.
|
|
626
|
+
HighsInt dummy_row = num_upper_bound_row;
|
|
627
|
+
vector<HighsInt> indirection;
|
|
628
|
+
vector<HighsInt> count;
|
|
629
|
+
indirection.assign(original_num_row_, dummy_row);
|
|
630
|
+
count.assign(num_upper_bound_row + 1, 0);
|
|
631
|
+
HighsInt extra_iRow = 0;
|
|
632
|
+
for (HighsInt iX = 0; iX < num_upper_bound_row; iX++) {
|
|
633
|
+
HighsInt iRow = upper_bound_row_[iX];
|
|
634
|
+
indirection[iRow] = extra_iRow++;
|
|
635
|
+
double upper = original_row_upper_[iRow];
|
|
636
|
+
lp_.col_cost_.push_back(upper);
|
|
637
|
+
lp_.col_lower_.push_back(-inf);
|
|
638
|
+
lp_.col_upper_.push_back(0);
|
|
639
|
+
}
|
|
640
|
+
for (HighsInt iEl = 0; iEl < original_num_nz_; iEl++)
|
|
641
|
+
count[indirection[index[iEl]]]++;
|
|
642
|
+
extra_columns.start_.resize(num_upper_bound_col + num_upper_bound_row + 1);
|
|
643
|
+
for (HighsInt iRow = 0; iRow < num_upper_bound_row; iRow++) {
|
|
644
|
+
extra_columns.start_[num_upper_bound_col + iRow + 1] =
|
|
645
|
+
extra_columns.start_[num_upper_bound_col + iRow] + count[iRow];
|
|
646
|
+
count[iRow] = extra_columns.start_[num_upper_bound_col + iRow];
|
|
647
|
+
}
|
|
648
|
+
HighsInt extra_columns_num_nz =
|
|
649
|
+
extra_columns.start_[num_upper_bound_col + num_upper_bound_row];
|
|
650
|
+
extra_columns.index_.resize(extra_columns_num_nz);
|
|
651
|
+
extra_columns.value_.resize(extra_columns_num_nz);
|
|
652
|
+
for (HighsInt iCol = 0; iCol < original_num_col_; iCol++) {
|
|
653
|
+
for (HighsInt iEl = start[iCol]; iEl < start[iCol + 1]; iEl++) {
|
|
654
|
+
HighsInt iRow = indirection[index[iEl]];
|
|
655
|
+
if (iRow < num_upper_bound_row) {
|
|
656
|
+
HighsInt extra_columns_iEl = count[iRow];
|
|
657
|
+
assert(extra_columns_iEl < extra_columns_num_nz);
|
|
658
|
+
extra_columns.index_[extra_columns_iEl] = iCol;
|
|
659
|
+
extra_columns.value_[extra_columns_iEl] = value[iEl];
|
|
660
|
+
count[iRow]++;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
extra_columns.num_col_ += num_upper_bound_row;
|
|
665
|
+
}
|
|
666
|
+
// Incorporate the cost shift by subtracting A*primal_bound from the
|
|
667
|
+
// cost vector; compute the objective offset
|
|
668
|
+
double delta_offset = 0;
|
|
669
|
+
for (size_t iX = 0; iX < primal_bound_index.size(); iX++) {
|
|
670
|
+
HighsInt iCol = primal_bound_index[iX];
|
|
671
|
+
double multiplier = primal_bound_value[iX];
|
|
672
|
+
delta_offset += multiplier * original_col_cost_[iCol];
|
|
673
|
+
for (HighsInt iEl = start[iCol]; iEl < start[iCol + 1]; iEl++)
|
|
674
|
+
lp_.col_cost_[index[iEl]] -= multiplier * value[iEl];
|
|
675
|
+
}
|
|
676
|
+
if (extra_columns.num_col_) {
|
|
677
|
+
// Incorporate the cost shift by subtracting
|
|
678
|
+
// extra_columns*primal_bound from the cost vector for the extra
|
|
679
|
+
// dual variables
|
|
680
|
+
//
|
|
681
|
+
// Have to scatter the packed primal bound values into a
|
|
682
|
+
// full-length vector
|
|
683
|
+
//
|
|
684
|
+
// ToDo Make this more efficient?
|
|
685
|
+
vector<double> primal_bound;
|
|
686
|
+
primal_bound.assign(original_num_col_, 0);
|
|
687
|
+
for (size_t iX = 0; iX < primal_bound_index.size(); iX++)
|
|
688
|
+
primal_bound[primal_bound_index[iX]] = primal_bound_value[iX];
|
|
689
|
+
|
|
690
|
+
for (HighsInt iCol = 0; iCol < extra_columns.num_col_; iCol++) {
|
|
691
|
+
double cost = lp_.col_cost_[original_num_row_ + iCol];
|
|
692
|
+
for (HighsInt iEl = extra_columns.start_[iCol];
|
|
693
|
+
iEl < extra_columns.start_[iCol + 1]; iEl++)
|
|
694
|
+
cost -=
|
|
695
|
+
primal_bound[extra_columns.index_[iEl]] * extra_columns.value_[iEl];
|
|
696
|
+
lp_.col_cost_[original_num_row_ + iCol] = cost;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
lp_.offset_ += delta_offset;
|
|
700
|
+
// Copy the row-wise dual LP constraint matrix and transpose it.
|
|
701
|
+
// ToDo Make this more efficient
|
|
702
|
+
lp_.a_matrix_ = dual_matrix;
|
|
703
|
+
lp_.a_matrix_.ensureColwise();
|
|
704
|
+
// Add the extra columns to the dual LP constraint matrix
|
|
705
|
+
lp_.a_matrix_.addCols(extra_columns);
|
|
706
|
+
|
|
707
|
+
HighsInt dual_num_col =
|
|
708
|
+
original_num_row_ + num_upper_bound_col + num_upper_bound_row;
|
|
709
|
+
HighsInt dual_num_row = original_num_col_;
|
|
710
|
+
assert(dual_num_col == (int)lp_.col_cost_.size());
|
|
711
|
+
assert(lp_.a_matrix_.num_col_ == dual_num_col);
|
|
712
|
+
const bool ignore_scaling = true;
|
|
713
|
+
if (!ignore_scaling) {
|
|
714
|
+
// Flip any scale factors
|
|
715
|
+
if (lp_.scale_.has_scaling) {
|
|
716
|
+
std::vector<double> temp_scale = lp_.scale_.row;
|
|
717
|
+
lp_.scale_.row = lp_.scale_.col;
|
|
718
|
+
lp_.scale_.col = temp_scale;
|
|
719
|
+
lp_.scale_.num_col = dual_num_col;
|
|
720
|
+
lp_.scale_.num_row = dual_num_row;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
// Change optimization sense
|
|
724
|
+
if (lp_.sense_ == ObjSense::kMinimize) {
|
|
725
|
+
lp_.sense_ = ObjSense::kMaximize;
|
|
726
|
+
} else {
|
|
727
|
+
lp_.sense_ = ObjSense::kMinimize;
|
|
728
|
+
}
|
|
729
|
+
// Flip LP dimensions
|
|
730
|
+
lp_.num_col_ = dual_num_col;
|
|
731
|
+
lp_.num_row_ = dual_num_row;
|
|
732
|
+
status_.is_dualized = true;
|
|
733
|
+
status_.has_basis = false;
|
|
734
|
+
status_.has_ar_matrix = false;
|
|
735
|
+
status_.has_nla = false;
|
|
736
|
+
highsLogUser(options_->log_options, HighsLogType::kInfo,
|
|
737
|
+
"Solving dual LP with %d columns", (int)dual_num_col);
|
|
738
|
+
if (num_upper_bound_col + num_upper_bound_row) {
|
|
739
|
+
highsLogUser(options_->log_options, HighsLogType::kInfo, " [%d extra from",
|
|
740
|
+
(int)dual_num_col - original_num_row_);
|
|
741
|
+
if (num_upper_bound_col)
|
|
742
|
+
highsLogUser(options_->log_options, HighsLogType::kInfo,
|
|
743
|
+
" %d boxed variable(s)", (int)num_upper_bound_col);
|
|
744
|
+
if (num_upper_bound_col && num_upper_bound_row)
|
|
745
|
+
highsLogUser(options_->log_options, HighsLogType::kInfo, " and");
|
|
746
|
+
if (num_upper_bound_row)
|
|
747
|
+
highsLogUser(options_->log_options, HighsLogType::kInfo,
|
|
748
|
+
" %d boxed constraint(s)", (int)num_upper_bound_row);
|
|
749
|
+
highsLogUser(options_->log_options, HighsLogType::kInfo, "]");
|
|
750
|
+
}
|
|
751
|
+
highsLogUser(options_->log_options, HighsLogType::kInfo, " and %d rows\n",
|
|
752
|
+
(int)dual_num_row);
|
|
753
|
+
// reportLp(options_->log_options, lp_, HighsLogType::kVerbose);
|
|
754
|
+
return HighsStatus::kOk;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
HighsStatus HEkk::undualize() {
|
|
758
|
+
if (!this->status_.is_dualized) return HighsStatus::kOk;
|
|
759
|
+
HighsInt dual_num_col = lp_.num_col_;
|
|
760
|
+
HighsInt primal_num_tot = original_num_col_ + original_num_row_;
|
|
761
|
+
// These two aren't used (yet)
|
|
762
|
+
// vector<double>& dual_work_dual = info_.workDual_;
|
|
763
|
+
// vector<double>& primal_work_value = info_.workValue_;
|
|
764
|
+
// Take copies of the nonbasic information for the dual LP, since
|
|
765
|
+
// its values will be over-written in constructing the corresponding
|
|
766
|
+
// data for the primal problem
|
|
767
|
+
vector<int8_t> dual_nonbasic_flag = basis_.nonbasicFlag_;
|
|
768
|
+
vector<int8_t> dual_nonbasic_move = basis_.nonbasicMove_;
|
|
769
|
+
vector<HighsInt>& primal_basic_index = basis_.basicIndex_;
|
|
770
|
+
vector<int8_t>& primal_nonbasic_flag = basis_.nonbasicFlag_;
|
|
771
|
+
vector<int8_t>& primal_nonbasic_move = basis_.nonbasicMove_;
|
|
772
|
+
basis_.nonbasicFlag_.assign(primal_num_tot, kIllegalFlagValue);
|
|
773
|
+
basis_.nonbasicMove_.assign(primal_num_tot, kIllegalMoveValue);
|
|
774
|
+
basis_.basicIndex_.resize(0);
|
|
775
|
+
// The number of dual rows is the number of primal columns, so all
|
|
776
|
+
// dual basic variables are nonbasic in the primal problem.
|
|
777
|
+
//
|
|
778
|
+
// If there are extra dual columns due to upper bounds on boxed
|
|
779
|
+
// primal variables/constraints, there will be an excess of dual
|
|
780
|
+
// nonbasic variables for the required primal basic variables.
|
|
781
|
+
//
|
|
782
|
+
// For each pair of dual variables associated with a boxed primal
|
|
783
|
+
// variable/constraint:
|
|
784
|
+
//
|
|
785
|
+
// * If one is basic then it yields a nonbasic primal variable, at
|
|
786
|
+
// a bound given by the basic dual
|
|
787
|
+
//
|
|
788
|
+
// * If both are nonbasic, then they yield a basic primal variable
|
|
789
|
+
//
|
|
790
|
+
// Keep track of the dual column added to handle upper bounds on
|
|
791
|
+
// boxed variables/constraints
|
|
792
|
+
HighsInt upper_bound_col = original_num_row_;
|
|
793
|
+
for (HighsInt iCol = 0; iCol < original_num_col_; iCol++) {
|
|
794
|
+
const double lower = original_col_lower_[iCol];
|
|
795
|
+
const double upper = original_col_upper_[iCol];
|
|
796
|
+
int8_t move = kIllegalMoveValue;
|
|
797
|
+
HighsInt dual_variable = dual_num_col + iCol;
|
|
798
|
+
bool dual_basic = dual_nonbasic_flag[dual_variable] == kNonbasicFlagFalse;
|
|
799
|
+
if (lower == upper) {
|
|
800
|
+
// Fixed
|
|
801
|
+
if (dual_basic) move = kNonbasicMoveZe;
|
|
802
|
+
} else if (!highs_isInfinity(-lower)) {
|
|
803
|
+
// Finite lower bound so boxed or lower
|
|
804
|
+
if (!highs_isInfinity(upper)) {
|
|
805
|
+
// Finite upper bound so boxed
|
|
806
|
+
if (dual_basic) {
|
|
807
|
+
// Primal variable is nonbasic at its lower bound
|
|
808
|
+
move = kNonbasicMoveUp;
|
|
809
|
+
} else {
|
|
810
|
+
// Look at the corresponding dual variable for the upper bound
|
|
811
|
+
dual_variable = upper_bound_col;
|
|
812
|
+
dual_basic = dual_nonbasic_flag[dual_variable] == kNonbasicFlagFalse;
|
|
813
|
+
if (dual_basic) {
|
|
814
|
+
// Primal variable is nonbasic at its upper bound
|
|
815
|
+
move = kNonbasicMoveDn;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
upper_bound_col++;
|
|
819
|
+
} else {
|
|
820
|
+
// Lower (since upper bound is infinite)
|
|
821
|
+
if (dual_basic) move = kNonbasicMoveUp;
|
|
822
|
+
}
|
|
823
|
+
} else if (!highs_isInfinity(upper)) {
|
|
824
|
+
// Upper
|
|
825
|
+
if (dual_basic) move = kNonbasicMoveDn;
|
|
826
|
+
} else {
|
|
827
|
+
// FREE
|
|
828
|
+
//
|
|
829
|
+
// Dual activity a^Ty is fixed by cost, implying dual for primal
|
|
830
|
+
// column (slack for dual row) is fixed at zero
|
|
831
|
+
if (dual_basic) {
|
|
832
|
+
assert(4 == 0);
|
|
833
|
+
move = kNonbasicMoveZe;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
if (dual_basic) {
|
|
837
|
+
// Primal nonbasic column from basic dual row
|
|
838
|
+
assert(move != kIllegalMoveValue);
|
|
839
|
+
primal_nonbasic_flag[iCol] = kNonbasicFlagTrue;
|
|
840
|
+
primal_nonbasic_move[iCol] = move;
|
|
841
|
+
} else {
|
|
842
|
+
// Primal basic column from nonbasic dual row
|
|
843
|
+
primal_basic_index.push_back(iCol);
|
|
844
|
+
primal_nonbasic_flag[iCol] = kNonbasicFlagFalse;
|
|
845
|
+
primal_nonbasic_move[iCol] = 0;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
for (HighsInt iRow = 0; iRow < original_num_row_; iRow++) {
|
|
849
|
+
double lower = original_row_lower_[iRow];
|
|
850
|
+
double upper = original_row_upper_[iRow];
|
|
851
|
+
int8_t move = kIllegalMoveValue;
|
|
852
|
+
HighsInt dual_variable = iRow;
|
|
853
|
+
bool dual_basic = dual_nonbasic_flag[dual_variable] == kNonbasicFlagFalse;
|
|
854
|
+
if (lower == upper) {
|
|
855
|
+
// Equality constraint
|
|
856
|
+
//
|
|
857
|
+
// Dual variable has primal RHS as cost and is free
|
|
858
|
+
if (dual_basic) {
|
|
859
|
+
move = kNonbasicMoveZe;
|
|
860
|
+
}
|
|
861
|
+
} else if (!highs_isInfinity(-lower)) {
|
|
862
|
+
// Finite lower bound so boxed or lower
|
|
863
|
+
if (!highs_isInfinity(upper)) {
|
|
864
|
+
// Finite upper bound so boxed
|
|
865
|
+
if (dual_basic) {
|
|
866
|
+
// Primal variable is nonbasic at its lower bound
|
|
867
|
+
move = kNonbasicMoveDn;
|
|
868
|
+
} else {
|
|
869
|
+
// Look at the corresponding dual variable for the upper bound
|
|
870
|
+
dual_variable = upper_bound_col;
|
|
871
|
+
dual_basic = dual_nonbasic_flag[dual_variable] == kNonbasicFlagFalse;
|
|
872
|
+
if (dual_basic) {
|
|
873
|
+
// Primal variable is nonbasic at its upper bound
|
|
874
|
+
move = kNonbasicMoveUp;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
upper_bound_col++;
|
|
878
|
+
} else {
|
|
879
|
+
// Lower (since upper bound is infinite)
|
|
880
|
+
if (dual_basic) {
|
|
881
|
+
move = kNonbasicMoveDn;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
} else if (!highs_isInfinity(upper)) {
|
|
885
|
+
// Upper
|
|
886
|
+
if (dual_basic) {
|
|
887
|
+
move = kNonbasicMoveUp;
|
|
888
|
+
}
|
|
889
|
+
} else {
|
|
890
|
+
// FREE
|
|
891
|
+
if (dual_basic) {
|
|
892
|
+
assert(14 == 0);
|
|
893
|
+
move = kNonbasicMoveZe;
|
|
894
|
+
}
|
|
895
|
+
// Shouldn't get free rows, but handle them anyway
|
|
896
|
+
}
|
|
897
|
+
if (dual_basic) {
|
|
898
|
+
// Primal nonbasic column from basic dual row
|
|
899
|
+
assert(move != kIllegalMoveValue);
|
|
900
|
+
primal_nonbasic_flag[original_num_col_ + iRow] = kNonbasicFlagTrue;
|
|
901
|
+
primal_nonbasic_move[original_num_col_ + iRow] = move;
|
|
902
|
+
} else {
|
|
903
|
+
// Primal basic column from nonbasic dual row
|
|
904
|
+
primal_basic_index.push_back(original_num_col_ + iRow);
|
|
905
|
+
primal_nonbasic_flag[original_num_col_ + iRow] = kNonbasicFlagFalse;
|
|
906
|
+
primal_nonbasic_move[original_num_col_ + iRow] = 0;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
const bool ignore_scaling = true;
|
|
910
|
+
if (!ignore_scaling) {
|
|
911
|
+
// Flip any scale factors
|
|
912
|
+
if (lp_.scale_.has_scaling) {
|
|
913
|
+
std::vector<double> temp_scale = lp_.scale_.row;
|
|
914
|
+
lp_.scale_.row = lp_.scale_.col;
|
|
915
|
+
lp_.scale_.col = temp_scale;
|
|
916
|
+
lp_.scale_.col.resize(original_num_col_);
|
|
917
|
+
lp_.scale_.row.resize(original_num_row_);
|
|
918
|
+
lp_.scale_.num_col = original_num_col_;
|
|
919
|
+
lp_.scale_.num_row = original_num_row_;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
// Change optimization sense
|
|
923
|
+
if (lp_.sense_ == ObjSense::kMinimize) {
|
|
924
|
+
lp_.sense_ = ObjSense::kMaximize;
|
|
925
|
+
} else {
|
|
926
|
+
lp_.sense_ = ObjSense::kMinimize;
|
|
927
|
+
}
|
|
928
|
+
// Flip LP dimensions
|
|
929
|
+
lp_.num_col_ = original_num_col_;
|
|
930
|
+
lp_.num_row_ = original_num_row_;
|
|
931
|
+
// Restore the original offset
|
|
932
|
+
lp_.offset_ = original_offset_;
|
|
933
|
+
// Copy back the costs and bounds
|
|
934
|
+
lp_.col_cost_ = original_col_cost_;
|
|
935
|
+
lp_.col_lower_ = original_col_lower_;
|
|
936
|
+
lp_.col_upper_ = original_col_upper_;
|
|
937
|
+
lp_.row_lower_ = original_row_lower_;
|
|
938
|
+
lp_.row_upper_ = original_row_upper_;
|
|
939
|
+
// The primal constraint matrix is available row-wise as the first
|
|
940
|
+
// original_num_row_ vectors of the dual constraint matrix
|
|
941
|
+
HighsSparseMatrix primal_matrix;
|
|
942
|
+
primal_matrix.start_.resize(original_num_row_ + 1);
|
|
943
|
+
primal_matrix.index_.resize(original_num_nz_);
|
|
944
|
+
primal_matrix.value_.resize(original_num_nz_);
|
|
945
|
+
|
|
946
|
+
for (HighsInt iCol = 0; iCol < original_num_row_ + 1; iCol++)
|
|
947
|
+
primal_matrix.start_[iCol] = lp_.a_matrix_.start_[iCol];
|
|
948
|
+
for (HighsInt iEl = 0; iEl < original_num_nz_; iEl++) {
|
|
949
|
+
primal_matrix.index_[iEl] = lp_.a_matrix_.index_[iEl];
|
|
950
|
+
primal_matrix.value_[iEl] = lp_.a_matrix_.value_[iEl];
|
|
951
|
+
}
|
|
952
|
+
primal_matrix.num_col_ = original_num_col_;
|
|
953
|
+
primal_matrix.num_row_ = original_num_row_;
|
|
954
|
+
primal_matrix.format_ = MatrixFormat::kRowwise;
|
|
955
|
+
// Copy the row-wise primal LP constraint matrix and transpose it.
|
|
956
|
+
// ToDo Make this more efficient
|
|
957
|
+
lp_.a_matrix_ = primal_matrix;
|
|
958
|
+
lp_.a_matrix_.ensureColwise();
|
|
959
|
+
// Some sanity checks
|
|
960
|
+
assert(lp_.num_col_ == original_num_col_);
|
|
961
|
+
assert(lp_.num_row_ == original_num_row_);
|
|
962
|
+
assert(lp_.a_matrix_.numNz() == original_num_nz_);
|
|
963
|
+
HighsInt num_basic_variables = primal_basic_index.size();
|
|
964
|
+
bool num_basic_variables_ok = num_basic_variables == original_num_row_;
|
|
965
|
+
if (!num_basic_variables_ok)
|
|
966
|
+
printf("HEkk::undualize: Have %d basic variables, not %d\n",
|
|
967
|
+
(int)num_basic_variables, (int)original_num_row_);
|
|
968
|
+
assert(num_basic_variables_ok);
|
|
969
|
+
|
|
970
|
+
// Clear the data retained when solving dual LP
|
|
971
|
+
clearEkkDualize();
|
|
972
|
+
status_.is_dualized = false;
|
|
973
|
+
// Now solve with this basis. Should just be a case of reinverting
|
|
974
|
+
// and re-solving for optimal primal and dual values, but
|
|
975
|
+
// numerically marginal LPs will need clean-up
|
|
976
|
+
status_.has_basis = true;
|
|
977
|
+
status_.has_ar_matrix = false;
|
|
978
|
+
status_.has_nla = false;
|
|
979
|
+
status_.has_invert = false;
|
|
980
|
+
HighsInt primal_solve_iteration_count = -iteration_count_;
|
|
981
|
+
HighsStatus return_status = solve();
|
|
982
|
+
primal_solve_iteration_count += iteration_count_;
|
|
983
|
+
// if (primal_solve_iteration_count)
|
|
984
|
+
highsLogUser(options_->log_options, HighsLogType::kInfo,
|
|
985
|
+
"Solving the primal LP (%s) using the optimal basis of its dual "
|
|
986
|
+
"required %d simplex iterations\n",
|
|
987
|
+
lp_.model_name_.c_str(), (int)primal_solve_iteration_count);
|
|
988
|
+
return return_status;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
HighsStatus HEkk::permute() {
|
|
992
|
+
assert(1 == 0);
|
|
993
|
+
return HighsStatus::kError;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
HighsStatus HEkk::unpermute() {
|
|
997
|
+
if (!this->status_.is_permuted) return HighsStatus::kOk;
|
|
998
|
+
assert(1 == 0);
|
|
999
|
+
return HighsStatus::kError;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
HighsStatus HEkk::solve(const bool force_phase2) {
|
|
1003
|
+
debugInitialise();
|
|
1004
|
+
|
|
1005
|
+
initialiseAnalysis();
|
|
1006
|
+
initialiseControl();
|
|
1007
|
+
|
|
1008
|
+
if (analysis_.analyse_simplex_time)
|
|
1009
|
+
analysis_.simplexTimerStart(SimplexTotalClock);
|
|
1010
|
+
dual_simplex_cleanup_level_ = 0;
|
|
1011
|
+
dual_simplex_phase1_cleanup_level_ = 0;
|
|
1012
|
+
|
|
1013
|
+
previous_iteration_cycling_detected = -kHighsIInf;
|
|
1014
|
+
|
|
1015
|
+
initialiseForSolve();
|
|
1016
|
+
|
|
1017
|
+
const HighsDebugStatus simplex_nla_status =
|
|
1018
|
+
simplex_nla_.debugCheckData("Before HEkk::solve()");
|
|
1019
|
+
const bool simplex_nla_ok = simplex_nla_status == HighsDebugStatus::kOk;
|
|
1020
|
+
if (!simplex_nla_ok) {
|
|
1021
|
+
highsLogUser(options_->log_options, HighsLogType::kError,
|
|
1022
|
+
"Error in simplex NLA data\n");
|
|
1023
|
+
assert(simplex_nla_ok);
|
|
1024
|
+
return returnFromEkkSolve(HighsStatus::kError);
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
const bool report_initial_basis = false;
|
|
1028
|
+
if (report_initial_basis) debugReportInitialBasis();
|
|
1029
|
+
|
|
1030
|
+
assert(status_.has_basis);
|
|
1031
|
+
assert(status_.has_invert);
|
|
1032
|
+
assert(status_.initialised_for_solve);
|
|
1033
|
+
if (model_status_ == HighsModelStatus::kOptimal)
|
|
1034
|
+
return returnFromEkkSolve(HighsStatus::kOk);
|
|
1035
|
+
|
|
1036
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
1037
|
+
HighsStatus call_status;
|
|
1038
|
+
std::string algorithm_name;
|
|
1039
|
+
|
|
1040
|
+
// Indicate that dual and primal rays are not known
|
|
1041
|
+
this->clearRayRecords();
|
|
1042
|
+
|
|
1043
|
+
// Allow primal and dual perturbations in case a block on them is
|
|
1044
|
+
// hanging over from a previous call
|
|
1045
|
+
info_.allow_cost_shifting = true;
|
|
1046
|
+
info_.allow_cost_perturbation = true;
|
|
1047
|
+
info_.allow_bound_perturbation = true;
|
|
1048
|
+
|
|
1049
|
+
chooseSimplexStrategyThreads(*options_, info_);
|
|
1050
|
+
HighsInt& simplex_strategy = info_.simplex_strategy;
|
|
1051
|
+
|
|
1052
|
+
// Initial solve according to strategy
|
|
1053
|
+
if (simplex_strategy == kSimplexStrategyPrimal) {
|
|
1054
|
+
algorithm_name = "primal";
|
|
1055
|
+
reportSimplexPhaseIterations(options_->log_options, iteration_count_, info_,
|
|
1056
|
+
true);
|
|
1057
|
+
highsLogUser(options_->log_options, HighsLogType::kInfo, "Using %s\n",
|
|
1058
|
+
simplexStrategyToString(kSimplexStrategyPrimal).c_str());
|
|
1059
|
+
HEkkPrimal primal_solver(*this);
|
|
1060
|
+
call_status = primal_solver.solve(force_phase2);
|
|
1061
|
+
assert(called_return_from_solve_);
|
|
1062
|
+
return_status = interpretCallStatus(options_->log_options, call_status,
|
|
1063
|
+
return_status, "HEkkPrimal::solve");
|
|
1064
|
+
} else {
|
|
1065
|
+
algorithm_name = "dual";
|
|
1066
|
+
reportSimplexPhaseIterations(options_->log_options, iteration_count_, info_,
|
|
1067
|
+
true);
|
|
1068
|
+
// Solve, depending on the particular strategy
|
|
1069
|
+
if (simplex_strategy == kSimplexStrategyDualTasks) {
|
|
1070
|
+
highsLogUser(options_->log_options, HighsLogType::kInfo,
|
|
1071
|
+
"Using %s with concurrency of %d\n",
|
|
1072
|
+
simplexStrategyToString(kSimplexStrategyDualTasks).c_str(),
|
|
1073
|
+
int(info_.num_concurrency));
|
|
1074
|
+
} else if (simplex_strategy == kSimplexStrategyDualMulti) {
|
|
1075
|
+
highsLogUser(options_->log_options, HighsLogType::kInfo,
|
|
1076
|
+
"Using %s with concurrency of %d\n",
|
|
1077
|
+
simplexStrategyToString(kSimplexStrategyDualMulti).c_str(),
|
|
1078
|
+
int(info_.num_concurrency));
|
|
1079
|
+
} else {
|
|
1080
|
+
highsLogUser(options_->log_options, HighsLogType::kInfo, "Using %s\n",
|
|
1081
|
+
simplexStrategyToString(kSimplexStrategyDual).c_str());
|
|
1082
|
+
}
|
|
1083
|
+
HEkkDual dual_solver(*this);
|
|
1084
|
+
call_status = dual_solver.solve(force_phase2);
|
|
1085
|
+
assert(called_return_from_solve_);
|
|
1086
|
+
return_status = interpretCallStatus(options_->log_options, call_status,
|
|
1087
|
+
return_status, "HEkkDual::solve");
|
|
1088
|
+
|
|
1089
|
+
// Dual simplex solver may set model_status to be
|
|
1090
|
+
// kUnboundedOrInfeasible, and Highs::run() may not allow that to
|
|
1091
|
+
// be returned, so use primal simplex to distinguish
|
|
1092
|
+
if (model_status_ == HighsModelStatus::kUnboundedOrInfeasible &&
|
|
1093
|
+
!options_->allow_unbounded_or_infeasible) {
|
|
1094
|
+
HEkkPrimal primal_solver(*this);
|
|
1095
|
+
call_status = primal_solver.solve();
|
|
1096
|
+
assert(called_return_from_solve_);
|
|
1097
|
+
return_status = interpretCallStatus(options_->log_options, call_status,
|
|
1098
|
+
return_status, "HEkkPrimal::solve");
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
reportSimplexPhaseIterations(options_->log_options, iteration_count_, info_);
|
|
1103
|
+
if (return_status == HighsStatus::kError)
|
|
1104
|
+
return returnFromEkkSolve(return_status);
|
|
1105
|
+
highsLogDev(options_->log_options, HighsLogType::kInfo,
|
|
1106
|
+
"%s simplex solver returns %" HIGHSINT_FORMAT
|
|
1107
|
+
" primal and %" HIGHSINT_FORMAT
|
|
1108
|
+
" dual infeasibilities: "
|
|
1109
|
+
"Status %s\n",
|
|
1110
|
+
algorithm_name.c_str(), info_.num_primal_infeasibilities,
|
|
1111
|
+
info_.num_dual_infeasibilities,
|
|
1112
|
+
utilModelStatusToString(model_status_).c_str());
|
|
1113
|
+
// Can model_status_ = HighsModelStatus::kNotset be returned?
|
|
1114
|
+
assert(model_status_ != HighsModelStatus::kNotset);
|
|
1115
|
+
|
|
1116
|
+
if (analysis_.analyse_simplex_summary_data) analysis_.summaryReport();
|
|
1117
|
+
if (analysis_.analyse_factor_data) analysis_.reportInvertFormData();
|
|
1118
|
+
if (analysis_.analyse_factor_time) analysis_.reportFactorTimer();
|
|
1119
|
+
return returnFromEkkSolve(return_status);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
HighsStatus HEkk::setBasis() {
|
|
1123
|
+
// Set up nonbasicFlag and basicIndex for a logical basis
|
|
1124
|
+
const HighsInt num_col = lp_.num_col_;
|
|
1125
|
+
const HighsInt num_row = lp_.num_row_;
|
|
1126
|
+
|
|
1127
|
+
basis_.setup(num_col, num_row);
|
|
1128
|
+
basis_.debug_origin_name = "HEkk::setBasis - logical";
|
|
1129
|
+
|
|
1130
|
+
for (HighsInt iCol = 0; iCol < num_col; iCol++) {
|
|
1131
|
+
basis_.nonbasicFlag_[iCol] = kNonbasicFlagTrue;
|
|
1132
|
+
double lower = lp_.col_lower_[iCol];
|
|
1133
|
+
double upper = lp_.col_upper_[iCol];
|
|
1134
|
+
int8_t move = kIllegalMoveValue;
|
|
1135
|
+
if (lower == upper) {
|
|
1136
|
+
// Fixed
|
|
1137
|
+
move = kNonbasicMoveZe;
|
|
1138
|
+
} else if (!highs_isInfinity(-lower)) {
|
|
1139
|
+
// Finite lower bound so boxed or lower
|
|
1140
|
+
if (!highs_isInfinity(upper)) {
|
|
1141
|
+
// Finite upper bound so boxed. Set to bound of LP that is closer to
|
|
1142
|
+
// zero
|
|
1143
|
+
if (move == kIllegalMoveValue) {
|
|
1144
|
+
if (fabs(lower) < fabs(upper)) {
|
|
1145
|
+
move = kNonbasicMoveUp;
|
|
1146
|
+
} else {
|
|
1147
|
+
move = kNonbasicMoveDn;
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
} else {
|
|
1151
|
+
// Lower (since upper bound is infinite)
|
|
1152
|
+
move = kNonbasicMoveUp;
|
|
1153
|
+
}
|
|
1154
|
+
} else if (!highs_isInfinity(upper)) {
|
|
1155
|
+
// Upper
|
|
1156
|
+
move = kNonbasicMoveDn;
|
|
1157
|
+
} else {
|
|
1158
|
+
// FREE
|
|
1159
|
+
move = kNonbasicMoveZe;
|
|
1160
|
+
}
|
|
1161
|
+
assert(move != kIllegalMoveValue);
|
|
1162
|
+
basis_.nonbasicMove_[iCol] = move;
|
|
1163
|
+
}
|
|
1164
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
1165
|
+
HighsInt iVar = num_col + iRow;
|
|
1166
|
+
basis_.nonbasicFlag_[iVar] = kNonbasicFlagFalse;
|
|
1167
|
+
HighsHashHelpers::sparse_combine(basis_.hash, iVar);
|
|
1168
|
+
basis_.basicIndex_[iRow] = iVar;
|
|
1169
|
+
}
|
|
1170
|
+
info_.num_basic_logicals = num_row;
|
|
1171
|
+
status_.has_basis = true;
|
|
1172
|
+
return HighsStatus::kOk;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
HighsStatus HEkk::setBasis(const HighsBasis& highs_basis) {
|
|
1176
|
+
// Shouldn't have to check the incoming basis since this is an
|
|
1177
|
+
// internal call, but it may be a basis that's set up internally
|
|
1178
|
+
// with errors :-) ...
|
|
1179
|
+
//
|
|
1180
|
+
if (kDebugMipNodeDualFeasible) {
|
|
1181
|
+
// The basis should be dual feasible unless it was alien
|
|
1182
|
+
debug_dual_feasible = !highs_basis.was_alien;
|
|
1183
|
+
} else {
|
|
1184
|
+
assert(!debug_dual_feasible);
|
|
1185
|
+
}
|
|
1186
|
+
HighsOptions& options = *options_;
|
|
1187
|
+
if (debugHighsBasisConsistent(options, lp_, highs_basis) ==
|
|
1188
|
+
HighsDebugStatus::kLogicalError) {
|
|
1189
|
+
highsLogDev(options_->log_options, HighsLogType::kError,
|
|
1190
|
+
"Supposed to be a Highs basis, but not valid\n");
|
|
1191
|
+
return HighsStatus::kError;
|
|
1192
|
+
}
|
|
1193
|
+
HighsInt num_col = lp_.num_col_;
|
|
1194
|
+
HighsInt num_row = lp_.num_row_;
|
|
1195
|
+
// Set up the basis in case it has not yet been done for this LP
|
|
1196
|
+
basis_.setup(num_col, num_row);
|
|
1197
|
+
basis_.debug_id = highs_basis.debug_id;
|
|
1198
|
+
basis_.debug_update_count = highs_basis.debug_update_count;
|
|
1199
|
+
basis_.debug_origin_name = highs_basis.debug_origin_name;
|
|
1200
|
+
assert(basis_.debug_origin_name != "");
|
|
1201
|
+
HighsInt num_basic_variables = 0;
|
|
1202
|
+
for (HighsInt iCol = 0; iCol < num_col; iCol++) {
|
|
1203
|
+
HighsInt iVar = iCol;
|
|
1204
|
+
const double lower = lp_.col_lower_[iCol];
|
|
1205
|
+
const double upper = lp_.col_upper_[iCol];
|
|
1206
|
+
if (highs_basis.col_status[iCol] == HighsBasisStatus::kBasic) {
|
|
1207
|
+
basis_.nonbasicFlag_[iVar] = kNonbasicFlagFalse;
|
|
1208
|
+
basis_.nonbasicMove_[iVar] = 0;
|
|
1209
|
+
basis_.basicIndex_[num_basic_variables++] = iVar;
|
|
1210
|
+
HighsHashHelpers::sparse_combine(basis_.hash, iVar);
|
|
1211
|
+
} else {
|
|
1212
|
+
basis_.nonbasicFlag_[iVar] = kNonbasicFlagTrue;
|
|
1213
|
+
if (lower == upper) {
|
|
1214
|
+
basis_.nonbasicMove_[iVar] = kNonbasicMoveZe;
|
|
1215
|
+
} else if (highs_basis.col_status[iCol] == HighsBasisStatus::kLower) {
|
|
1216
|
+
basis_.nonbasicMove_[iVar] = kNonbasicMoveUp;
|
|
1217
|
+
} else if (highs_basis.col_status[iCol] == HighsBasisStatus::kUpper) {
|
|
1218
|
+
basis_.nonbasicMove_[iVar] = kNonbasicMoveDn;
|
|
1219
|
+
} else {
|
|
1220
|
+
assert(highs_basis.col_status[iCol] == HighsBasisStatus::kZero);
|
|
1221
|
+
basis_.nonbasicMove_[iVar] = kNonbasicMoveZe;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
1226
|
+
HighsInt iVar = num_col + iRow;
|
|
1227
|
+
const double lower = lp_.row_lower_[iRow];
|
|
1228
|
+
const double upper = lp_.row_upper_[iRow];
|
|
1229
|
+
if (highs_basis.row_status[iRow] == HighsBasisStatus::kBasic) {
|
|
1230
|
+
basis_.nonbasicFlag_[iVar] = kNonbasicFlagFalse;
|
|
1231
|
+
basis_.nonbasicMove_[iVar] = 0;
|
|
1232
|
+
basis_.basicIndex_[num_basic_variables++] = iVar;
|
|
1233
|
+
HighsHashHelpers::sparse_combine(basis_.hash, iVar);
|
|
1234
|
+
} else {
|
|
1235
|
+
basis_.nonbasicFlag_[iVar] = kNonbasicFlagTrue;
|
|
1236
|
+
if (lower == upper) {
|
|
1237
|
+
basis_.nonbasicMove_[iVar] = kNonbasicMoveZe;
|
|
1238
|
+
} else if (highs_basis.row_status[iRow] == HighsBasisStatus::kLower) {
|
|
1239
|
+
basis_.nonbasicMove_[iVar] = kNonbasicMoveDn;
|
|
1240
|
+
} else if (highs_basis.row_status[iRow] == HighsBasisStatus::kUpper) {
|
|
1241
|
+
basis_.nonbasicMove_[iVar] = kNonbasicMoveUp;
|
|
1242
|
+
} else {
|
|
1243
|
+
assert(highs_basis.row_status[iRow] == HighsBasisStatus::kZero);
|
|
1244
|
+
basis_.nonbasicMove_[iVar] = kNonbasicMoveZe;
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
status_.has_basis = true;
|
|
1249
|
+
return HighsStatus::kOk;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
void HEkk::addCols(const HighsLp& lp,
|
|
1253
|
+
const HighsSparseMatrix& scaled_a_matrix) {
|
|
1254
|
+
// Should be extendSimplexLpRandomVectors
|
|
1255
|
+
// if (valid_simplex_basis)
|
|
1256
|
+
// appendBasicRowsToBasis(simplex_lp, simplex_basis, XnumNewRow);
|
|
1257
|
+
// ekk_instance_.updateStatus(LpAction::kNewRows);
|
|
1258
|
+
// if (valid_simplex_lp) {
|
|
1259
|
+
// simplex_lp.num_row_ += XnumNewRow;
|
|
1260
|
+
// ekk_instance_.initialiseSimplexLpRandomVectors();
|
|
1261
|
+
// }
|
|
1262
|
+
// if (valid_simplex_lp)
|
|
1263
|
+
// assert(ekk_instance_.lp_.dimensionsOk("addCols - simplex"));
|
|
1264
|
+
if (this->status_.has_nla) this->simplex_nla_.addCols(&lp);
|
|
1265
|
+
this->updateStatus(LpAction::kNewCols);
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
void HEkk::addRows(const HighsLp& lp,
|
|
1269
|
+
const HighsSparseMatrix& scaled_ar_matrix) {
|
|
1270
|
+
// Should be extendSimplexLpRandomVectors
|
|
1271
|
+
// if (valid_simplex_basis)
|
|
1272
|
+
// appendBasicRowsToBasis(simplex_lp, simplex_basis, XnumNewRow);
|
|
1273
|
+
// ekk_instance_.updateStatus(LpAction::kNewRows);
|
|
1274
|
+
// if (valid_simplex_lp) {
|
|
1275
|
+
// simplex_lp.num_row_ += XnumNewRow;
|
|
1276
|
+
// ekk_instance_.initialiseSimplexLpRandomVectors();
|
|
1277
|
+
// }
|
|
1278
|
+
// if (valid_simplex_lp)
|
|
1279
|
+
// assert(ekk_instance_.lp_.dimensionsOk("addRows - simplex"));
|
|
1280
|
+
if (kExtendInvertWhenAddingRows && this->status_.has_nla) {
|
|
1281
|
+
this->simplex_nla_.addRows(&lp, basis_.basicIndex_.data(),
|
|
1282
|
+
&scaled_ar_matrix);
|
|
1283
|
+
setNlaPointersForTrans(lp);
|
|
1284
|
+
this->debugNlaCheckInvert("HEkk::addRows - on entry",
|
|
1285
|
+
kHighsDebugLevelExpensive + 1);
|
|
1286
|
+
}
|
|
1287
|
+
// Update the number of rows in the simplex LP so that it's
|
|
1288
|
+
// consistent with simplex basis information
|
|
1289
|
+
this->lp_.num_row_ = lp.num_row_;
|
|
1290
|
+
this->updateStatus(LpAction::kNewRows);
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
void HEkk::deleteCols(const HighsIndexCollection& index_collection) {
|
|
1294
|
+
this->updateStatus(LpAction::kDelCols);
|
|
1295
|
+
}
|
|
1296
|
+
void HEkk::deleteRows(const HighsIndexCollection& index_collection) {
|
|
1297
|
+
this->updateStatus(LpAction::kDelRows);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
void HEkk::unscaleSimplex(const HighsLp& incumbent_lp) {
|
|
1301
|
+
if (!this->simplex_in_scaled_space_) return;
|
|
1302
|
+
assert(incumbent_lp.scale_.has_scaling);
|
|
1303
|
+
const HighsInt num_col = incumbent_lp.num_col_;
|
|
1304
|
+
const HighsInt num_row = incumbent_lp.num_row_;
|
|
1305
|
+
const vector<double>& col_scale = incumbent_lp.scale_.col;
|
|
1306
|
+
const vector<double>& row_scale = incumbent_lp.scale_.row;
|
|
1307
|
+
for (HighsInt iCol = 0; iCol < num_col; iCol++) {
|
|
1308
|
+
const HighsInt iVar = iCol;
|
|
1309
|
+
const double factor = col_scale[iCol];
|
|
1310
|
+
this->info_.workCost_[iVar] /= factor;
|
|
1311
|
+
this->info_.workDual_[iVar] /= factor;
|
|
1312
|
+
this->info_.workShift_[iVar] /= factor;
|
|
1313
|
+
this->info_.workLower_[iVar] *= factor;
|
|
1314
|
+
this->info_.workUpper_[iVar] *= factor;
|
|
1315
|
+
this->info_.workRange_[iVar] *= factor;
|
|
1316
|
+
this->info_.workValue_[iVar] *= factor;
|
|
1317
|
+
this->info_.workLowerShift_[iVar] *= factor;
|
|
1318
|
+
this->info_.workUpperShift_[iVar] *= factor;
|
|
1319
|
+
}
|
|
1320
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
1321
|
+
const HighsInt iVar = num_col + iRow;
|
|
1322
|
+
const double factor = row_scale[iRow];
|
|
1323
|
+
this->info_.workCost_[iVar] *= factor;
|
|
1324
|
+
this->info_.workDual_[iVar] *= factor;
|
|
1325
|
+
this->info_.workShift_[iVar] *= factor;
|
|
1326
|
+
this->info_.workLower_[iVar] /= factor;
|
|
1327
|
+
this->info_.workUpper_[iVar] /= factor;
|
|
1328
|
+
this->info_.workRange_[iVar] /= factor;
|
|
1329
|
+
this->info_.workValue_[iVar] /= factor;
|
|
1330
|
+
this->info_.workLowerShift_[iVar] /= factor;
|
|
1331
|
+
this->info_.workUpperShift_[iVar] /= factor;
|
|
1332
|
+
}
|
|
1333
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
1334
|
+
double factor;
|
|
1335
|
+
const HighsInt iVar = this->basis_.basicIndex_[iRow];
|
|
1336
|
+
if (iVar < num_col) {
|
|
1337
|
+
factor = col_scale[iVar];
|
|
1338
|
+
} else {
|
|
1339
|
+
factor = 1.0 / row_scale[iVar - num_col];
|
|
1340
|
+
}
|
|
1341
|
+
this->info_.baseLower_[iRow] *= factor;
|
|
1342
|
+
this->info_.baseUpper_[iRow] *= factor;
|
|
1343
|
+
this->info_.baseValue_[iRow] *= factor;
|
|
1344
|
+
}
|
|
1345
|
+
this->simplex_in_scaled_space_ = false;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
HighsSolution HEkk::getSolution() {
|
|
1349
|
+
HighsSolution solution;
|
|
1350
|
+
// Scatter the basic primal values
|
|
1351
|
+
for (HighsInt iRow = 0; iRow < lp_.num_row_; iRow++)
|
|
1352
|
+
info_.workValue_[basis_.basicIndex_[iRow]] = info_.baseValue_[iRow];
|
|
1353
|
+
// Zero the basic dual values
|
|
1354
|
+
for (HighsInt iRow = 0; iRow < lp_.num_row_; iRow++)
|
|
1355
|
+
info_.workDual_[basis_.basicIndex_[iRow]] = 0;
|
|
1356
|
+
|
|
1357
|
+
// Now we can get the solution
|
|
1358
|
+
solution.col_value.resize(lp_.num_col_);
|
|
1359
|
+
solution.col_dual.resize(lp_.num_col_);
|
|
1360
|
+
solution.row_value.resize(lp_.num_row_);
|
|
1361
|
+
solution.row_dual.resize(lp_.num_row_);
|
|
1362
|
+
|
|
1363
|
+
for (HighsInt iCol = 0; iCol < lp_.num_col_; iCol++) {
|
|
1364
|
+
solution.col_value[iCol] = info_.workValue_[iCol];
|
|
1365
|
+
solution.col_dual[iCol] = (HighsInt)lp_.sense_ * info_.workDual_[iCol];
|
|
1366
|
+
}
|
|
1367
|
+
for (HighsInt iRow = 0; iRow < lp_.num_row_; iRow++) {
|
|
1368
|
+
solution.row_value[iRow] = -info_.workValue_[lp_.num_col_ + iRow];
|
|
1369
|
+
// @FlipRowDual negate RHS
|
|
1370
|
+
solution.row_dual[iRow] =
|
|
1371
|
+
-(HighsInt)lp_.sense_ * info_.workDual_[lp_.num_col_ + iRow];
|
|
1372
|
+
}
|
|
1373
|
+
solution.value_valid = true;
|
|
1374
|
+
solution.dual_valid = true;
|
|
1375
|
+
return solution;
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
HighsBasis HEkk::getHighsBasis(HighsLp& use_lp) const {
|
|
1379
|
+
HighsInt num_col = use_lp.num_col_;
|
|
1380
|
+
HighsInt num_row = use_lp.num_row_;
|
|
1381
|
+
HighsBasis highs_basis;
|
|
1382
|
+
highs_basis.col_status.resize(num_col);
|
|
1383
|
+
highs_basis.row_status.resize(num_row);
|
|
1384
|
+
assert(status_.has_basis);
|
|
1385
|
+
highs_basis.valid = false;
|
|
1386
|
+
for (HighsInt iCol = 0; iCol < num_col; iCol++) {
|
|
1387
|
+
HighsInt iVar = iCol;
|
|
1388
|
+
const double lower = use_lp.col_lower_[iCol];
|
|
1389
|
+
const double upper = use_lp.col_upper_[iCol];
|
|
1390
|
+
HighsBasisStatus basis_status = HighsBasisStatus::kNonbasic;
|
|
1391
|
+
if (!basis_.nonbasicFlag_[iVar]) {
|
|
1392
|
+
basis_status = HighsBasisStatus::kBasic;
|
|
1393
|
+
} else if (basis_.nonbasicMove_[iVar] == kNonbasicMoveUp) {
|
|
1394
|
+
basis_status = HighsBasisStatus::kLower;
|
|
1395
|
+
} else if (basis_.nonbasicMove_[iVar] == kNonbasicMoveDn) {
|
|
1396
|
+
basis_status = HighsBasisStatus::kUpper;
|
|
1397
|
+
} else if (basis_.nonbasicMove_[iVar] == kNonbasicMoveZe) {
|
|
1398
|
+
if (lower == upper) {
|
|
1399
|
+
const double dual = (HighsInt)lp_.sense_ * info_.workDual_[iCol];
|
|
1400
|
+
basis_status =
|
|
1401
|
+
dual >= 0 ? HighsBasisStatus::kLower : HighsBasisStatus::kUpper;
|
|
1402
|
+
} else {
|
|
1403
|
+
basis_status = HighsBasisStatus::kZero;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
highs_basis.col_status[iCol] = basis_status;
|
|
1407
|
+
}
|
|
1408
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
1409
|
+
HighsInt iVar = num_col + iRow;
|
|
1410
|
+
const double lower = use_lp.row_lower_[iRow];
|
|
1411
|
+
const double upper = use_lp.row_upper_[iRow];
|
|
1412
|
+
HighsBasisStatus basis_status = HighsBasisStatus::kNonbasic;
|
|
1413
|
+
if (!basis_.nonbasicFlag_[iVar]) {
|
|
1414
|
+
basis_status = HighsBasisStatus::kBasic;
|
|
1415
|
+
} else if (basis_.nonbasicMove_[iVar] == kNonbasicMoveUp) {
|
|
1416
|
+
basis_status = HighsBasisStatus::kUpper;
|
|
1417
|
+
} else if (basis_.nonbasicMove_[iVar] == kNonbasicMoveDn) {
|
|
1418
|
+
basis_status = HighsBasisStatus::kLower;
|
|
1419
|
+
} else if (basis_.nonbasicMove_[iVar] == kNonbasicMoveZe) {
|
|
1420
|
+
if (lower == upper) {
|
|
1421
|
+
const double dual = (HighsInt)lp_.sense_ * info_.workDual_[iVar];
|
|
1422
|
+
basis_status =
|
|
1423
|
+
dual >= 0 ? HighsBasisStatus::kLower : HighsBasisStatus::kUpper;
|
|
1424
|
+
} else {
|
|
1425
|
+
basis_status = HighsBasisStatus::kZero;
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
highs_basis.row_status[iRow] = basis_status;
|
|
1429
|
+
}
|
|
1430
|
+
highs_basis.valid = true;
|
|
1431
|
+
highs_basis.alien = false;
|
|
1432
|
+
highs_basis.useful = true;
|
|
1433
|
+
highs_basis.was_alien = false;
|
|
1434
|
+
highs_basis.debug_id =
|
|
1435
|
+
(HighsInt)(build_synthetic_tick_ + total_synthetic_tick_);
|
|
1436
|
+
highs_basis.debug_update_count = info_.update_count;
|
|
1437
|
+
highs_basis.debug_origin_name = basis_.debug_origin_name;
|
|
1438
|
+
return highs_basis;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
HighsStatus HEkk::initialiseSimplexLpBasisAndFactor(
|
|
1442
|
+
const bool only_from_known_basis) {
|
|
1443
|
+
// This is normally called only from HEkk::initialiseForSolve, with
|
|
1444
|
+
// only_from_known_basis = false.
|
|
1445
|
+
//
|
|
1446
|
+
// In this case, if there is no existing simplex basis then a
|
|
1447
|
+
// logical basis is set up. Otherwise the existing simplex basis is
|
|
1448
|
+
// factorized, with logicals introduced to handle rank deficiency.
|
|
1449
|
+
//
|
|
1450
|
+
// It is also called from HighsSolution's
|
|
1451
|
+
// formSimplexLpBasisAndFactor, with only_from_known_basis = true or
|
|
1452
|
+
// false. In both cases a simplex basis is known.
|
|
1453
|
+
//
|
|
1454
|
+
// Calls with only_from_known_basis = true originate from
|
|
1455
|
+
// Highs::getBasicVariablesInterface, and are made when
|
|
1456
|
+
// Highs::getBasicVariables has been called and there is no
|
|
1457
|
+
// factorization of the current basis matrix. No rank deficiency
|
|
1458
|
+
// handling is permitted so, if it occurs, an error must be
|
|
1459
|
+
// returned.
|
|
1460
|
+
//
|
|
1461
|
+
// Calls with only_from_known_basis = false originate from
|
|
1462
|
+
// Highs::setBasis. The simplex basis should be non-singular since
|
|
1463
|
+
// it's come from a HighsBasis that is either non-alien, or from an
|
|
1464
|
+
// alien HighsBasis that's been checked/completed. However, it's
|
|
1465
|
+
// conceivable that a singularity could occur, and it's fine to
|
|
1466
|
+
// accommodate it.
|
|
1467
|
+
//
|
|
1468
|
+
// If only_from_known_basis is true, then there should be a simplex
|
|
1469
|
+
// basis to use
|
|
1470
|
+
if (only_from_known_basis) assert(status_.has_basis);
|
|
1471
|
+
// If there is no simplex basis, set up a logical basis
|
|
1472
|
+
if (!status_.has_basis) setBasis();
|
|
1473
|
+
// The simplex NLA operates in the scaled space if the LP has
|
|
1474
|
+
// scaling factors. If they exist but haven't been applied, then the
|
|
1475
|
+
// simplex NLA needs a separate, scaled constraint matrix. Thus
|
|
1476
|
+
// getScaledAMatrixPointer() returns a pointer to either the
|
|
1477
|
+
// constraint matrix or a scaled copy (that is a member of the HEkk
|
|
1478
|
+
// class), with the latter returned if the LP has scaling factors
|
|
1479
|
+
// but is unscaled.
|
|
1480
|
+
//
|
|
1481
|
+
HighsSparseMatrix* local_scaled_a_matrix = getScaledAMatrixPointer();
|
|
1482
|
+
//
|
|
1483
|
+
// If simplex NLA is set up, pass the pointers that it uses. It
|
|
1484
|
+
// deduces any scaling factors that it must use by inspecting
|
|
1485
|
+
// whether the LP has scaling factors, and whether it is scaled.
|
|
1486
|
+
//
|
|
1487
|
+
// If simplex NLA is not set up, then it will be done if
|
|
1488
|
+
//
|
|
1489
|
+
if (this->status_.has_nla) {
|
|
1490
|
+
assert(lpFactorRowCompatible());
|
|
1491
|
+
this->simplex_nla_.setPointers(
|
|
1492
|
+
&(this->lp_), local_scaled_a_matrix, this->basis_.basicIndex_.data(),
|
|
1493
|
+
this->options_, this->timer_, &(this->analysis_));
|
|
1494
|
+
} else {
|
|
1495
|
+
// todo @ Julian: this fails on glass4
|
|
1496
|
+
assert(info_.factor_pivot_threshold >= options_->factor_pivot_threshold);
|
|
1497
|
+
simplex_nla_.setup(
|
|
1498
|
+
&(this->lp_), //&lp_,
|
|
1499
|
+
this->basis_.basicIndex_.data(), // basis_.basicIndex_.data(),
|
|
1500
|
+
this->options_, // options_,
|
|
1501
|
+
this->timer_, // timer_,
|
|
1502
|
+
&(this->analysis_), //&analysis_,
|
|
1503
|
+
local_scaled_a_matrix, this->info_.factor_pivot_threshold);
|
|
1504
|
+
status_.has_nla = true;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
if (!status_.has_invert) {
|
|
1508
|
+
const HighsInt rank_deficiency = computeFactor();
|
|
1509
|
+
if (rank_deficiency) {
|
|
1510
|
+
// Basis is rank deficient
|
|
1511
|
+
highsLogDev(
|
|
1512
|
+
options_->log_options, HighsLogType::kInfo,
|
|
1513
|
+
"HEkk::initialiseSimplexLpBasisAndFactor (%s) Rank_deficiency %d: Id "
|
|
1514
|
+
"= "
|
|
1515
|
+
"%d; UpdateCount = %d\n",
|
|
1516
|
+
basis_.debug_origin_name.c_str(), (int)rank_deficiency,
|
|
1517
|
+
(int)basis_.debug_id, (int)basis_.debug_update_count);
|
|
1518
|
+
if (only_from_known_basis) {
|
|
1519
|
+
// If only this basis should be used, then return error
|
|
1520
|
+
highsLogDev(options_->log_options, HighsLogType::kError,
|
|
1521
|
+
"Supposed to be a full-rank basis, but incorrect\n");
|
|
1522
|
+
return HighsStatus::kError;
|
|
1523
|
+
}
|
|
1524
|
+
// Account for rank deficiency by correcting nonbasicFlag
|
|
1525
|
+
handleRankDeficiency();
|
|
1526
|
+
this->updateStatus(LpAction::kNewBasis);
|
|
1527
|
+
setNonbasicMove();
|
|
1528
|
+
status_.has_basis = true;
|
|
1529
|
+
status_.has_invert = true;
|
|
1530
|
+
status_.has_fresh_invert = true;
|
|
1531
|
+
}
|
|
1532
|
+
// Record the synthetic clock for INVERT, and zero it for UPDATE
|
|
1533
|
+
resetSyntheticClock();
|
|
1534
|
+
}
|
|
1535
|
+
assert(status_.has_invert);
|
|
1536
|
+
return HighsStatus::kOk;
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
void HEkk::handleRankDeficiency() {
|
|
1540
|
+
HFactor& factor = simplex_nla_.factor_;
|
|
1541
|
+
HighsInt rank_deficiency = factor.rank_deficiency;
|
|
1542
|
+
vector<HighsInt>& row_with_no_pivot = factor.row_with_no_pivot;
|
|
1543
|
+
vector<HighsInt>& var_with_no_pivot = factor.var_with_no_pivot;
|
|
1544
|
+
for (HighsInt k = 0; k < rank_deficiency; k++) {
|
|
1545
|
+
HighsInt row_in = row_with_no_pivot[k];
|
|
1546
|
+
HighsInt variable_in = lp_.num_col_ + row_in;
|
|
1547
|
+
HighsInt variable_out = var_with_no_pivot[k];
|
|
1548
|
+
basis_.nonbasicFlag_[variable_in] = kNonbasicFlagFalse;
|
|
1549
|
+
basis_.nonbasicFlag_[variable_out] = kNonbasicFlagTrue;
|
|
1550
|
+
HighsInt row_out = row_with_no_pivot[k];
|
|
1551
|
+
assert(basis_.basicIndex_[row_out] == variable_in);
|
|
1552
|
+
highsLogDev(
|
|
1553
|
+
options_->log_options, HighsLogType::kInfo,
|
|
1554
|
+
"HEkk::handleRankDeficiency: %4d: Basic row of leaving variable (%4d "
|
|
1555
|
+
"is %s %4d) is "
|
|
1556
|
+
"%4d; Entering logical = %4d is variable %d)\n",
|
|
1557
|
+
(int)k, (int)variable_out,
|
|
1558
|
+
variable_out < lp_.num_col_ ? " column" : "logical",
|
|
1559
|
+
variable_out < lp_.num_col_ ? (int)variable_out
|
|
1560
|
+
: (int)(variable_out - lp_.num_col_),
|
|
1561
|
+
(int)row_out, (int)(row_in), (int)variable_in);
|
|
1562
|
+
// NB Parameters row_out, variable_in, variable_out, since
|
|
1563
|
+
// variable_in is the logical that must not come out to be
|
|
1564
|
+
// replaced by the structural variable_out
|
|
1565
|
+
addBadBasisChange(row_out, variable_in, variable_out,
|
|
1566
|
+
BadBasisChangeReason::kSingular, true);
|
|
1567
|
+
}
|
|
1568
|
+
status_.has_ar_matrix = false;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
// Private methods
|
|
1572
|
+
|
|
1573
|
+
void HEkk::initialiseEkk() {
|
|
1574
|
+
if (status_.initialised_for_new_lp) return;
|
|
1575
|
+
setSimplexOptions();
|
|
1576
|
+
initialiseControl();
|
|
1577
|
+
initialiseSimplexLpRandomVectors();
|
|
1578
|
+
simplex_nla_.clear();
|
|
1579
|
+
clearBadBasisChange();
|
|
1580
|
+
status_.initialised_for_new_lp = true;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
bool HEkk::isUnconstrainedLp() const {
|
|
1584
|
+
bool is_unconstrained_lp = lp_.num_row_ <= 0;
|
|
1585
|
+
if (is_unconstrained_lp)
|
|
1586
|
+
highsLogDev(
|
|
1587
|
+
options_->log_options, HighsLogType::kError,
|
|
1588
|
+
"HEkkDual::solve called for LP with non-positive (%" HIGHSINT_FORMAT
|
|
1589
|
+
") number of constraints\n",
|
|
1590
|
+
lp_.num_row_);
|
|
1591
|
+
assert(!is_unconstrained_lp);
|
|
1592
|
+
return is_unconstrained_lp;
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
void HEkk::initialiseForSolve() {
|
|
1596
|
+
const HighsStatus return_status = initialiseSimplexLpBasisAndFactor();
|
|
1597
|
+
assert(return_status == HighsStatus::kOk);
|
|
1598
|
+
assert(status_.has_basis);
|
|
1599
|
+
|
|
1600
|
+
updateSimplexOptions();
|
|
1601
|
+
initialiseSimplexLpRandomVectors();
|
|
1602
|
+
initialisePartitionedRowwiseMatrix(); // Timed
|
|
1603
|
+
allocateWorkAndBaseArrays();
|
|
1604
|
+
initialiseCost(SimplexAlgorithm::kPrimal, kSolvePhaseUnknown, false);
|
|
1605
|
+
initialiseBound(SimplexAlgorithm::kPrimal, kSolvePhaseUnknown, false);
|
|
1606
|
+
initialiseNonbasicValueAndMove();
|
|
1607
|
+
computePrimal(); // Timed
|
|
1608
|
+
computeDual(); // Timed
|
|
1609
|
+
computeSimplexInfeasible(); // Timed
|
|
1610
|
+
computeDualObjectiveValue(); // Timed
|
|
1611
|
+
computePrimalObjectiveValue(); // Timed
|
|
1612
|
+
status_.initialised_for_solve = true;
|
|
1613
|
+
|
|
1614
|
+
bool primal_feasible = info_.num_primal_infeasibilities == 0;
|
|
1615
|
+
bool dual_feasible = info_.num_dual_infeasibilities == 0;
|
|
1616
|
+
visited_basis_.clear();
|
|
1617
|
+
visited_basis_.insert(basis_.hash);
|
|
1618
|
+
model_status_ = HighsModelStatus::kNotset;
|
|
1619
|
+
if (primal_feasible && dual_feasible)
|
|
1620
|
+
model_status_ = HighsModelStatus::kOptimal;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
void HEkk::setSimplexOptions() {
|
|
1624
|
+
// Copy values of HighsOptions for the simplex solver
|
|
1625
|
+
// Currently most of these options are straight copies, but they
|
|
1626
|
+
// will become valuable when "choose" becomes a HiGHS strategy value
|
|
1627
|
+
// that will need converting into a specific simplex strategy value.
|
|
1628
|
+
//
|
|
1629
|
+
// NB simplex_strategy is set by chooseSimplexStrategyThreads in each call
|
|
1630
|
+
//
|
|
1631
|
+
info_.dual_edge_weight_strategy = options_->simplex_dual_edge_weight_strategy;
|
|
1632
|
+
info_.price_strategy = options_->simplex_price_strategy;
|
|
1633
|
+
info_.dual_simplex_cost_perturbation_multiplier =
|
|
1634
|
+
options_->dual_simplex_cost_perturbation_multiplier;
|
|
1635
|
+
info_.primal_simplex_bound_perturbation_multiplier =
|
|
1636
|
+
options_->primal_simplex_bound_perturbation_multiplier;
|
|
1637
|
+
info_.factor_pivot_threshold = options_->factor_pivot_threshold;
|
|
1638
|
+
info_.update_limit = options_->simplex_update_limit;
|
|
1639
|
+
random_.initialise(options_->random_seed);
|
|
1640
|
+
|
|
1641
|
+
// Set values of internal options
|
|
1642
|
+
info_.store_squared_primal_infeasibility = true;
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
void HEkk::updateSimplexOptions() {
|
|
1646
|
+
// Update some simplex option values from HighsOptions when
|
|
1647
|
+
// (re-)solving an LP. Others aren't changed because better values
|
|
1648
|
+
// may have been learned due to solving this LP (possibly with some
|
|
1649
|
+
// modification) before.
|
|
1650
|
+
//
|
|
1651
|
+
// NB simplex_strategy is set by chooseSimplexStrategyThreads in each call
|
|
1652
|
+
//
|
|
1653
|
+
info_.dual_simplex_cost_perturbation_multiplier =
|
|
1654
|
+
options_->dual_simplex_cost_perturbation_multiplier;
|
|
1655
|
+
info_.primal_simplex_bound_perturbation_multiplier =
|
|
1656
|
+
options_->primal_simplex_bound_perturbation_multiplier;
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
void HEkk::initialiseSimplexLpRandomVectors() {
|
|
1660
|
+
const HighsInt num_col = lp_.num_col_;
|
|
1661
|
+
const HighsInt num_tot = lp_.num_col_ + lp_.num_row_;
|
|
1662
|
+
if (!num_tot) return;
|
|
1663
|
+
// Instantiate and (re-)initialise the random number generator
|
|
1664
|
+
// HighsRandom random;
|
|
1665
|
+
HighsRandom& random = random_;
|
|
1666
|
+
// random.initialise();
|
|
1667
|
+
|
|
1668
|
+
if (num_col) {
|
|
1669
|
+
// Generate a random permutation of the column indices
|
|
1670
|
+
vector<HighsInt>& numColPermutation = info_.numColPermutation_;
|
|
1671
|
+
numColPermutation.resize(num_col);
|
|
1672
|
+
for (HighsInt i = 0; i < num_col; i++) numColPermutation[i] = i;
|
|
1673
|
+
random.shuffle(numColPermutation.data(), num_col);
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
// Re-initialise the random number generator and generate the
|
|
1677
|
+
// random vectors in the same order as hsol to maintain repeatable
|
|
1678
|
+
// performance
|
|
1679
|
+
// random.initialise();
|
|
1680
|
+
|
|
1681
|
+
// Generate a random permutation of all the indices
|
|
1682
|
+
vector<HighsInt>& numTotPermutation = info_.numTotPermutation_;
|
|
1683
|
+
numTotPermutation.resize(num_tot);
|
|
1684
|
+
for (HighsInt i = 0; i < num_tot; i++) numTotPermutation[i] = i;
|
|
1685
|
+
random.shuffle(numTotPermutation.data(), num_tot);
|
|
1686
|
+
|
|
1687
|
+
// Generate a vector of random reals
|
|
1688
|
+
info_.numTotRandomValue_.resize(num_tot);
|
|
1689
|
+
vector<double>& numTotRandomValue = info_.numTotRandomValue_;
|
|
1690
|
+
for (HighsInt i = 0; i < num_tot; i++) {
|
|
1691
|
+
numTotRandomValue[i] = random.fraction();
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
void HEkk::chooseSimplexStrategyThreads(const HighsOptions& options,
|
|
1696
|
+
HighsSimplexInfo& info) {
|
|
1697
|
+
// Ensure that this is not called with an optimal basis
|
|
1698
|
+
assert(info.num_dual_infeasibilities > 0 ||
|
|
1699
|
+
info.num_primal_infeasibilities > 0);
|
|
1700
|
+
// Set the internal simplex strategy and number of threads for dual
|
|
1701
|
+
// simplex
|
|
1702
|
+
HighsInt& simplex_strategy = info.simplex_strategy;
|
|
1703
|
+
// By default, use the HighsOptions strategy. If this is
|
|
1704
|
+
// kSimplexStrategyChoose, then the strategy used will depend on
|
|
1705
|
+
// whether the current basis is primal feasible.
|
|
1706
|
+
simplex_strategy = options.simplex_strategy;
|
|
1707
|
+
if (simplex_strategy == kSimplexStrategyChoose) {
|
|
1708
|
+
// HiGHS is left to choose the simplex strategy
|
|
1709
|
+
if (info.num_primal_infeasibilities > 0) {
|
|
1710
|
+
// Not primal feasible, so use dual simplex
|
|
1711
|
+
simplex_strategy = kSimplexStrategyDual;
|
|
1712
|
+
} else {
|
|
1713
|
+
// Primal feasible. so use primal simplex
|
|
1714
|
+
simplex_strategy = kSimplexStrategyPrimal;
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
// Set min/max_threads to correspond to serial code. They will be
|
|
1718
|
+
// set to other values if parallel options are used.
|
|
1719
|
+
info.min_concurrency = 1;
|
|
1720
|
+
info.max_concurrency = 1;
|
|
1721
|
+
// Record the min/max minimum concurrency in the options
|
|
1722
|
+
const HighsInt simplex_min_concurrency = options.simplex_min_concurrency;
|
|
1723
|
+
const HighsInt simplex_max_concurrency = options.simplex_max_concurrency;
|
|
1724
|
+
HighsInt max_threads = highs::parallel::num_threads();
|
|
1725
|
+
|
|
1726
|
+
if (options.parallel == kHighsOnString &&
|
|
1727
|
+
simplex_strategy == kSimplexStrategyDual) {
|
|
1728
|
+
// The parallel strategy is on and the simplex strategy is dual so use
|
|
1729
|
+
// PAMI if there are enough threads
|
|
1730
|
+
if (max_threads >= kDualMultiMinConcurrency)
|
|
1731
|
+
simplex_strategy = kSimplexStrategyDualMulti;
|
|
1732
|
+
}
|
|
1733
|
+
//
|
|
1734
|
+
// If parallel strategies are used, the minimum concurrency will be
|
|
1735
|
+
// set to be at least the minimum required for the strategy
|
|
1736
|
+
//
|
|
1737
|
+
// All this is independent of the number of threads available, since
|
|
1738
|
+
// code with multiple concurrency can be run in serial.
|
|
1739
|
+
|
|
1740
|
+
if (simplex_strategy == kSimplexStrategyDualTasks) {
|
|
1741
|
+
info.min_concurrency =
|
|
1742
|
+
max(kDualTasksMinConcurrency, simplex_min_concurrency);
|
|
1743
|
+
info.max_concurrency = max(info.min_concurrency, simplex_max_concurrency);
|
|
1744
|
+
} else if (simplex_strategy == kSimplexStrategyDualMulti) {
|
|
1745
|
+
info.min_concurrency =
|
|
1746
|
+
max(kDualMultiMinConcurrency, simplex_min_concurrency);
|
|
1747
|
+
info.max_concurrency = max(info.min_concurrency, simplex_max_concurrency);
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
// Set the concurrency to be used to be the maximum number
|
|
1751
|
+
info.num_concurrency = info.max_concurrency;
|
|
1752
|
+
// Give a warning if the concurrency to be used is less than the
|
|
1753
|
+
// minimum concurrency allowed
|
|
1754
|
+
if (info.num_concurrency < simplex_min_concurrency) {
|
|
1755
|
+
highsLogUser(options.log_options, HighsLogType::kWarning,
|
|
1756
|
+
"Using concurrency of %" HIGHSINT_FORMAT
|
|
1757
|
+
" for parallel strategy rather than "
|
|
1758
|
+
"minimum number (%" HIGHSINT_FORMAT ") specified in options\n",
|
|
1759
|
+
info.num_concurrency, simplex_min_concurrency);
|
|
1760
|
+
}
|
|
1761
|
+
// Give a warning if the concurrency to be used is more than the
|
|
1762
|
+
// maximum concurrency allowed
|
|
1763
|
+
if (info.num_concurrency > simplex_max_concurrency) {
|
|
1764
|
+
highsLogUser(options.log_options, HighsLogType::kWarning,
|
|
1765
|
+
"Using concurrency of %" HIGHSINT_FORMAT
|
|
1766
|
+
" for parallel strategy rather than "
|
|
1767
|
+
"maximum number (%" HIGHSINT_FORMAT ") specified in options\n",
|
|
1768
|
+
info.num_concurrency, simplex_max_concurrency);
|
|
1769
|
+
}
|
|
1770
|
+
// Give a warning if the concurrency to be used is less than the
|
|
1771
|
+
// number of threads available
|
|
1772
|
+
if (info.num_concurrency > max_threads) {
|
|
1773
|
+
highsLogUser(options.log_options, HighsLogType::kWarning,
|
|
1774
|
+
"Number of threads available = %" HIGHSINT_FORMAT
|
|
1775
|
+
" < %" HIGHSINT_FORMAT
|
|
1776
|
+
" = Simplex concurrency to be used: Parallel performance may "
|
|
1777
|
+
"be less than anticipated\n",
|
|
1778
|
+
max_threads, info.num_concurrency);
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
bool HEkk::getNonsingularInverse(const HighsInt solve_phase) {
|
|
1783
|
+
assert(status_.has_basis);
|
|
1784
|
+
const vector<HighsInt>& basicIndex = basis_.basicIndex_;
|
|
1785
|
+
// Take a copy of basicIndex from before INVERT to be used as the
|
|
1786
|
+
// saved ordering of basic variables - so reinvert will run
|
|
1787
|
+
// identically.
|
|
1788
|
+
const vector<HighsInt> basicIndex_before_compute_factor = basicIndex;
|
|
1789
|
+
// Save the number of updates performed in case it has to be used to determine
|
|
1790
|
+
// a limit
|
|
1791
|
+
const HighsInt simplex_update_count = info_.update_count;
|
|
1792
|
+
// Dual simplex edge weights are identified with rows, so must be
|
|
1793
|
+
// permuted according to INVERT. Scatter the edge weights so that,
|
|
1794
|
+
// after INVERT, they can be gathered according to the new
|
|
1795
|
+
// permutation of basicIndex
|
|
1796
|
+
analysis_.simplexTimerStart(PermWtClock);
|
|
1797
|
+
for (HighsInt i = 0; i < lp_.num_row_; i++)
|
|
1798
|
+
scattered_dual_edge_weight_[basicIndex[i]] = dual_edge_weight_[i];
|
|
1799
|
+
analysis_.simplexTimerStop(PermWtClock);
|
|
1800
|
+
|
|
1801
|
+
// Call computeFactor to perform INVERT
|
|
1802
|
+
HighsInt rank_deficiency = computeFactor();
|
|
1803
|
+
if (rank_deficiency)
|
|
1804
|
+
highsLogDev(
|
|
1805
|
+
options_->log_options, HighsLogType::kInfo,
|
|
1806
|
+
"HEkk::getNonsingularInverse Rank_deficiency: solve %d (Iteration "
|
|
1807
|
+
"%d)\n",
|
|
1808
|
+
(int)debug_solve_call_num_, (int)iteration_count_);
|
|
1809
|
+
|
|
1810
|
+
const bool artificial_rank_deficiency = false; // true;//
|
|
1811
|
+
if (artificial_rank_deficiency) {
|
|
1812
|
+
if (!info_.phase1_backtracking_test_done && solve_phase == kSolvePhase1) {
|
|
1813
|
+
// Claim rank deficiency to test backtracking
|
|
1814
|
+
// printf("Phase1 (Iter %" HIGHSINT_FORMAT
|
|
1815
|
+
// ") Claiming rank deficiency to test backtracking\n",
|
|
1816
|
+
// iteration_count_);
|
|
1817
|
+
rank_deficiency = 1;
|
|
1818
|
+
info_.phase1_backtracking_test_done = true;
|
|
1819
|
+
} else if (!info_.phase2_backtracking_test_done &&
|
|
1820
|
+
solve_phase == kSolvePhase2) {
|
|
1821
|
+
// Claim rank deficiency to test backtracking
|
|
1822
|
+
// printf("Phase2 (Iter %" HIGHSINT_FORMAT
|
|
1823
|
+
// ") Claiming rank deficiency to test backtracking\n",
|
|
1824
|
+
// iteration_count_);
|
|
1825
|
+
rank_deficiency = 1;
|
|
1826
|
+
info_.phase2_backtracking_test_done = true;
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
if (rank_deficiency) {
|
|
1830
|
+
// Rank deficient basis, so backtrack to last full rank basis
|
|
1831
|
+
//
|
|
1832
|
+
// Get the last nonsingular basis - so long as there is one
|
|
1833
|
+
uint64_t deficient_hash = basis_.hash;
|
|
1834
|
+
if (!getBacktrackingBasis()) return false;
|
|
1835
|
+
// Record that backtracking is taking place
|
|
1836
|
+
info_.backtracking_ = true;
|
|
1837
|
+
visited_basis_.clear();
|
|
1838
|
+
visited_basis_.insert(basis_.hash);
|
|
1839
|
+
visited_basis_.insert(deficient_hash);
|
|
1840
|
+
this->updateStatus(LpAction::kBacktracking);
|
|
1841
|
+
HighsInt backtrack_rank_deficiency = computeFactor();
|
|
1842
|
+
// This basis has previously been inverted successfully, so it shouldn't be
|
|
1843
|
+
// singular
|
|
1844
|
+
if (backtrack_rank_deficiency) return false;
|
|
1845
|
+
// simplex update limit will be half of the number of updates
|
|
1846
|
+
// performed, so make sure that at least one update was performed
|
|
1847
|
+
if (simplex_update_count <= 1) return false;
|
|
1848
|
+
HighsInt use_simplex_update_limit = info_.update_limit;
|
|
1849
|
+
HighsInt new_simplex_update_limit = simplex_update_count / 2;
|
|
1850
|
+
info_.update_limit = new_simplex_update_limit;
|
|
1851
|
+
highsLogDev(options_->log_options, HighsLogType::kWarning,
|
|
1852
|
+
"Rank deficiency of %" HIGHSINT_FORMAT
|
|
1853
|
+
" after %" HIGHSINT_FORMAT
|
|
1854
|
+
" simplex updates, so "
|
|
1855
|
+
"backtracking: max updates reduced from %" HIGHSINT_FORMAT
|
|
1856
|
+
" to %" HIGHSINT_FORMAT "\n",
|
|
1857
|
+
rank_deficiency, simplex_update_count, use_simplex_update_limit,
|
|
1858
|
+
new_simplex_update_limit);
|
|
1859
|
+
} else {
|
|
1860
|
+
// Current basis is full rank so save it
|
|
1861
|
+
putBacktrackingBasis(basicIndex_before_compute_factor);
|
|
1862
|
+
// Indicate that backtracking is not taking place
|
|
1863
|
+
info_.backtracking_ = false;
|
|
1864
|
+
// Reset the update limit in case this is the first successful
|
|
1865
|
+
// inversion after backtracking
|
|
1866
|
+
info_.update_limit = options_->simplex_update_limit;
|
|
1867
|
+
}
|
|
1868
|
+
// Gather the edge weights according to the permutation of
|
|
1869
|
+
// basicIndex after INVERT
|
|
1870
|
+
analysis_.simplexTimerStart(PermWtClock);
|
|
1871
|
+
for (HighsInt i = 0; i < lp_.num_row_; i++)
|
|
1872
|
+
dual_edge_weight_[i] = scattered_dual_edge_weight_[basicIndex[i]];
|
|
1873
|
+
analysis_.simplexTimerStop(PermWtClock);
|
|
1874
|
+
return true;
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
bool HEkk::getBacktrackingBasis() {
|
|
1878
|
+
if (!info_.valid_backtracking_basis_) return false;
|
|
1879
|
+
basis_ = info_.backtracking_basis_;
|
|
1880
|
+
info_.costs_shifted = (info_.backtracking_basis_costs_shifted_ != 0);
|
|
1881
|
+
info_.costs_perturbed = (info_.backtracking_basis_costs_perturbed_ != 0);
|
|
1882
|
+
info_.bounds_shifted = (info_.backtracking_basis_bounds_shifted_ != 0);
|
|
1883
|
+
info_.bounds_perturbed = (info_.backtracking_basis_bounds_perturbed_ != 0);
|
|
1884
|
+
info_.workShift_ = info_.backtracking_basis_workShift_;
|
|
1885
|
+
const HighsInt num_tot = lp_.num_col_ + lp_.num_row_;
|
|
1886
|
+
for (HighsInt iVar = 0; iVar < num_tot; iVar++)
|
|
1887
|
+
scattered_dual_edge_weight_[iVar] =
|
|
1888
|
+
info_.backtracking_basis_edge_weight_[iVar];
|
|
1889
|
+
return true;
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
void HEkk::putBacktrackingBasis() {
|
|
1893
|
+
const vector<HighsInt>& basicIndex = basis_.basicIndex_;
|
|
1894
|
+
analysis_.simplexTimerStart(PermWtClock);
|
|
1895
|
+
for (HighsInt i = 0; i < lp_.num_row_; i++)
|
|
1896
|
+
scattered_dual_edge_weight_[basicIndex[i]] = dual_edge_weight_[i];
|
|
1897
|
+
analysis_.simplexTimerStop(PermWtClock);
|
|
1898
|
+
putBacktrackingBasis(basicIndex);
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
void HEkk::putBacktrackingBasis(
|
|
1902
|
+
const vector<HighsInt>& basicIndex_before_compute_factor) {
|
|
1903
|
+
info_.valid_backtracking_basis_ = true;
|
|
1904
|
+
info_.backtracking_basis_ = basis_;
|
|
1905
|
+
info_.backtracking_basis_.basicIndex_ = basicIndex_before_compute_factor;
|
|
1906
|
+
info_.backtracking_basis_costs_shifted_ = info_.costs_shifted;
|
|
1907
|
+
info_.backtracking_basis_costs_perturbed_ = info_.costs_perturbed;
|
|
1908
|
+
info_.backtracking_basis_bounds_shifted_ = info_.bounds_shifted;
|
|
1909
|
+
info_.backtracking_basis_bounds_perturbed_ = info_.bounds_perturbed;
|
|
1910
|
+
info_.backtracking_basis_workShift_ = info_.workShift_;
|
|
1911
|
+
const HighsInt num_tot = lp_.num_col_ + lp_.num_row_;
|
|
1912
|
+
for (HighsInt iVar = 0; iVar < num_tot; iVar++)
|
|
1913
|
+
info_.backtracking_basis_edge_weight_[iVar] =
|
|
1914
|
+
scattered_dual_edge_weight_[iVar];
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
void HEkk::computePrimalObjectiveValue() {
|
|
1918
|
+
analysis_.simplexTimerStart(ComputePrObjClock);
|
|
1919
|
+
info_.primal_objective_value = 0;
|
|
1920
|
+
for (HighsInt iRow = 0; iRow < lp_.num_row_; iRow++) {
|
|
1921
|
+
HighsInt iVar = basis_.basicIndex_[iRow];
|
|
1922
|
+
if (iVar < lp_.num_col_) {
|
|
1923
|
+
info_.primal_objective_value +=
|
|
1924
|
+
info_.baseValue_[iRow] * lp_.col_cost_[iVar];
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
for (HighsInt iCol = 0; iCol < lp_.num_col_; iCol++) {
|
|
1928
|
+
if (basis_.nonbasicFlag_[iCol])
|
|
1929
|
+
info_.primal_objective_value +=
|
|
1930
|
+
info_.workValue_[iCol] * lp_.col_cost_[iCol];
|
|
1931
|
+
}
|
|
1932
|
+
info_.primal_objective_value *= cost_scale_;
|
|
1933
|
+
// Objective value calculation is done using primal values and
|
|
1934
|
+
// original costs so offset is vanilla
|
|
1935
|
+
info_.primal_objective_value += lp_.offset_;
|
|
1936
|
+
// Now have primal objective value
|
|
1937
|
+
status_.has_primal_objective_value = true;
|
|
1938
|
+
analysis_.simplexTimerStop(ComputePrObjClock);
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
void HEkk::computeDualObjectiveValue(const HighsInt phase) {
|
|
1942
|
+
analysis_.simplexTimerStart(ComputeDuObjClock);
|
|
1943
|
+
info_.dual_objective_value = 0;
|
|
1944
|
+
const HighsInt num_tot = lp_.num_col_ + lp_.num_row_;
|
|
1945
|
+
for (HighsInt iCol = 0; iCol < num_tot; iCol++) {
|
|
1946
|
+
if (basis_.nonbasicFlag_[iCol])
|
|
1947
|
+
info_.dual_objective_value +=
|
|
1948
|
+
info_.workValue_[iCol] * info_.workDual_[iCol];
|
|
1949
|
+
}
|
|
1950
|
+
info_.dual_objective_value *= cost_scale_;
|
|
1951
|
+
if (phase != 1) {
|
|
1952
|
+
// In phase 1 the dual objective has no objective
|
|
1953
|
+
// shift. Otherwise, if minimizing the shift is added. If
|
|
1954
|
+
// maximizing, workCost (and hence workDual) are negated, so the
|
|
1955
|
+
// shift is subtracted. Hence the shift is added according to the
|
|
1956
|
+
// sign implied by sense_
|
|
1957
|
+
info_.dual_objective_value += ((HighsInt)lp_.sense_) * lp_.offset_;
|
|
1958
|
+
}
|
|
1959
|
+
// Now have dual objective value
|
|
1960
|
+
status_.has_dual_objective_value = true;
|
|
1961
|
+
analysis_.simplexTimerStop(ComputeDuObjClock);
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
bool HEkk::rebuildRefactor(HighsInt rebuild_reason) {
|
|
1965
|
+
// If no updates have been performed, then don't refactor!
|
|
1966
|
+
if (info_.update_count == 0) return false;
|
|
1967
|
+
// Otherwise, refactor by default
|
|
1968
|
+
bool refactor = true;
|
|
1969
|
+
double solution_error = 0;
|
|
1970
|
+
if (options_->no_unnecessary_rebuild_refactor) {
|
|
1971
|
+
// Consider whether not to refactor in rebuild
|
|
1972
|
+
//
|
|
1973
|
+
// Must have an INVERT just to consider this!
|
|
1974
|
+
assert(status_.has_invert);
|
|
1975
|
+
if (rebuild_reason == kRebuildReasonNo ||
|
|
1976
|
+
rebuild_reason == kRebuildReasonPossiblyOptimal ||
|
|
1977
|
+
rebuild_reason == kRebuildReasonPossiblyPhase1Feasible ||
|
|
1978
|
+
rebuild_reason == kRebuildReasonPossiblyPrimalUnbounded ||
|
|
1979
|
+
rebuild_reason == kRebuildReasonPossiblyDualUnbounded ||
|
|
1980
|
+
rebuild_reason == kRebuildReasonPrimalInfeasibleInPrimalSimplex) {
|
|
1981
|
+
// By default, don't refactor!
|
|
1982
|
+
refactor = false;
|
|
1983
|
+
// Possibly revise the decision based on accuracy when solving a
|
|
1984
|
+
// test system
|
|
1985
|
+
const double error_tolerance =
|
|
1986
|
+
options_->rebuild_refactor_solution_error_tolerance;
|
|
1987
|
+
if (error_tolerance > 0) {
|
|
1988
|
+
solution_error = factorSolveError();
|
|
1989
|
+
refactor = solution_error > error_tolerance;
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
const bool report_refactorization = false;
|
|
1994
|
+
if (report_refactorization) {
|
|
1995
|
+
const std::string logic = refactor ? " " : "no ";
|
|
1996
|
+
if (info_.update_count &&
|
|
1997
|
+
rebuild_reason != kRebuildReasonSyntheticClockSaysInvert)
|
|
1998
|
+
printf(
|
|
1999
|
+
"%srefactorization after %4d updates and solution error = %11.4g for "
|
|
2000
|
+
"rebuild reason = %s\n",
|
|
2001
|
+
logic.c_str(), (int)info_.update_count, solution_error,
|
|
2002
|
+
rebuildReason(rebuild_reason).c_str());
|
|
2003
|
+
}
|
|
2004
|
+
return refactor;
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
HighsInt HEkk::computeFactor() {
|
|
2008
|
+
assert(status_.has_nla);
|
|
2009
|
+
if (status_.has_fresh_invert) return 0;
|
|
2010
|
+
// Clear any bad basis changes
|
|
2011
|
+
clearBadBasisChange();
|
|
2012
|
+
highsAssert(lpFactorRowCompatible(),
|
|
2013
|
+
"HEkk::computeFactor: lpFactorRowCompatible");
|
|
2014
|
+
// Perform INVERT
|
|
2015
|
+
analysis_.simplexTimerStart(InvertClock);
|
|
2016
|
+
const HighsInt rank_deficiency = simplex_nla_.invert();
|
|
2017
|
+
analysis_.simplexTimerStop(InvertClock);
|
|
2018
|
+
//
|
|
2019
|
+
// Set up hot start information
|
|
2020
|
+
hot_start_.refactor_info = simplex_nla_.factor_.refactor_info_;
|
|
2021
|
+
hot_start_.nonbasicMove = basis_.nonbasicMove_;
|
|
2022
|
+
hot_start_.valid = true;
|
|
2023
|
+
|
|
2024
|
+
if (analysis_.analyse_factor_data)
|
|
2025
|
+
analysis_.updateInvertFormData(simplex_nla_.factor_);
|
|
2026
|
+
|
|
2027
|
+
HighsInt alt_debug_level = -1;
|
|
2028
|
+
if (rank_deficiency) alt_debug_level = kHighsDebugLevelCostly;
|
|
2029
|
+
debugNlaCheckInvert("HEkk::computeFactor - original", alt_debug_level);
|
|
2030
|
+
|
|
2031
|
+
if (rank_deficiency) {
|
|
2032
|
+
// Have an invertible representation, but of B with column(s)
|
|
2033
|
+
// replacements due to singularity. So no (fresh) representation of
|
|
2034
|
+
// B^{-1}
|
|
2035
|
+
status_.has_invert = false;
|
|
2036
|
+
status_.has_fresh_invert = false;
|
|
2037
|
+
} else {
|
|
2038
|
+
// Now have a representation of B^{-1}, and it is fresh!
|
|
2039
|
+
status_.has_invert = true;
|
|
2040
|
+
status_.has_fresh_invert = true;
|
|
2041
|
+
}
|
|
2042
|
+
// Set the update count to zero since the corrected invertible
|
|
2043
|
+
// representation may be used for an initial basis. In any case the
|
|
2044
|
+
// number of updates shouldn't be positive
|
|
2045
|
+
info_.update_count = 0;
|
|
2046
|
+
|
|
2047
|
+
simplex_stats_.num_invert++;
|
|
2048
|
+
return rank_deficiency;
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
void HEkk::computeDualSteepestEdgeWeights(const bool initial) {
|
|
2052
|
+
if (analysis_.analyse_simplex_time) {
|
|
2053
|
+
analysis_.simplexTimerStart(SimplexIzDseWtClock);
|
|
2054
|
+
analysis_.simplexTimerStart(DseIzClock);
|
|
2055
|
+
}
|
|
2056
|
+
const HighsInt num_row = lp_.num_row_;
|
|
2057
|
+
HVector row_ep;
|
|
2058
|
+
row_ep.setup(num_row);
|
|
2059
|
+
assert((HighsInt)dual_edge_weight_.size() >= num_row);
|
|
2060
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++)
|
|
2061
|
+
dual_edge_weight_[iRow] = computeDualSteepestEdgeWeight(iRow, row_ep);
|
|
2062
|
+
if (analysis_.analyse_simplex_time) {
|
|
2063
|
+
analysis_.simplexTimerStop(SimplexIzDseWtClock);
|
|
2064
|
+
analysis_.simplexTimerStop(DseIzClock);
|
|
2065
|
+
if (initial) {
|
|
2066
|
+
double IzDseWtTT = analysis_.simplexTimerRead(SimplexIzDseWtClock);
|
|
2067
|
+
highsLogDev(options_->log_options, HighsLogType::kDetailed,
|
|
2068
|
+
"Computed %" HIGHSINT_FORMAT " initial DSE weights in %gs\n",
|
|
2069
|
+
num_row, IzDseWtTT);
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
double HEkk::computeDualSteepestEdgeWeight(const HighsInt iRow,
|
|
2075
|
+
HVector& row_ep) {
|
|
2076
|
+
row_ep.clear();
|
|
2077
|
+
row_ep.count = 1;
|
|
2078
|
+
row_ep.index[0] = iRow;
|
|
2079
|
+
row_ep.array[iRow] = 1;
|
|
2080
|
+
row_ep.packFlag = false;
|
|
2081
|
+
simplex_nla_.btranInScaledSpace(row_ep, info_.row_ep_density,
|
|
2082
|
+
analysis_.pointer_serial_factor_clocks);
|
|
2083
|
+
const double local_row_ep_density = (1.0 * row_ep.count) / lp_.num_row_;
|
|
2084
|
+
updateOperationResultDensity(local_row_ep_density, info_.row_ep_density);
|
|
2085
|
+
return row_ep.norm2();
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
// Update the DSE weights
|
|
2089
|
+
void HEkk::updateDualSteepestEdgeWeights(
|
|
2090
|
+
const HighsInt row_out, const HighsInt variable_in, const HVector* column,
|
|
2091
|
+
const double new_pivotal_edge_weight, const double Kai,
|
|
2092
|
+
const double* dual_steepest_edge_array) {
|
|
2093
|
+
analysis_.simplexTimerStart(DseUpdateWeightClock);
|
|
2094
|
+
|
|
2095
|
+
const HighsInt num_row = lp_.num_row_;
|
|
2096
|
+
const HighsInt column_count = column->count;
|
|
2097
|
+
const HighsInt* variable_index = column->index.data();
|
|
2098
|
+
const double* column_array = column->array.data();
|
|
2099
|
+
|
|
2100
|
+
const double col_aq_scale = simplex_nla_.variableScaleFactor(variable_in);
|
|
2101
|
+
const double col_ap_scale = simplex_nla_.basicColScaleFactor(row_out);
|
|
2102
|
+
const double inv_col_ap_scale = 1.0 / col_ap_scale;
|
|
2103
|
+
|
|
2104
|
+
const bool DSE_check = false;
|
|
2105
|
+
HVector alt_dual_steepest_edge_column;
|
|
2106
|
+
HVector alt_pivotal_column;
|
|
2107
|
+
if (DSE_check) {
|
|
2108
|
+
// Compute the DSE column otherwise to check
|
|
2109
|
+
alt_dual_steepest_edge_column.setup(num_row);
|
|
2110
|
+
alt_dual_steepest_edge_column.clear();
|
|
2111
|
+
alt_dual_steepest_edge_column.count = 1;
|
|
2112
|
+
alt_dual_steepest_edge_column.index[0] = row_out;
|
|
2113
|
+
alt_dual_steepest_edge_column.array[row_out] = 1;
|
|
2114
|
+
alt_dual_steepest_edge_column.packFlag = false;
|
|
2115
|
+
simplex_nla_.btranInScaledSpace(alt_dual_steepest_edge_column,
|
|
2116
|
+
info_.row_ep_density,
|
|
2117
|
+
analysis_.pointer_serial_factor_clocks);
|
|
2118
|
+
simplex_nla_.ftranInScaledSpace(alt_dual_steepest_edge_column,
|
|
2119
|
+
info_.row_DSE_density,
|
|
2120
|
+
analysis_.pointer_serial_factor_clocks);
|
|
2121
|
+
// Compute the pivotal column in the scaled space otherwise to check
|
|
2122
|
+
//
|
|
2123
|
+
// Need \bar{B}^{-1}(R.aq.cq) = \bar{B}^{-1}R.(cq.aq)
|
|
2124
|
+
//
|
|
2125
|
+
alt_pivotal_column.setup(num_row);
|
|
2126
|
+
alt_pivotal_column.clear();
|
|
2127
|
+
//
|
|
2128
|
+
// Determine cq, and apply it in forming RHS
|
|
2129
|
+
//
|
|
2130
|
+
lp_.a_matrix_.collectAj(alt_pivotal_column, variable_in, col_aq_scale);
|
|
2131
|
+
simplex_nla_.applyBasisMatrixRowScale(alt_pivotal_column);
|
|
2132
|
+
simplex_nla_.ftranInScaledSpace(alt_pivotal_column, info_.col_aq_density,
|
|
2133
|
+
analysis_.pointer_serial_factor_clocks);
|
|
2134
|
+
double max_dse_column_error = 0;
|
|
2135
|
+
double sum_dse_column_error = 0;
|
|
2136
|
+
HighsInt num_dse_column_error = 0;
|
|
2137
|
+
const double dse_column_value_tolerance = 1e-2;
|
|
2138
|
+
const double dse_column_error_tolerance = 1e-4;
|
|
2139
|
+
HighsInt DSE_array_count = 0;
|
|
2140
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
2141
|
+
const double dual_steepest_edge_array_value =
|
|
2142
|
+
dual_steepest_edge_array[iRow] * inv_col_ap_scale;
|
|
2143
|
+
if (dual_steepest_edge_array_value) DSE_array_count++;
|
|
2144
|
+
if (std::abs(dual_steepest_edge_array_value) >
|
|
2145
|
+
dse_column_value_tolerance ||
|
|
2146
|
+
std::abs(alt_dual_steepest_edge_column.array[iRow]) >
|
|
2147
|
+
dse_column_value_tolerance) {
|
|
2148
|
+
const double dse_column_error =
|
|
2149
|
+
std::abs(alt_dual_steepest_edge_column.array[iRow] -
|
|
2150
|
+
dual_steepest_edge_array_value) /
|
|
2151
|
+
std::max(1.0, std::abs(dual_steepest_edge_array_value));
|
|
2152
|
+
sum_dse_column_error += dse_column_error;
|
|
2153
|
+
if (dse_column_error > dse_column_error_tolerance) {
|
|
2154
|
+
max_dse_column_error =
|
|
2155
|
+
std::max(dse_column_error, max_dse_column_error);
|
|
2156
|
+
num_dse_column_error++;
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
if (max_dse_column_error > dse_column_error_tolerance) {
|
|
2161
|
+
printf(
|
|
2162
|
+
"HEkk::updateDualSteepestEdgeWeights: Iter %2d has num / max / sum = "
|
|
2163
|
+
"%d / %g / %g DSE column errors exceeding = %g\n",
|
|
2164
|
+
(int)iteration_count_, (int)num_dse_column_error,
|
|
2165
|
+
max_dse_column_error, sum_dse_column_error,
|
|
2166
|
+
dse_column_error_tolerance);
|
|
2167
|
+
printf("DSE column count alt = %d; og = %d)\n",
|
|
2168
|
+
(int)alt_dual_steepest_edge_column.count, (int)DSE_array_count);
|
|
2169
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
2170
|
+
const double dual_steepest_edge_array_value =
|
|
2171
|
+
dual_steepest_edge_array[iRow] * inv_col_ap_scale;
|
|
2172
|
+
if (alt_dual_steepest_edge_column.array[iRow] != 0 &&
|
|
2173
|
+
dual_steepest_edge_array_value != 0) {
|
|
2174
|
+
const double dse_column_error =
|
|
2175
|
+
std::abs(alt_dual_steepest_edge_column.array[iRow] -
|
|
2176
|
+
dual_steepest_edge_array_value) /
|
|
2177
|
+
std::max(1.0, std::abs(dual_steepest_edge_array_value));
|
|
2178
|
+
if (dse_column_error > 1e-10)
|
|
2179
|
+
printf(
|
|
2180
|
+
"Row %4d: DSE column (alt = %11.4g; og = %11.4g) difference "
|
|
2181
|
+
"%10.4g\n",
|
|
2182
|
+
(int)iRow, alt_dual_steepest_edge_column.array[iRow],
|
|
2183
|
+
dual_steepest_edge_array_value, dse_column_error);
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
fflush(stdout);
|
|
2187
|
+
assert(max_dse_column_error < dse_column_error_tolerance);
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
if ((HighsInt)dual_edge_weight_.size() < num_row) {
|
|
2192
|
+
printf(
|
|
2193
|
+
"HEkk::updateDualSteepestEdgeWeights solve %d: "
|
|
2194
|
+
"dual_edge_weight_.size() = %d < %d\n",
|
|
2195
|
+
(int)debug_solve_call_num_, (int)dual_edge_weight_.size(),
|
|
2196
|
+
(int)num_row);
|
|
2197
|
+
fflush(stdout);
|
|
2198
|
+
}
|
|
2199
|
+
assert((HighsInt)dual_edge_weight_.size() >= num_row);
|
|
2200
|
+
HighsInt to_entry;
|
|
2201
|
+
const bool use_row_indices =
|
|
2202
|
+
simplex_nla_.sparseLoopStyle(column_count, num_row, to_entry);
|
|
2203
|
+
const bool convert_to_scaled_space = !simplex_in_scaled_space_;
|
|
2204
|
+
for (HighsInt iEntry = 0; iEntry < to_entry; iEntry++) {
|
|
2205
|
+
const HighsInt iRow = use_row_indices ? variable_index[iEntry] : iEntry;
|
|
2206
|
+
double aa_iRow = column_array[iRow];
|
|
2207
|
+
if (!aa_iRow) continue;
|
|
2208
|
+
double dual_steepest_edge_array_value = dual_steepest_edge_array[iRow];
|
|
2209
|
+
if (convert_to_scaled_space) {
|
|
2210
|
+
double basic_col_scale = simplex_nla_.basicColScaleFactor(iRow);
|
|
2211
|
+
aa_iRow /= basic_col_scale;
|
|
2212
|
+
aa_iRow *= col_aq_scale;
|
|
2213
|
+
dual_steepest_edge_array_value *= inv_col_ap_scale;
|
|
2214
|
+
}
|
|
2215
|
+
if (DSE_check) {
|
|
2216
|
+
const double pivotal_column_error =
|
|
2217
|
+
std::abs(aa_iRow - alt_pivotal_column.array[iRow]);
|
|
2218
|
+
if (pivotal_column_error > 1e-4) {
|
|
2219
|
+
printf(
|
|
2220
|
+
"HEkk::updateDualSteepestEdgeWeights Row %2d of pivotal column has "
|
|
2221
|
+
"error %10.4g\n",
|
|
2222
|
+
(int)iRow, pivotal_column_error);
|
|
2223
|
+
fflush(stdout);
|
|
2224
|
+
}
|
|
2225
|
+
assert(pivotal_column_error < 1e-4);
|
|
2226
|
+
}
|
|
2227
|
+
dual_edge_weight_[iRow] += aa_iRow * (new_pivotal_edge_weight * aa_iRow +
|
|
2228
|
+
Kai * dual_steepest_edge_array_value);
|
|
2229
|
+
dual_edge_weight_[iRow] =
|
|
2230
|
+
std::max(kMinDualSteepestEdgeWeight, dual_edge_weight_[iRow]);
|
|
2231
|
+
}
|
|
2232
|
+
analysis_.simplexTimerStop(DseUpdateWeightClock);
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
// Update the Devex weights
|
|
2236
|
+
void HEkk::updateDualDevexWeights(const HVector* column,
|
|
2237
|
+
const double new_pivotal_edge_weight) {
|
|
2238
|
+
analysis_.simplexTimerStart(DevexUpdateWeightClock);
|
|
2239
|
+
|
|
2240
|
+
const HighsInt num_row = lp_.num_row_;
|
|
2241
|
+
const HighsInt column_count = column->count;
|
|
2242
|
+
const HighsInt* variable_index = column->index.data();
|
|
2243
|
+
const double* column_array = column->array.data();
|
|
2244
|
+
|
|
2245
|
+
if ((HighsInt)dual_edge_weight_.size() < num_row) {
|
|
2246
|
+
printf(
|
|
2247
|
+
"HEkk::updateDualDevexWeights solve %d: "
|
|
2248
|
+
"dual_edge_weight_.size() = %d < %d\n",
|
|
2249
|
+
(int)debug_solve_call_num_, (int)dual_edge_weight_.size(),
|
|
2250
|
+
(int)num_row);
|
|
2251
|
+
fflush(stdout);
|
|
2252
|
+
}
|
|
2253
|
+
assert((HighsInt)dual_edge_weight_.size() >= num_row);
|
|
2254
|
+
HighsInt to_entry;
|
|
2255
|
+
const bool use_row_indices =
|
|
2256
|
+
simplex_nla_.sparseLoopStyle(column_count, num_row, to_entry);
|
|
2257
|
+
for (HighsInt iEntry = 0; iEntry < to_entry; iEntry++) {
|
|
2258
|
+
const HighsInt iRow = use_row_indices ? variable_index[iEntry] : iEntry;
|
|
2259
|
+
const double aa_iRow = column_array[iRow];
|
|
2260
|
+
dual_edge_weight_[iRow] = max(dual_edge_weight_[iRow],
|
|
2261
|
+
new_pivotal_edge_weight * aa_iRow * aa_iRow);
|
|
2262
|
+
}
|
|
2263
|
+
analysis_.simplexTimerStop(DevexUpdateWeightClock);
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
void HEkk::resetSyntheticClock() {
|
|
2267
|
+
this->build_synthetic_tick_ = this->simplex_nla_.build_synthetic_tick_;
|
|
2268
|
+
this->total_synthetic_tick_ = 0;
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
void HEkk::initialisePartitionedRowwiseMatrix() {
|
|
2272
|
+
if (status_.has_ar_matrix) return;
|
|
2273
|
+
analysis_.simplexTimerStart(matrixSetupClock);
|
|
2274
|
+
ar_matrix_.createRowwisePartitioned(lp_.a_matrix_,
|
|
2275
|
+
basis_.nonbasicFlag_.data());
|
|
2276
|
+
assert(ar_matrix_.debugPartitionOk(basis_.nonbasicFlag_.data()));
|
|
2277
|
+
analysis_.simplexTimerStop(matrixSetupClock);
|
|
2278
|
+
status_.has_ar_matrix = true;
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2281
|
+
bool HEkk::lpFactorRowCompatible() const {
|
|
2282
|
+
return lpFactorRowCompatible(this->lp_.num_row_);
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2285
|
+
bool HEkk::lpFactorRowCompatible(const HighsInt expectedNumRow) const {
|
|
2286
|
+
// Check for LP-HFactor row compatibility
|
|
2287
|
+
const bool consistent_num_row =
|
|
2288
|
+
this->simplex_nla_.factor_.num_row == expectedNumRow;
|
|
2289
|
+
if (!consistent_num_row) {
|
|
2290
|
+
highsLogDev(options_->log_options, HighsLogType::kError,
|
|
2291
|
+
"HEkk::initialiseSimplexLpBasisAndFactor: LP(%6d, %6d) has "
|
|
2292
|
+
"factor_num_row = %d\n",
|
|
2293
|
+
(int)this->lp_.num_col_, expectedNumRow,
|
|
2294
|
+
(int)this->simplex_nla_.factor_.num_row);
|
|
2295
|
+
}
|
|
2296
|
+
return consistent_num_row;
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
std::string HEkk::simplexStrategyToString(
|
|
2300
|
+
const HighsInt simplex_strategy) const {
|
|
2301
|
+
assert(kSimplexStrategyMin <= simplex_strategy &&
|
|
2302
|
+
simplex_strategy <= kSimplexStrategyMax);
|
|
2303
|
+
if (simplex_strategy == kSimplexStrategyChoose)
|
|
2304
|
+
return "choose simplex solver";
|
|
2305
|
+
if (simplex_strategy == kSimplexStrategyDual) return "dual simplex solver";
|
|
2306
|
+
if (simplex_strategy == kSimplexStrategyDualPlain)
|
|
2307
|
+
return "serial dual simplex solver";
|
|
2308
|
+
if (simplex_strategy == kSimplexStrategyDualTasks)
|
|
2309
|
+
return "parallel dual simplex solver - SIP";
|
|
2310
|
+
if (simplex_strategy == kSimplexStrategyDualMulti)
|
|
2311
|
+
return "parallel dual simplex solver - PAMI";
|
|
2312
|
+
if (simplex_strategy == kSimplexStrategyPrimal)
|
|
2313
|
+
return "primal simplex solver";
|
|
2314
|
+
return "Unknown";
|
|
2315
|
+
}
|
|
2316
|
+
|
|
2317
|
+
void HEkk::zeroBasicDuals() {
|
|
2318
|
+
for (HighsInt iRow = 0; iRow < lp_.num_row_; iRow++)
|
|
2319
|
+
info_.workDual_[basis_.basicIndex_[iRow]] = 0;
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
void HEkk::setNonbasicMove() {
|
|
2323
|
+
const bool have_solution = false;
|
|
2324
|
+
// Don't have a simplex basis since nonbasicMove is not set up.
|
|
2325
|
+
|
|
2326
|
+
// Assign nonbasicMove using as much information as is available
|
|
2327
|
+
double lower;
|
|
2328
|
+
double upper;
|
|
2329
|
+
const HighsInt num_tot = lp_.num_col_ + lp_.num_row_;
|
|
2330
|
+
basis_.nonbasicMove_.resize(num_tot);
|
|
2331
|
+
|
|
2332
|
+
for (HighsInt iVar = 0; iVar < num_tot; iVar++) {
|
|
2333
|
+
if (!basis_.nonbasicFlag_[iVar]) {
|
|
2334
|
+
// Basic variable
|
|
2335
|
+
basis_.nonbasicMove_[iVar] = kNonbasicMoveZe;
|
|
2336
|
+
continue;
|
|
2337
|
+
}
|
|
2338
|
+
// Nonbasic variable
|
|
2339
|
+
if (iVar < lp_.num_col_) {
|
|
2340
|
+
lower = lp_.col_lower_[iVar];
|
|
2341
|
+
upper = lp_.col_upper_[iVar];
|
|
2342
|
+
} else {
|
|
2343
|
+
HighsInt iRow = iVar - lp_.num_col_;
|
|
2344
|
+
lower = -lp_.row_upper_[iRow];
|
|
2345
|
+
upper = -lp_.row_lower_[iRow];
|
|
2346
|
+
}
|
|
2347
|
+
int8_t move = kIllegalMoveValue;
|
|
2348
|
+
if (lower == upper) {
|
|
2349
|
+
// Fixed
|
|
2350
|
+
move = kNonbasicMoveZe;
|
|
2351
|
+
} else if (!highs_isInfinity(-lower)) {
|
|
2352
|
+
// Finite lower bound so boxed or lower
|
|
2353
|
+
if (!highs_isInfinity(upper)) {
|
|
2354
|
+
// Finite upper bound so boxed
|
|
2355
|
+
//
|
|
2356
|
+
// Determine the bound to set the value to according to, in order of
|
|
2357
|
+
// priority
|
|
2358
|
+
//
|
|
2359
|
+
// 1. Any solution value
|
|
2360
|
+
if (have_solution) {
|
|
2361
|
+
double midpoint = 0.5 * (lower + upper);
|
|
2362
|
+
double value = info_.workValue_[iVar];
|
|
2363
|
+
if (value < midpoint) {
|
|
2364
|
+
move = kNonbasicMoveUp;
|
|
2365
|
+
} else {
|
|
2366
|
+
move = kNonbasicMoveDn;
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
// 2. Bound of original LP that is closer to zero
|
|
2370
|
+
if (move == kIllegalMoveValue) {
|
|
2371
|
+
if (fabs(lower) < fabs(upper)) {
|
|
2372
|
+
move = kNonbasicMoveUp;
|
|
2373
|
+
} else {
|
|
2374
|
+
move = kNonbasicMoveDn;
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
} else {
|
|
2378
|
+
// Lower (since upper bound is infinite)
|
|
2379
|
+
move = kNonbasicMoveUp;
|
|
2380
|
+
}
|
|
2381
|
+
} else if (!highs_isInfinity(upper)) {
|
|
2382
|
+
// Upper
|
|
2383
|
+
move = kNonbasicMoveDn;
|
|
2384
|
+
} else {
|
|
2385
|
+
// FREE
|
|
2386
|
+
move = kNonbasicMoveZe;
|
|
2387
|
+
}
|
|
2388
|
+
assert(move != kIllegalMoveValue);
|
|
2389
|
+
basis_.nonbasicMove_[iVar] = move;
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
void HEkk::allocateWorkAndBaseArrays() {
|
|
2394
|
+
const HighsInt num_tot = lp_.num_col_ + lp_.num_row_;
|
|
2395
|
+
info_.workCost_.resize(num_tot);
|
|
2396
|
+
info_.workDual_.resize(num_tot);
|
|
2397
|
+
info_.workShift_.resize(num_tot);
|
|
2398
|
+
|
|
2399
|
+
info_.workLower_.resize(num_tot);
|
|
2400
|
+
info_.workUpper_.resize(num_tot);
|
|
2401
|
+
info_.workRange_.resize(num_tot);
|
|
2402
|
+
info_.workValue_.resize(num_tot);
|
|
2403
|
+
info_.workLowerShift_.resize(num_tot);
|
|
2404
|
+
info_.workUpperShift_.resize(num_tot);
|
|
2405
|
+
|
|
2406
|
+
// Feel that it should be possible to resize this with in dual
|
|
2407
|
+
// solver, and only if Devex is being used, but a pointer to it
|
|
2408
|
+
// needs to be set up when constructing HDual
|
|
2409
|
+
info_.devex_index_.resize(num_tot);
|
|
2410
|
+
|
|
2411
|
+
info_.baseLower_.resize(lp_.num_row_);
|
|
2412
|
+
info_.baseUpper_.resize(lp_.num_row_);
|
|
2413
|
+
info_.baseValue_.resize(lp_.num_row_);
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2416
|
+
void HEkk::initialiseLpColBound() {
|
|
2417
|
+
for (HighsInt iCol = 0; iCol < lp_.num_col_; iCol++) {
|
|
2418
|
+
info_.workLower_[iCol] = lp_.col_lower_[iCol];
|
|
2419
|
+
info_.workUpper_[iCol] = lp_.col_upper_[iCol];
|
|
2420
|
+
info_.workRange_[iCol] = info_.workUpper_[iCol] - info_.workLower_[iCol];
|
|
2421
|
+
info_.workLowerShift_[iCol] = 0;
|
|
2422
|
+
info_.workUpperShift_[iCol] = 0;
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
void HEkk::initialiseLpRowBound() {
|
|
2427
|
+
for (HighsInt iRow = 0; iRow < lp_.num_row_; iRow++) {
|
|
2428
|
+
HighsInt iCol = lp_.num_col_ + iRow;
|
|
2429
|
+
info_.workLower_[iCol] = -lp_.row_upper_[iRow];
|
|
2430
|
+
info_.workUpper_[iCol] = -lp_.row_lower_[iRow];
|
|
2431
|
+
info_.workRange_[iCol] = info_.workUpper_[iCol] - info_.workLower_[iCol];
|
|
2432
|
+
info_.workLowerShift_[iCol] = 0;
|
|
2433
|
+
info_.workUpperShift_[iCol] = 0;
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
|
|
2437
|
+
void HEkk::initialiseCost(const SimplexAlgorithm algorithm,
|
|
2438
|
+
const HighsInt solve_phase, const bool perturb) {
|
|
2439
|
+
// Copy the cost
|
|
2440
|
+
initialiseLpColCost();
|
|
2441
|
+
initialiseLpRowCost();
|
|
2442
|
+
info_.costs_shifted = false;
|
|
2443
|
+
info_.costs_perturbed = false;
|
|
2444
|
+
analysis_.net_num_single_cost_shift = 0;
|
|
2445
|
+
// Primal simplex costs are either from the LP or set specially in phase 1
|
|
2446
|
+
if (algorithm == SimplexAlgorithm::kPrimal) return;
|
|
2447
|
+
// Dual simplex costs are either from the LP or perturbed
|
|
2448
|
+
if (!perturb || info_.dual_simplex_cost_perturbation_multiplier == 0) return;
|
|
2449
|
+
// Perturb the original costs, scale down if is too big
|
|
2450
|
+
const bool report_cost_perturbation =
|
|
2451
|
+
options_->output_flag; // && analysis_.analyse_simplex_runtime_data;
|
|
2452
|
+
HighsInt num_original_nonzero_cost = 0;
|
|
2453
|
+
if (report_cost_perturbation)
|
|
2454
|
+
highsLogDev(options_->log_options, HighsLogType::kInfo,
|
|
2455
|
+
"Cost perturbation for %s\n", lp_.model_name_.c_str());
|
|
2456
|
+
double min_abs_cost = kHighsInf;
|
|
2457
|
+
double max_abs_cost = 0;
|
|
2458
|
+
double sum_abs_cost = 0;
|
|
2459
|
+
for (HighsInt i = 0; i < lp_.num_col_; i++) {
|
|
2460
|
+
const double abs_cost = fabs(info_.workCost_[i]);
|
|
2461
|
+
if (report_cost_perturbation) {
|
|
2462
|
+
if (abs_cost) {
|
|
2463
|
+
num_original_nonzero_cost++;
|
|
2464
|
+
min_abs_cost = min(min_abs_cost, abs_cost);
|
|
2465
|
+
}
|
|
2466
|
+
sum_abs_cost += abs_cost;
|
|
2467
|
+
}
|
|
2468
|
+
max_abs_cost = max(max_abs_cost, abs_cost);
|
|
2469
|
+
}
|
|
2470
|
+
const HighsInt pct0 = (100 * num_original_nonzero_cost) / lp_.num_col_;
|
|
2471
|
+
double average_abs_cost = 0;
|
|
2472
|
+
if (report_cost_perturbation) {
|
|
2473
|
+
highsLogDev(options_->log_options, HighsLogType::kInfo,
|
|
2474
|
+
" Initially have %" HIGHSINT_FORMAT
|
|
2475
|
+
" nonzero costs (%3" HIGHSINT_FORMAT "%%)",
|
|
2476
|
+
num_original_nonzero_cost, pct0);
|
|
2477
|
+
if (num_original_nonzero_cost) {
|
|
2478
|
+
average_abs_cost = sum_abs_cost / num_original_nonzero_cost;
|
|
2479
|
+
highsLogDev(options_->log_options, HighsLogType::kInfo,
|
|
2480
|
+
" with min / average / max = %g / %g / %g\n", min_abs_cost,
|
|
2481
|
+
average_abs_cost, max_abs_cost);
|
|
2482
|
+
} else {
|
|
2483
|
+
min_abs_cost = 1.0;
|
|
2484
|
+
max_abs_cost = 1.0;
|
|
2485
|
+
average_abs_cost = 1.0;
|
|
2486
|
+
highsLogDev(options_->log_options, HighsLogType::kInfo,
|
|
2487
|
+
" but perturb as if max cost was 1\n");
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
if (max_abs_cost > 100) {
|
|
2491
|
+
max_abs_cost = sqrt(sqrt(max_abs_cost));
|
|
2492
|
+
if (report_cost_perturbation)
|
|
2493
|
+
highsLogDev(
|
|
2494
|
+
options_->log_options, HighsLogType::kInfo,
|
|
2495
|
+
" Large so set max_abs_cost = sqrt(sqrt(max_abs_cost)) = %g\n",
|
|
2496
|
+
max_abs_cost);
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
// If there are few boxed variables, we will just use simple perturbation
|
|
2500
|
+
double boxedRate = 0;
|
|
2501
|
+
const HighsInt num_tot = lp_.num_col_ + lp_.num_row_;
|
|
2502
|
+
for (HighsInt i = 0; i < num_tot; i++)
|
|
2503
|
+
boxedRate += (info_.workRange_[i] < 1e30);
|
|
2504
|
+
boxedRate /= num_tot;
|
|
2505
|
+
if (boxedRate < 0.01) {
|
|
2506
|
+
max_abs_cost = min(max_abs_cost, 1.0);
|
|
2507
|
+
if (report_cost_perturbation)
|
|
2508
|
+
highsLogDev(options_->log_options, HighsLogType::kInfo,
|
|
2509
|
+
" Small boxedRate (%g) so set max_abs_cost = "
|
|
2510
|
+
"min(max_abs_cost, 1.0) = "
|
|
2511
|
+
"%g\n",
|
|
2512
|
+
boxedRate, max_abs_cost);
|
|
2513
|
+
}
|
|
2514
|
+
// Determine the perturbation base
|
|
2515
|
+
cost_perturbation_max_abs_cost_ = max_abs_cost;
|
|
2516
|
+
cost_perturbation_base_ =
|
|
2517
|
+
info_.dual_simplex_cost_perturbation_multiplier * 5e-7 * max_abs_cost;
|
|
2518
|
+
if (report_cost_perturbation)
|
|
2519
|
+
highsLogDev(options_->log_options, HighsLogType::kInfo,
|
|
2520
|
+
" Perturbation column base = %g\n", cost_perturbation_base_);
|
|
2521
|
+
|
|
2522
|
+
// Now do the perturbation
|
|
2523
|
+
for (HighsInt i = 0; i < lp_.num_col_; i++) {
|
|
2524
|
+
double lower = lp_.col_lower_[i];
|
|
2525
|
+
double upper = lp_.col_upper_[i];
|
|
2526
|
+
double xpert = (1 + info_.numTotRandomValue_[i]) *
|
|
2527
|
+
(fabs(info_.workCost_[i]) + 1) * cost_perturbation_base_;
|
|
2528
|
+
// const double previous_cost = info_.workCost_[i];
|
|
2529
|
+
if (lower <= -kHighsInf && upper >= kHighsInf) {
|
|
2530
|
+
// Free - no perturb
|
|
2531
|
+
} else if (upper >= kHighsInf) { // Lower
|
|
2532
|
+
info_.workCost_[i] += xpert;
|
|
2533
|
+
} else if (lower <= -kHighsInf) { // Upper
|
|
2534
|
+
info_.workCost_[i] += -xpert;
|
|
2535
|
+
} else if (lower != upper) { // Boxed
|
|
2536
|
+
info_.workCost_[i] += (info_.workCost_[i] >= 0) ? xpert : -xpert;
|
|
2537
|
+
} else {
|
|
2538
|
+
// Fixed - no perturb
|
|
2539
|
+
}
|
|
2540
|
+
// if (report_cost_perturbation) {
|
|
2541
|
+
// const double perturbation1 = fabs(info_.workCost_[i] -
|
|
2542
|
+
// previous_cost); if (perturbation1)
|
|
2543
|
+
// updateValueDistribution(perturbation1,
|
|
2544
|
+
// analysis_.cost_perturbation1_distribution);
|
|
2545
|
+
// }
|
|
2546
|
+
}
|
|
2547
|
+
const double row_cost_perturbation_base_ =
|
|
2548
|
+
info_.dual_simplex_cost_perturbation_multiplier * 1e-12;
|
|
2549
|
+
if (report_cost_perturbation)
|
|
2550
|
+
highsLogDev(options_->log_options, HighsLogType::kInfo,
|
|
2551
|
+
" Perturbation row base = %g\n",
|
|
2552
|
+
row_cost_perturbation_base_);
|
|
2553
|
+
for (HighsInt i = lp_.num_col_; i < num_tot; i++) {
|
|
2554
|
+
double perturbation2 =
|
|
2555
|
+
(0.5 - info_.numTotRandomValue_[i]) * row_cost_perturbation_base_;
|
|
2556
|
+
info_.workCost_[i] += perturbation2;
|
|
2557
|
+
// if (report_cost_perturbation) {
|
|
2558
|
+
// perturbation2 = fabs(perturbation2);
|
|
2559
|
+
// updateValueDistribution(perturbation2,
|
|
2560
|
+
// analysis_.cost_perturbation2_distribution);
|
|
2561
|
+
// }
|
|
2562
|
+
}
|
|
2563
|
+
info_.costs_perturbed = true;
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
void HEkk::initialiseBound(const SimplexAlgorithm algorithm,
|
|
2567
|
+
const HighsInt solve_phase, const bool perturb) {
|
|
2568
|
+
initialiseLpColBound();
|
|
2569
|
+
initialiseLpRowBound();
|
|
2570
|
+
info_.bounds_shifted = false;
|
|
2571
|
+
info_.bounds_perturbed = false;
|
|
2572
|
+
// Primal simplex bounds are either from the LP or perturbed
|
|
2573
|
+
if (algorithm == SimplexAlgorithm::kPrimal) {
|
|
2574
|
+
if (!perturb || info_.primal_simplex_bound_perturbation_multiplier == 0)
|
|
2575
|
+
return;
|
|
2576
|
+
// Perturb the bounds
|
|
2577
|
+
// Determine the smallest and largest finite lower/upper bounds
|
|
2578
|
+
HighsInt num_col = lp_.num_col_;
|
|
2579
|
+
HighsInt num_row = lp_.num_row_;
|
|
2580
|
+
HighsInt num_tot = num_col + num_row;
|
|
2581
|
+
double min_abs_lower = kHighsInf;
|
|
2582
|
+
double max_abs_lower = -1;
|
|
2583
|
+
double min_abs_upper = kHighsInf;
|
|
2584
|
+
double max_abs_upper = -1;
|
|
2585
|
+
for (HighsInt iVar = 0; iVar < num_tot; iVar++) {
|
|
2586
|
+
double abs_lower = fabs(info_.workLower_[iVar]);
|
|
2587
|
+
double abs_upper = fabs(info_.workUpper_[iVar]);
|
|
2588
|
+
if (abs_lower && abs_lower < kHighsInf) {
|
|
2589
|
+
min_abs_lower = min(abs_lower, min_abs_lower);
|
|
2590
|
+
max_abs_lower = max(abs_lower, max_abs_lower);
|
|
2591
|
+
}
|
|
2592
|
+
if (abs_upper && abs_upper < kHighsInf) {
|
|
2593
|
+
min_abs_upper = min(abs_upper, min_abs_upper);
|
|
2594
|
+
max_abs_upper = max(abs_upper, max_abs_upper);
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
// printf(
|
|
2598
|
+
// "Nonzero finite lower bounds in [%9.4g, %9.4g]; upper bounds in "
|
|
2599
|
+
// "[%9.4g, %9.4g]\n",
|
|
2600
|
+
// min_abs_lower, max_abs_lower, min_abs_upper, max_abs_upper);
|
|
2601
|
+
|
|
2602
|
+
const double base =
|
|
2603
|
+
info_.primal_simplex_bound_perturbation_multiplier * 5e-7;
|
|
2604
|
+
for (HighsInt iVar = 0; iVar < num_tot; iVar++) {
|
|
2605
|
+
double lower = info_.workLower_[iVar];
|
|
2606
|
+
double upper = info_.workUpper_[iVar];
|
|
2607
|
+
const bool fixed = lower == upper;
|
|
2608
|
+
// Don't perturb bounds of nonbasic fixed variables as they stay nonbasic
|
|
2609
|
+
if (basis_.nonbasicFlag_[iVar] == kNonbasicFlagTrue && fixed) continue;
|
|
2610
|
+
double random_value = info_.numTotRandomValue_[iVar];
|
|
2611
|
+
if (lower > -kHighsInf) {
|
|
2612
|
+
if (lower < -1) {
|
|
2613
|
+
lower -= random_value * base * (-lower);
|
|
2614
|
+
} else if (lower < 1) {
|
|
2615
|
+
lower -= random_value * base;
|
|
2616
|
+
} else {
|
|
2617
|
+
lower -= random_value * base * lower;
|
|
2618
|
+
}
|
|
2619
|
+
info_.workLower_[iVar] = lower;
|
|
2620
|
+
}
|
|
2621
|
+
if (upper < kHighsInf) {
|
|
2622
|
+
if (upper < -1) {
|
|
2623
|
+
upper += random_value * base * (-upper);
|
|
2624
|
+
} else if (upper < 1) {
|
|
2625
|
+
upper += random_value * base;
|
|
2626
|
+
} else {
|
|
2627
|
+
upper += random_value * base * upper;
|
|
2628
|
+
}
|
|
2629
|
+
info_.workUpper_[iVar] = upper;
|
|
2630
|
+
}
|
|
2631
|
+
info_.workRange_[iVar] = info_.workUpper_[iVar] - info_.workLower_[iVar];
|
|
2632
|
+
if (basis_.nonbasicFlag_[iVar] == kNonbasicFlagFalse) continue;
|
|
2633
|
+
// Set values of nonbasic variables
|
|
2634
|
+
if (basis_.nonbasicMove_[iVar] > 0) {
|
|
2635
|
+
info_.workValue_[iVar] = lower;
|
|
2636
|
+
} else if (basis_.nonbasicMove_[iVar] < 0) {
|
|
2637
|
+
info_.workValue_[iVar] = upper;
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
2641
|
+
HighsInt iVar = basis_.basicIndex_[iRow];
|
|
2642
|
+
info_.baseLower_[iRow] = info_.workLower_[iVar];
|
|
2643
|
+
info_.baseUpper_[iRow] = info_.workUpper_[iVar];
|
|
2644
|
+
}
|
|
2645
|
+
info_.bounds_perturbed = true;
|
|
2646
|
+
return;
|
|
2647
|
+
}
|
|
2648
|
+
// Dual simplex bounds are either from the LP or set to special values in
|
|
2649
|
+
// phase
|
|
2650
|
+
// 1
|
|
2651
|
+
assert(algorithm == SimplexAlgorithm::kDual);
|
|
2652
|
+
if (solve_phase == kSolvePhase2) return;
|
|
2653
|
+
|
|
2654
|
+
// The dual objective is the sum of products of primal and dual
|
|
2655
|
+
// values for nonbasic variables. For dual simplex phase 1, the
|
|
2656
|
+
// primal bounds are set so that when the dual value is feasible, the
|
|
2657
|
+
// primal value is set to zero. Otherwise the value is +1/-1
|
|
2658
|
+
// according to the required sign of the dual, except for free
|
|
2659
|
+
// variables, where the bounds are [-1000, 1000]. Hence the dual
|
|
2660
|
+
// objective is the negation of the sum of infeasibilities, unless there are
|
|
2661
|
+
// free In Phase 1: change to dual phase 1 bound.
|
|
2662
|
+
const double inf = kHighsInf;
|
|
2663
|
+
const HighsInt num_tot = lp_.num_col_ + lp_.num_row_;
|
|
2664
|
+
for (HighsInt iCol = 0; iCol < num_tot; iCol++) {
|
|
2665
|
+
if (info_.workLower_[iCol] == -inf && info_.workUpper_[iCol] == inf) {
|
|
2666
|
+
// Phase 1 bounds were not modified for free rows in hsol. Why?
|
|
2667
|
+
// To reduce the number of free variables on the assumption that
|
|
2668
|
+
// free rows should never be nonbasic? This is normally true
|
|
2669
|
+
// when starting from a logical basis or crash - unless
|
|
2670
|
+
// singularity makes a free logical nonbasic - but what about an
|
|
2671
|
+
// advanced basis start? It doesn't happen with the HiGHS MIP
|
|
2672
|
+
// solver. However, SCIP cut handling can lead to a nonbasic row
|
|
2673
|
+
// with nonzero dual being made free and, particularly if it's
|
|
2674
|
+
// (then) the only dual infeasibility, phase 1 fails to remove
|
|
2675
|
+
// it.
|
|
2676
|
+
//
|
|
2677
|
+
// if (iCol >= lp_.num_col_) continue;
|
|
2678
|
+
info_.workLower_[iCol] = -1000,
|
|
2679
|
+
info_.workUpper_[iCol] = 1000; // FREE
|
|
2680
|
+
} else if (info_.workLower_[iCol] == -inf) {
|
|
2681
|
+
info_.workLower_[iCol] = -1,
|
|
2682
|
+
info_.workUpper_[iCol] = 0; // UPPER
|
|
2683
|
+
} else if (info_.workUpper_[iCol] == inf) {
|
|
2684
|
+
info_.workLower_[iCol] = 0,
|
|
2685
|
+
info_.workUpper_[iCol] = 1; // LOWER
|
|
2686
|
+
} else {
|
|
2687
|
+
info_.workLower_[iCol] = 0,
|
|
2688
|
+
info_.workUpper_[iCol] = 0; // BOXED or FIXED
|
|
2689
|
+
}
|
|
2690
|
+
info_.workRange_[iCol] = info_.workUpper_[iCol] - info_.workLower_[iCol];
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2694
|
+
void HEkk::initialiseLpColCost() {
|
|
2695
|
+
double cost_scale_factor = pow(2.0, options_->cost_scale_factor);
|
|
2696
|
+
for (HighsInt iCol = 0; iCol < lp_.num_col_; iCol++) {
|
|
2697
|
+
info_.workCost_[iCol] =
|
|
2698
|
+
(HighsInt)lp_.sense_ * cost_scale_factor * lp_.col_cost_[iCol];
|
|
2699
|
+
info_.workShift_[iCol] = 0;
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2703
|
+
void HEkk::initialiseLpRowCost() {
|
|
2704
|
+
for (HighsInt iCol = lp_.num_col_; iCol < lp_.num_col_ + lp_.num_row_;
|
|
2705
|
+
iCol++) {
|
|
2706
|
+
info_.workCost_[iCol] = 0;
|
|
2707
|
+
info_.workShift_[iCol] = 0;
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2711
|
+
void HEkk::initialiseNonbasicValueAndMove() {
|
|
2712
|
+
// Initialise workValue and nonbasicMove from nonbasicFlag and
|
|
2713
|
+
// bounds, except for boxed variables when nonbasicMove is used to
|
|
2714
|
+
// set workValue=workLower/workUpper
|
|
2715
|
+
const HighsInt num_tot = lp_.num_col_ + lp_.num_row_;
|
|
2716
|
+
for (HighsInt iVar = 0; iVar < num_tot; iVar++) {
|
|
2717
|
+
if (!basis_.nonbasicFlag_[iVar]) {
|
|
2718
|
+
// Basic variable
|
|
2719
|
+
basis_.nonbasicMove_[iVar] = kNonbasicMoveZe;
|
|
2720
|
+
continue;
|
|
2721
|
+
}
|
|
2722
|
+
// Nonbasic variable
|
|
2723
|
+
const double lower = info_.workLower_[iVar];
|
|
2724
|
+
const double upper = info_.workUpper_[iVar];
|
|
2725
|
+
const int8_t original_move = basis_.nonbasicMove_[iVar];
|
|
2726
|
+
double value;
|
|
2727
|
+
int8_t move = kIllegalMoveValue;
|
|
2728
|
+
if (lower == upper) {
|
|
2729
|
+
// Fixed
|
|
2730
|
+
value = lower;
|
|
2731
|
+
move = kNonbasicMoveZe;
|
|
2732
|
+
} else if (!highs_isInfinity(-lower)) {
|
|
2733
|
+
// Finite lower bound so boxed or lower
|
|
2734
|
+
if (!highs_isInfinity(upper)) {
|
|
2735
|
+
// Finite upper bound so boxed
|
|
2736
|
+
if (original_move == kNonbasicMoveUp) {
|
|
2737
|
+
// Set at lower
|
|
2738
|
+
value = lower;
|
|
2739
|
+
move = kNonbasicMoveUp;
|
|
2740
|
+
} else if (original_move == kNonbasicMoveDn) {
|
|
2741
|
+
// Set at upper
|
|
2742
|
+
value = upper;
|
|
2743
|
+
move = kNonbasicMoveDn;
|
|
2744
|
+
} else {
|
|
2745
|
+
// Invalid nonbasicMove: correct and set value at lower
|
|
2746
|
+
value = lower;
|
|
2747
|
+
move = kNonbasicMoveUp;
|
|
2748
|
+
}
|
|
2749
|
+
} else {
|
|
2750
|
+
// Lower
|
|
2751
|
+
value = lower;
|
|
2752
|
+
move = kNonbasicMoveUp;
|
|
2753
|
+
}
|
|
2754
|
+
} else if (!highs_isInfinity(upper)) {
|
|
2755
|
+
// Upper
|
|
2756
|
+
value = upper;
|
|
2757
|
+
move = kNonbasicMoveDn;
|
|
2758
|
+
} else {
|
|
2759
|
+
// FREE
|
|
2760
|
+
value = 0;
|
|
2761
|
+
move = kNonbasicMoveZe;
|
|
2762
|
+
}
|
|
2763
|
+
assert(move != kIllegalMoveValue);
|
|
2764
|
+
basis_.nonbasicMove_[iVar] = move;
|
|
2765
|
+
info_.workValue_[iVar] = value;
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
void HEkk::pivotColumnFtran(const HighsInt iCol, HVector& col_aq) {
|
|
2770
|
+
analysis_.simplexTimerStart(FtranClock);
|
|
2771
|
+
col_aq.clear();
|
|
2772
|
+
col_aq.packFlag = true;
|
|
2773
|
+
lp_.a_matrix_.collectAj(col_aq, iCol, 1);
|
|
2774
|
+
if (analysis_.analyse_simplex_summary_data)
|
|
2775
|
+
analysis_.operationRecordBefore(kSimplexNlaFtran, col_aq,
|
|
2776
|
+
info_.col_aq_density);
|
|
2777
|
+
simplex_nla_.ftran(col_aq, info_.col_aq_density,
|
|
2778
|
+
analysis_.pointer_serial_factor_clocks);
|
|
2779
|
+
if (analysis_.analyse_simplex_summary_data)
|
|
2780
|
+
analysis_.operationRecordAfter(kSimplexNlaFtran, col_aq);
|
|
2781
|
+
HighsInt num_row = lp_.num_row_;
|
|
2782
|
+
const double local_col_aq_density = (double)col_aq.count / num_row;
|
|
2783
|
+
updateOperationResultDensity(local_col_aq_density, info_.col_aq_density);
|
|
2784
|
+
analysis_.simplexTimerStop(FtranClock);
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
void HEkk::unitBtran(const HighsInt iRow, HVector& row_ep) {
|
|
2788
|
+
analysis_.simplexTimerStart(BtranClock);
|
|
2789
|
+
row_ep.clear();
|
|
2790
|
+
row_ep.count = 1;
|
|
2791
|
+
row_ep.index[0] = iRow;
|
|
2792
|
+
row_ep.array[iRow] = 1;
|
|
2793
|
+
row_ep.packFlag = true;
|
|
2794
|
+
if (analysis_.analyse_simplex_summary_data)
|
|
2795
|
+
analysis_.operationRecordBefore(kSimplexNlaBtranEp, row_ep,
|
|
2796
|
+
info_.row_ep_density);
|
|
2797
|
+
simplex_nla_.btran(row_ep, info_.row_ep_density,
|
|
2798
|
+
analysis_.pointer_serial_factor_clocks);
|
|
2799
|
+
if (analysis_.analyse_simplex_summary_data)
|
|
2800
|
+
analysis_.operationRecordAfter(kSimplexNlaBtranEp, row_ep);
|
|
2801
|
+
HighsInt num_row = lp_.num_row_;
|
|
2802
|
+
const double local_row_ep_density = (double)row_ep.count / num_row;
|
|
2803
|
+
updateOperationResultDensity(local_row_ep_density, info_.row_ep_density);
|
|
2804
|
+
analysis_.simplexTimerStop(BtranClock);
|
|
2805
|
+
}
|
|
2806
|
+
|
|
2807
|
+
void HEkk::fullBtran(HVector& buffer) {
|
|
2808
|
+
// Performs BTRAN on the buffer supplied. Make sure that
|
|
2809
|
+
// buffer.count is large (>lp_.num_row_ to be sure) rather
|
|
2810
|
+
// than 0 if the indices of the RHS (and true value of buffer.count)
|
|
2811
|
+
// isn't known.
|
|
2812
|
+
analysis_.simplexTimerStart(BtranFullClock);
|
|
2813
|
+
if (analysis_.analyse_simplex_summary_data)
|
|
2814
|
+
analysis_.operationRecordBefore(kSimplexNlaBtranFull, buffer,
|
|
2815
|
+
info_.dual_col_density);
|
|
2816
|
+
simplex_nla_.btran(buffer, info_.dual_col_density,
|
|
2817
|
+
analysis_.pointer_serial_factor_clocks);
|
|
2818
|
+
if (analysis_.analyse_simplex_summary_data)
|
|
2819
|
+
analysis_.operationRecordAfter(kSimplexNlaBtranFull, buffer);
|
|
2820
|
+
const double local_dual_col_density = (double)buffer.count / lp_.num_row_;
|
|
2821
|
+
updateOperationResultDensity(local_dual_col_density, info_.dual_col_density);
|
|
2822
|
+
analysis_.simplexTimerStop(BtranFullClock);
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
void HEkk::choosePriceTechnique(const HighsInt price_strategy,
|
|
2826
|
+
const double row_ep_density,
|
|
2827
|
+
bool& use_col_price,
|
|
2828
|
+
bool& use_row_price_w_switch) const {
|
|
2829
|
+
// By default switch to column PRICE when pi_p has at least this
|
|
2830
|
+
// density
|
|
2831
|
+
const double density_for_column_price_switch = 0.75;
|
|
2832
|
+
use_col_price = (price_strategy == kSimplexPriceStrategyCol) ||
|
|
2833
|
+
(price_strategy == kSimplexPriceStrategyRowSwitchColSwitch &&
|
|
2834
|
+
row_ep_density > density_for_column_price_switch);
|
|
2835
|
+
use_row_price_w_switch =
|
|
2836
|
+
price_strategy == kSimplexPriceStrategyRowSwitch ||
|
|
2837
|
+
price_strategy == kSimplexPriceStrategyRowSwitchColSwitch;
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
void HEkk::tableauRowPrice(const bool quad_precision, const HVector& row_ep,
|
|
2841
|
+
HVector& row_ap, const HighsInt debug_report) {
|
|
2842
|
+
analysis_.simplexTimerStart(PriceClock);
|
|
2843
|
+
const HighsInt solver_num_row = lp_.num_row_;
|
|
2844
|
+
const HighsInt solver_num_col = lp_.num_col_;
|
|
2845
|
+
const double local_density = 1.0 * row_ep.count / solver_num_row;
|
|
2846
|
+
bool use_col_price;
|
|
2847
|
+
bool use_row_price_w_switch;
|
|
2848
|
+
choosePriceTechnique(info_.price_strategy, local_density, use_col_price,
|
|
2849
|
+
use_row_price_w_switch);
|
|
2850
|
+
if (analysis_.analyse_simplex_summary_data) {
|
|
2851
|
+
if (use_col_price) {
|
|
2852
|
+
const double expected_density = 1;
|
|
2853
|
+
analysis_.operationRecordBefore(kSimplexNlaPriceAp, row_ep,
|
|
2854
|
+
expected_density);
|
|
2855
|
+
analysis_.num_col_price++;
|
|
2856
|
+
} else if (use_row_price_w_switch) {
|
|
2857
|
+
analysis_.operationRecordBefore(kSimplexNlaPriceAp, row_ep,
|
|
2858
|
+
info_.row_ep_density);
|
|
2859
|
+
analysis_.num_row_price_with_switch++;
|
|
2860
|
+
} else {
|
|
2861
|
+
analysis_.operationRecordBefore(kSimplexNlaPriceAp, row_ep,
|
|
2862
|
+
info_.row_ep_density);
|
|
2863
|
+
analysis_.num_row_price++;
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
row_ap.clear();
|
|
2867
|
+
if (use_col_price) {
|
|
2868
|
+
// Perform column-wise PRICE
|
|
2869
|
+
lp_.a_matrix_.priceByColumn(quad_precision, row_ap, row_ep, debug_report);
|
|
2870
|
+
} else if (use_row_price_w_switch) {
|
|
2871
|
+
// Perform hyper-sparse row-wise PRICE, but switch if the density of row_ap
|
|
2872
|
+
// becomes extreme
|
|
2873
|
+
const double switch_density = kHyperPriceDensity;
|
|
2874
|
+
ar_matrix_.priceByRowWithSwitch(quad_precision, row_ap, row_ep,
|
|
2875
|
+
info_.row_ap_density, 0, switch_density,
|
|
2876
|
+
debug_report);
|
|
2877
|
+
} else {
|
|
2878
|
+
// Perform hyper-sparse row-wise PRICE
|
|
2879
|
+
ar_matrix_.priceByRow(quad_precision, row_ap, row_ep, debug_report);
|
|
2880
|
+
}
|
|
2881
|
+
if (use_col_price) {
|
|
2882
|
+
// Column-wise PRICE computes components corresponding to basic
|
|
2883
|
+
// variables, so zero these by exploiting the fact that, for basic
|
|
2884
|
+
// variables, nonbasicFlag[*]=0
|
|
2885
|
+
const int8_t* nonbasicFlag = basis_.nonbasicFlag_.data();
|
|
2886
|
+
for (HighsInt iCol = 0; iCol < solver_num_col; iCol++)
|
|
2887
|
+
row_ap.array[iCol] *= nonbasicFlag[iCol];
|
|
2888
|
+
}
|
|
2889
|
+
// Update the record of average row_ap density
|
|
2890
|
+
const double local_row_ap_density = (double)row_ap.count / solver_num_col;
|
|
2891
|
+
updateOperationResultDensity(local_row_ap_density, info_.row_ap_density);
|
|
2892
|
+
if (analysis_.analyse_simplex_summary_data)
|
|
2893
|
+
analysis_.operationRecordAfter(kSimplexNlaPriceAp, row_ap);
|
|
2894
|
+
analysis_.simplexTimerStop(PriceClock);
|
|
2895
|
+
}
|
|
2896
|
+
|
|
2897
|
+
void HEkk::fullPrice(const HVector& full_col, HVector& full_row) {
|
|
2898
|
+
analysis_.simplexTimerStart(PriceFullClock);
|
|
2899
|
+
full_row.clear();
|
|
2900
|
+
if (analysis_.analyse_simplex_summary_data) {
|
|
2901
|
+
const double expected_density = 1;
|
|
2902
|
+
analysis_.operationRecordBefore(kSimplexNlaPriceFull, full_col,
|
|
2903
|
+
expected_density);
|
|
2904
|
+
}
|
|
2905
|
+
const bool quad_precision = false;
|
|
2906
|
+
lp_.a_matrix_.priceByColumn(quad_precision, full_row, full_col);
|
|
2907
|
+
if (analysis_.analyse_simplex_summary_data)
|
|
2908
|
+
analysis_.operationRecordAfter(kSimplexNlaPriceFull, full_row);
|
|
2909
|
+
analysis_.simplexTimerStop(PriceFullClock);
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2912
|
+
void HEkk::computePrimal() {
|
|
2913
|
+
analysis_.simplexTimerStart(ComputePrimalClock);
|
|
2914
|
+
const HighsInt num_row = lp_.num_row_;
|
|
2915
|
+
const HighsInt num_col = lp_.num_col_;
|
|
2916
|
+
// Setup a local buffer for the values of basic variables
|
|
2917
|
+
HVector primal_col;
|
|
2918
|
+
primal_col.setup(num_row);
|
|
2919
|
+
primal_col.clear();
|
|
2920
|
+
for (HighsInt i = 0; i < num_col + num_row; i++) {
|
|
2921
|
+
if (basis_.nonbasicFlag_[i] && info_.workValue_[i] != 0) {
|
|
2922
|
+
lp_.a_matrix_.collectAj(primal_col, i, info_.workValue_[i]);
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
// It's possible that the buffer has no nonzeros, so performing
|
|
2926
|
+
// FTRAN is unnecessary. Not much of a saving, but the zero density
|
|
2927
|
+
// looks odd in the analysis!
|
|
2928
|
+
if (primal_col.count) {
|
|
2929
|
+
simplex_nla_.ftran(primal_col, info_.primal_col_density,
|
|
2930
|
+
analysis_.pointer_serial_factor_clocks);
|
|
2931
|
+
const double local_primal_col_density = (double)primal_col.count / num_row;
|
|
2932
|
+
updateOperationResultDensity(local_primal_col_density,
|
|
2933
|
+
info_.primal_col_density);
|
|
2934
|
+
}
|
|
2935
|
+
for (HighsInt i = 0; i < num_row; i++) {
|
|
2936
|
+
HighsInt iCol = basis_.basicIndex_[i];
|
|
2937
|
+
info_.baseValue_[i] = -primal_col.array[i];
|
|
2938
|
+
info_.baseLower_[i] = info_.workLower_[iCol];
|
|
2939
|
+
info_.baseUpper_[i] = info_.workUpper_[iCol];
|
|
2940
|
+
}
|
|
2941
|
+
// Indicate that the primal infeasibility information isn't known
|
|
2942
|
+
info_.num_primal_infeasibilities = kHighsIllegalInfeasibilityCount;
|
|
2943
|
+
info_.max_primal_infeasibility = kHighsIllegalInfeasibilityMeasure;
|
|
2944
|
+
info_.sum_primal_infeasibilities = kHighsIllegalInfeasibilityMeasure;
|
|
2945
|
+
|
|
2946
|
+
analysis_.simplexTimerStop(ComputePrimalClock);
|
|
2947
|
+
}
|
|
2948
|
+
|
|
2949
|
+
void HEkk::computeDual() {
|
|
2950
|
+
analysis_.simplexTimerStart(ComputeDualClock);
|
|
2951
|
+
// Create a local buffer for the pi vector
|
|
2952
|
+
HVector dual_col;
|
|
2953
|
+
dual_col.setup(lp_.num_row_);
|
|
2954
|
+
dual_col.clear();
|
|
2955
|
+
for (HighsInt iRow = 0; iRow < lp_.num_row_; iRow++) {
|
|
2956
|
+
const double value = info_.workCost_[basis_.basicIndex_[iRow]] +
|
|
2957
|
+
info_.workShift_[basis_.basicIndex_[iRow]];
|
|
2958
|
+
if (value) {
|
|
2959
|
+
dual_col.index[dual_col.count++] = iRow;
|
|
2960
|
+
dual_col.array[iRow] = value;
|
|
2961
|
+
}
|
|
2962
|
+
}
|
|
2963
|
+
// If debugging, save the current duals
|
|
2964
|
+
const bool debug_compute_dual = false;
|
|
2965
|
+
if (debug_compute_dual) {
|
|
2966
|
+
debugComputeDual(true);
|
|
2967
|
+
debugSimplexDualInfeasible("(old duals)", true);
|
|
2968
|
+
}
|
|
2969
|
+
// Copy the costs in case the basic costs are all zero
|
|
2970
|
+
const HighsInt num_tot = lp_.num_col_ + lp_.num_row_;
|
|
2971
|
+
for (HighsInt i = 0; i < num_tot; i++)
|
|
2972
|
+
info_.workDual_[i] = info_.workCost_[i] + info_.workShift_[i];
|
|
2973
|
+
|
|
2974
|
+
if (dual_col.count) {
|
|
2975
|
+
fullBtran(dual_col);
|
|
2976
|
+
// Create a local buffer for the values of reduced costs
|
|
2977
|
+
HVector dual_row;
|
|
2978
|
+
dual_row.setup(lp_.num_col_);
|
|
2979
|
+
fullPrice(dual_col, dual_row);
|
|
2980
|
+
for (HighsInt i = 0; i < lp_.num_col_; i++)
|
|
2981
|
+
info_.workDual_[i] -= dual_row.array[i];
|
|
2982
|
+
for (HighsInt i = lp_.num_col_; i < num_tot; i++)
|
|
2983
|
+
info_.workDual_[i] -= dual_col.array[i - lp_.num_col_];
|
|
2984
|
+
if (debug_compute_dual) {
|
|
2985
|
+
debugComputeDual();
|
|
2986
|
+
debugSimplexDualInfeasible("(new duals)", true);
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
// Indicate that the dual infeasibility information isn't known
|
|
2990
|
+
info_.num_dual_infeasibilities = kHighsIllegalInfeasibilityCount;
|
|
2991
|
+
info_.max_dual_infeasibility = kHighsIllegalInfeasibilityMeasure;
|
|
2992
|
+
info_.sum_dual_infeasibilities = kHighsIllegalInfeasibilityMeasure;
|
|
2993
|
+
|
|
2994
|
+
analysis_.simplexTimerStop(ComputeDualClock);
|
|
2995
|
+
}
|
|
2996
|
+
|
|
2997
|
+
double HEkk::computeDualForTableauColumn(const HighsInt iVar,
|
|
2998
|
+
const HVector& tableau_column) const {
|
|
2999
|
+
const vector<double>& workCost = info_.workCost_;
|
|
3000
|
+
const vector<HighsInt>& basicIndex = basis_.basicIndex_;
|
|
3001
|
+
|
|
3002
|
+
double dual = info_.workCost_[iVar];
|
|
3003
|
+
for (HighsInt i = 0; i < tableau_column.count; i++) {
|
|
3004
|
+
HighsInt iRow = tableau_column.index[i];
|
|
3005
|
+
dual -= tableau_column.array[iRow] * workCost[basicIndex[iRow]];
|
|
3006
|
+
}
|
|
3007
|
+
return dual;
|
|
3008
|
+
}
|
|
3009
|
+
|
|
3010
|
+
bool HEkk::reinvertOnNumericalTrouble(
|
|
3011
|
+
const std::string method_name, double& numerical_trouble_measure,
|
|
3012
|
+
const double alpha_from_col, const double alpha_from_row,
|
|
3013
|
+
const double numerical_trouble_tolerance) {
|
|
3014
|
+
double abs_alpha_from_col = fabs(alpha_from_col);
|
|
3015
|
+
double abs_alpha_from_row = fabs(alpha_from_row);
|
|
3016
|
+
double min_abs_alpha = min(abs_alpha_from_col, abs_alpha_from_row);
|
|
3017
|
+
double abs_alpha_diff = fabs(abs_alpha_from_col - abs_alpha_from_row);
|
|
3018
|
+
numerical_trouble_measure = abs_alpha_diff / min_abs_alpha;
|
|
3019
|
+
const HighsInt update_count = info_.update_count;
|
|
3020
|
+
// Reinvert if the relative difference is large enough, and updates have been
|
|
3021
|
+
// performed
|
|
3022
|
+
const bool numerical_trouble =
|
|
3023
|
+
numerical_trouble_measure > numerical_trouble_tolerance;
|
|
3024
|
+
const bool reinvert = numerical_trouble && update_count > 0;
|
|
3025
|
+
debugReportReinvertOnNumericalTrouble(method_name, numerical_trouble_measure,
|
|
3026
|
+
alpha_from_col, alpha_from_row,
|
|
3027
|
+
numerical_trouble_tolerance, reinvert);
|
|
3028
|
+
if (reinvert) {
|
|
3029
|
+
// Consider increasing the Markowitz multiplier
|
|
3030
|
+
const double current_pivot_threshold = info_.factor_pivot_threshold;
|
|
3031
|
+
double new_pivot_threshold = 0;
|
|
3032
|
+
if (current_pivot_threshold < kDefaultPivotThreshold) {
|
|
3033
|
+
// Threshold is below default value, so increase it
|
|
3034
|
+
new_pivot_threshold =
|
|
3035
|
+
min(current_pivot_threshold * kPivotThresholdChangeFactor,
|
|
3036
|
+
kDefaultPivotThreshold);
|
|
3037
|
+
} else if (current_pivot_threshold < kMaxPivotThreshold) {
|
|
3038
|
+
// Threshold is below max value, so increase it if few updates have been
|
|
3039
|
+
// performed
|
|
3040
|
+
if (update_count < 10)
|
|
3041
|
+
new_pivot_threshold =
|
|
3042
|
+
min(current_pivot_threshold * kPivotThresholdChangeFactor,
|
|
3043
|
+
kMaxPivotThreshold);
|
|
3044
|
+
}
|
|
3045
|
+
if (new_pivot_threshold) {
|
|
3046
|
+
highsLogUser(options_->log_options, HighsLogType::kWarning,
|
|
3047
|
+
" Increasing Markowitz threshold to %g\n",
|
|
3048
|
+
new_pivot_threshold);
|
|
3049
|
+
info_.factor_pivot_threshold = new_pivot_threshold;
|
|
3050
|
+
simplex_nla_.setPivotThreshold(new_pivot_threshold);
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3053
|
+
return reinvert;
|
|
3054
|
+
}
|
|
3055
|
+
|
|
3056
|
+
// The major model updates. Factor calls factor_.update; Matrix
|
|
3057
|
+
// calls matrix_.update; updatePivots does everything---and is
|
|
3058
|
+
// called from the likes of HDual::updatePivots
|
|
3059
|
+
void HEkk::transformForUpdate(HVector* column, HVector* row_ep,
|
|
3060
|
+
const HighsInt variable_in, HighsInt* row_out) {
|
|
3061
|
+
simplex_nla_.transformForUpdate(column, row_ep, variable_in, *row_out);
|
|
3062
|
+
}
|
|
3063
|
+
|
|
3064
|
+
void HEkk::flipBound(const HighsInt iCol) {
|
|
3065
|
+
const int8_t move = basis_.nonbasicMove_[iCol] = -basis_.nonbasicMove_[iCol];
|
|
3066
|
+
info_.workValue_[iCol] =
|
|
3067
|
+
move == 1 ? info_.workLower_[iCol] : info_.workUpper_[iCol];
|
|
3068
|
+
}
|
|
3069
|
+
|
|
3070
|
+
void HEkk::updateFactor(HVector* column, HVector* row_ep, HighsInt* iRow,
|
|
3071
|
+
HighsInt* hint) {
|
|
3072
|
+
analysis_.simplexTimerStart(UpdateFactorClock);
|
|
3073
|
+
simplex_nla_.update(column, row_ep, iRow, hint);
|
|
3074
|
+
// Now have a representation of B^{-1}, but it is not fresh
|
|
3075
|
+
status_.has_invert = true;
|
|
3076
|
+
if (info_.update_count >= info_.update_limit)
|
|
3077
|
+
*hint = kRebuildReasonUpdateLimitReached;
|
|
3078
|
+
|
|
3079
|
+
// Determine whether to reinvert based on the synthetic clock
|
|
3080
|
+
bool reinvert_syntheticClock =
|
|
3081
|
+
this->total_synthetic_tick_ >= this->build_synthetic_tick_;
|
|
3082
|
+
const bool performed_min_updates =
|
|
3083
|
+
info_.update_count >= kSyntheticTickReinversionMinUpdateCount;
|
|
3084
|
+
if (reinvert_syntheticClock && performed_min_updates)
|
|
3085
|
+
*hint = kRebuildReasonSyntheticClockSaysInvert;
|
|
3086
|
+
analysis_.simplexTimerStop(UpdateFactorClock);
|
|
3087
|
+
// Use the next level down for the debug level, since the cost of
|
|
3088
|
+
// checking the INVERT every iteration is an order more expensive
|
|
3089
|
+
// than checking after factorization.
|
|
3090
|
+
HighsInt alt_debug_level = options_->highs_debug_level - 1;
|
|
3091
|
+
// Forced expensive debug for development work
|
|
3092
|
+
// if (debug_solve_report_) alt_debug_level = kHighsDebugLevelExpensive;
|
|
3093
|
+
HighsDebugStatus debug_status =
|
|
3094
|
+
debugNlaCheckInvert("HEkk::updateFactor", alt_debug_level);
|
|
3095
|
+
if (debug_status == HighsDebugStatus::kError) {
|
|
3096
|
+
*hint = kRebuildReasonPossiblySingularBasis;
|
|
3097
|
+
}
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
void HEkk::updatePivots(const HighsInt variable_in, const HighsInt row_out,
|
|
3101
|
+
const HighsInt move_out) {
|
|
3102
|
+
analysis_.simplexTimerStart(UpdatePivotsClock);
|
|
3103
|
+
HighsInt variable_out = basis_.basicIndex_[row_out];
|
|
3104
|
+
|
|
3105
|
+
// update hash value of basis
|
|
3106
|
+
HighsHashHelpers::sparse_inverse_combine(basis_.hash, variable_out);
|
|
3107
|
+
HighsHashHelpers::sparse_combine(basis_.hash, variable_in);
|
|
3108
|
+
visited_basis_.insert(basis_.hash);
|
|
3109
|
+
|
|
3110
|
+
// Incoming variable
|
|
3111
|
+
basis_.basicIndex_[row_out] = variable_in;
|
|
3112
|
+
basis_.nonbasicFlag_[variable_in] = 0;
|
|
3113
|
+
basis_.nonbasicMove_[variable_in] = 0;
|
|
3114
|
+
info_.baseLower_[row_out] = info_.workLower_[variable_in];
|
|
3115
|
+
info_.baseUpper_[row_out] = info_.workUpper_[variable_in];
|
|
3116
|
+
|
|
3117
|
+
// Outgoing variable
|
|
3118
|
+
basis_.nonbasicFlag_[variable_out] = 1;
|
|
3119
|
+
if (info_.workLower_[variable_out] == info_.workUpper_[variable_out]) {
|
|
3120
|
+
info_.workValue_[variable_out] = info_.workLower_[variable_out];
|
|
3121
|
+
basis_.nonbasicMove_[variable_out] = 0;
|
|
3122
|
+
} else if (move_out == -1) {
|
|
3123
|
+
info_.workValue_[variable_out] = info_.workLower_[variable_out];
|
|
3124
|
+
basis_.nonbasicMove_[variable_out] = 1;
|
|
3125
|
+
} else {
|
|
3126
|
+
info_.workValue_[variable_out] = info_.workUpper_[variable_out];
|
|
3127
|
+
basis_.nonbasicMove_[variable_out] = -1;
|
|
3128
|
+
}
|
|
3129
|
+
// Update the dual objective value
|
|
3130
|
+
double nwValue = info_.workValue_[variable_out];
|
|
3131
|
+
double vrDual = info_.workDual_[variable_out];
|
|
3132
|
+
double dl_dual_objective_value = nwValue * vrDual;
|
|
3133
|
+
info_.updated_dual_objective_value += dl_dual_objective_value;
|
|
3134
|
+
info_.update_count++;
|
|
3135
|
+
// Update the number of basic logicals
|
|
3136
|
+
if (variable_out < lp_.num_col_) info_.num_basic_logicals++;
|
|
3137
|
+
if (variable_in < lp_.num_col_) info_.num_basic_logicals--;
|
|
3138
|
+
// No longer have a representation of B^{-1}, and certainly not
|
|
3139
|
+
// fresh!
|
|
3140
|
+
status_.has_invert = false;
|
|
3141
|
+
status_.has_fresh_invert = false;
|
|
3142
|
+
// Data are no longer fresh from rebuild
|
|
3143
|
+
status_.has_fresh_rebuild = false;
|
|
3144
|
+
analysis_.simplexTimerStop(UpdatePivotsClock);
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
bool HEkk::isBadBasisChange(const SimplexAlgorithm algorithm,
|
|
3148
|
+
const HighsInt variable_in, const HighsInt row_out,
|
|
3149
|
+
const HighsInt rebuild_reason) {
|
|
3150
|
+
if (rebuild_reason) return false;
|
|
3151
|
+
if (variable_in == -1 || row_out == -1) return false;
|
|
3152
|
+
uint64_t currhash = basis_.hash;
|
|
3153
|
+
HighsInt variable_out = basis_.basicIndex_[row_out];
|
|
3154
|
+
|
|
3155
|
+
HighsHashHelpers::sparse_inverse_combine(currhash, variable_out);
|
|
3156
|
+
HighsHashHelpers::sparse_combine(currhash, variable_in);
|
|
3157
|
+
|
|
3158
|
+
bool cycling_detected = false;
|
|
3159
|
+
const bool posible_cycling = visited_basis_.find(currhash) != nullptr;
|
|
3160
|
+
if (posible_cycling) {
|
|
3161
|
+
if (iteration_count_ == previous_iteration_cycling_detected + 1) {
|
|
3162
|
+
// Cycling detected on successive iterations suggests infinite cycling
|
|
3163
|
+
// highsLogDev(options_->log_options, HighsLogType::kWarning,
|
|
3164
|
+
// "Cycling detected in %s simplex:");
|
|
3165
|
+
// printf("Cycling detected in %s simplex solve %d (Iteration %d)",
|
|
3166
|
+
// algorithm == SimplexAlgorithm::kPrimal ? "primal" : "dual",
|
|
3167
|
+
// (int)debug_solve_call_num_, (int)iteration_count_);
|
|
3168
|
+
cycling_detected = true;
|
|
3169
|
+
} else {
|
|
3170
|
+
previous_iteration_cycling_detected = iteration_count_;
|
|
3171
|
+
}
|
|
3172
|
+
}
|
|
3173
|
+
if (cycling_detected) {
|
|
3174
|
+
if (algorithm == SimplexAlgorithm::kDual) {
|
|
3175
|
+
analysis_.num_dual_cycling_detections++;
|
|
3176
|
+
} else {
|
|
3177
|
+
analysis_.num_primal_cycling_detections++;
|
|
3178
|
+
}
|
|
3179
|
+
highsLogDev(options_->log_options, HighsLogType::kWarning,
|
|
3180
|
+
" basis change (%d out; %d in) is bad\n", (int)variable_out,
|
|
3181
|
+
(int)variable_in);
|
|
3182
|
+
addBadBasisChange(row_out, variable_out, variable_in,
|
|
3183
|
+
BadBasisChangeReason::kCycling, true);
|
|
3184
|
+
return true;
|
|
3185
|
+
} else {
|
|
3186
|
+
// Look to see whether this basis change is in the list of bad
|
|
3187
|
+
// ones
|
|
3188
|
+
for (auto& change : bad_basis_change_) {
|
|
3189
|
+
if (change.variable_out == variable_out &&
|
|
3190
|
+
change.variable_in == variable_in && change.row_out == row_out) {
|
|
3191
|
+
change.taboo = true;
|
|
3192
|
+
return true;
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3195
|
+
}
|
|
3196
|
+
|
|
3197
|
+
return false;
|
|
3198
|
+
}
|
|
3199
|
+
|
|
3200
|
+
void HEkk::updateMatrix(const HighsInt variable_in,
|
|
3201
|
+
const HighsInt variable_out) {
|
|
3202
|
+
analysis_.simplexTimerStart(UpdateMatrixClock);
|
|
3203
|
+
ar_matrix_.update(variable_in, variable_out, lp_.a_matrix_);
|
|
3204
|
+
// assert(ar_matrix_.debugPartitionOk(basis_.nonbasicFlag_.data()));
|
|
3205
|
+
analysis_.simplexTimerStop(UpdateMatrixClock);
|
|
3206
|
+
}
|
|
3207
|
+
|
|
3208
|
+
void HEkk::computeInfeasibilitiesForReporting(const SimplexAlgorithm algorithm,
|
|
3209
|
+
const HighsInt solve_phase) {
|
|
3210
|
+
if (algorithm == SimplexAlgorithm::kPrimal) {
|
|
3211
|
+
// Report the primal and dual infeasibilities
|
|
3212
|
+
computeSimplexInfeasible();
|
|
3213
|
+
} else {
|
|
3214
|
+
// Report the primal infeasibilities
|
|
3215
|
+
computeSimplexPrimalInfeasible();
|
|
3216
|
+
if (solve_phase == kSolvePhase1) {
|
|
3217
|
+
// In phase 1, report the simplex LP dual infeasibilities
|
|
3218
|
+
computeSimplexLpDualInfeasible();
|
|
3219
|
+
} else {
|
|
3220
|
+
// In phase 2, report the simplex dual infeasibilities
|
|
3221
|
+
computeSimplexDualInfeasible();
|
|
3222
|
+
}
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
|
|
3226
|
+
void HEkk::computeSimplexInfeasible() {
|
|
3227
|
+
computeSimplexPrimalInfeasible();
|
|
3228
|
+
computeSimplexDualInfeasible();
|
|
3229
|
+
}
|
|
3230
|
+
|
|
3231
|
+
void HEkk::computeSimplexPrimalInfeasible() {
|
|
3232
|
+
// Computes num/max/sum of primal infeasibilities according to the
|
|
3233
|
+
// simplex bounds. This is used to determine optimality in dual
|
|
3234
|
+
// phase 1 and dual phase 2, albeit using different bounds in
|
|
3235
|
+
// workLower/Upper.
|
|
3236
|
+
analysis_.simplexTimerStart(ComputePrIfsClock);
|
|
3237
|
+
const double scaled_primal_feasibility_tolerance =
|
|
3238
|
+
options_->primal_feasibility_tolerance;
|
|
3239
|
+
HighsInt& num_primal_infeasibility = info_.num_primal_infeasibilities;
|
|
3240
|
+
double& max_primal_infeasibility = info_.max_primal_infeasibility;
|
|
3241
|
+
double& sum_primal_infeasibility = info_.sum_primal_infeasibilities;
|
|
3242
|
+
num_primal_infeasibility = 0;
|
|
3243
|
+
max_primal_infeasibility = 0;
|
|
3244
|
+
sum_primal_infeasibility = 0;
|
|
3245
|
+
|
|
3246
|
+
for (HighsInt i = 0; i < lp_.num_col_ + lp_.num_row_; i++) {
|
|
3247
|
+
if (basis_.nonbasicFlag_[i]) {
|
|
3248
|
+
// Nonbasic column
|
|
3249
|
+
double value = info_.workValue_[i];
|
|
3250
|
+
double lower = info_.workLower_[i];
|
|
3251
|
+
double upper = info_.workUpper_[i];
|
|
3252
|
+
// @primal_infeasibility calculation
|
|
3253
|
+
double primal_infeasibility = 0;
|
|
3254
|
+
if (value < lower - scaled_primal_feasibility_tolerance) {
|
|
3255
|
+
primal_infeasibility = lower - value;
|
|
3256
|
+
} else if (value > upper + scaled_primal_feasibility_tolerance) {
|
|
3257
|
+
primal_infeasibility = value - upper;
|
|
3258
|
+
}
|
|
3259
|
+
if (primal_infeasibility > 0) {
|
|
3260
|
+
if (primal_infeasibility > scaled_primal_feasibility_tolerance)
|
|
3261
|
+
num_primal_infeasibility++;
|
|
3262
|
+
max_primal_infeasibility =
|
|
3263
|
+
std::max(primal_infeasibility, max_primal_infeasibility);
|
|
3264
|
+
sum_primal_infeasibility += primal_infeasibility;
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3267
|
+
}
|
|
3268
|
+
for (HighsInt i = 0; i < lp_.num_row_; i++) {
|
|
3269
|
+
// Basic variable
|
|
3270
|
+
double value = info_.baseValue_[i];
|
|
3271
|
+
double lower = info_.baseLower_[i];
|
|
3272
|
+
double upper = info_.baseUpper_[i];
|
|
3273
|
+
// @primal_infeasibility calculation
|
|
3274
|
+
double primal_infeasibility = 0;
|
|
3275
|
+
if (value < lower - scaled_primal_feasibility_tolerance) {
|
|
3276
|
+
primal_infeasibility = lower - value;
|
|
3277
|
+
} else if (value > upper + scaled_primal_feasibility_tolerance) {
|
|
3278
|
+
primal_infeasibility = value - upper;
|
|
3279
|
+
}
|
|
3280
|
+
if (primal_infeasibility > 0) {
|
|
3281
|
+
if (primal_infeasibility > scaled_primal_feasibility_tolerance)
|
|
3282
|
+
num_primal_infeasibility++;
|
|
3283
|
+
max_primal_infeasibility =
|
|
3284
|
+
std::max(primal_infeasibility, max_primal_infeasibility);
|
|
3285
|
+
sum_primal_infeasibility += primal_infeasibility;
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
analysis_.simplexTimerStop(ComputePrIfsClock);
|
|
3289
|
+
}
|
|
3290
|
+
|
|
3291
|
+
void HEkk::computeSimplexDualInfeasible() {
|
|
3292
|
+
analysis_.simplexTimerStart(ComputeDuIfsClock);
|
|
3293
|
+
// Computes num/max/sum of dual infeasibilities in phase 1 and phase
|
|
3294
|
+
// 2 according to nonbasicMove. The bounds are only used to identify
|
|
3295
|
+
// free variables. Fixed variables are assumed to have
|
|
3296
|
+
// nonbasicMove=0 so that no dual infeasibility is counted for them.
|
|
3297
|
+
const double scaled_dual_feasibility_tolerance =
|
|
3298
|
+
options_->dual_feasibility_tolerance;
|
|
3299
|
+
HighsInt& num_dual_infeasibility = info_.num_dual_infeasibilities;
|
|
3300
|
+
double& max_dual_infeasibility = info_.max_dual_infeasibility;
|
|
3301
|
+
double& sum_dual_infeasibility = info_.sum_dual_infeasibilities;
|
|
3302
|
+
num_dual_infeasibility = 0;
|
|
3303
|
+
max_dual_infeasibility = 0;
|
|
3304
|
+
sum_dual_infeasibility = 0;
|
|
3305
|
+
|
|
3306
|
+
for (HighsInt iCol = 0; iCol < lp_.num_col_ + lp_.num_row_; iCol++) {
|
|
3307
|
+
if (!basis_.nonbasicFlag_[iCol]) continue;
|
|
3308
|
+
// Nonbasic column
|
|
3309
|
+
const double dual = info_.workDual_[iCol];
|
|
3310
|
+
const double lower = info_.workLower_[iCol];
|
|
3311
|
+
const double upper = info_.workUpper_[iCol];
|
|
3312
|
+
double dual_infeasibility = 0;
|
|
3313
|
+
if (highs_isInfinity(-lower) && highs_isInfinity(upper)) {
|
|
3314
|
+
// Free: any nonzero dual value is infeasible
|
|
3315
|
+
dual_infeasibility = fabs(dual);
|
|
3316
|
+
} else {
|
|
3317
|
+
// Not free: any dual infeasibility is given by the dual value
|
|
3318
|
+
// signed by nonbasicMove
|
|
3319
|
+
dual_infeasibility = -basis_.nonbasicMove_[iCol] * dual;
|
|
3320
|
+
}
|
|
3321
|
+
if (dual_infeasibility > 0) {
|
|
3322
|
+
if (dual_infeasibility >= scaled_dual_feasibility_tolerance) {
|
|
3323
|
+
num_dual_infeasibility++;
|
|
3324
|
+
}
|
|
3325
|
+
max_dual_infeasibility =
|
|
3326
|
+
std::max(dual_infeasibility, max_dual_infeasibility);
|
|
3327
|
+
sum_dual_infeasibility += dual_infeasibility;
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3330
|
+
analysis_.simplexTimerStop(ComputeDuIfsClock);
|
|
3331
|
+
}
|
|
3332
|
+
|
|
3333
|
+
void HEkk::computeSimplexLpDualInfeasible() {
|
|
3334
|
+
// Compute num/max/sum of dual infeasibilities according to the
|
|
3335
|
+
// bounds of the simplex LP. Assumes that boxed variables have
|
|
3336
|
+
// primal variable at the bound corresponding to the sign of the
|
|
3337
|
+
// dual so should only be used in dual phase 1 - where it's only
|
|
3338
|
+
// used for reporting after rebuilds.
|
|
3339
|
+
const double scaled_dual_feasibility_tolerance =
|
|
3340
|
+
options_->dual_feasibility_tolerance;
|
|
3341
|
+
HighsInt& num_dual_infeasibility =
|
|
3342
|
+
analysis_.num_dual_phase_1_lp_dual_infeasibility;
|
|
3343
|
+
double& max_dual_infeasibility =
|
|
3344
|
+
analysis_.max_dual_phase_1_lp_dual_infeasibility;
|
|
3345
|
+
double& sum_dual_infeasibility =
|
|
3346
|
+
analysis_.sum_dual_phase_1_lp_dual_infeasibility;
|
|
3347
|
+
num_dual_infeasibility = 0;
|
|
3348
|
+
max_dual_infeasibility = 0;
|
|
3349
|
+
sum_dual_infeasibility = 0;
|
|
3350
|
+
|
|
3351
|
+
for (HighsInt iCol = 0; iCol < lp_.num_col_; iCol++) {
|
|
3352
|
+
HighsInt iVar = iCol;
|
|
3353
|
+
if (!basis_.nonbasicFlag_[iVar]) continue;
|
|
3354
|
+
// Nonbasic column
|
|
3355
|
+
const double dual = info_.workDual_[iVar];
|
|
3356
|
+
const double lower = lp_.col_lower_[iCol];
|
|
3357
|
+
const double upper = lp_.col_upper_[iCol];
|
|
3358
|
+
double dual_infeasibility = 0;
|
|
3359
|
+
if (highs_isInfinity(upper)) {
|
|
3360
|
+
if (highs_isInfinity(-lower)) {
|
|
3361
|
+
// Free: any nonzero dual value is infeasible
|
|
3362
|
+
dual_infeasibility = fabs(dual);
|
|
3363
|
+
} else {
|
|
3364
|
+
// Only lower bounded: a negative dual is infeasible
|
|
3365
|
+
dual_infeasibility = -dual;
|
|
3366
|
+
}
|
|
3367
|
+
} else {
|
|
3368
|
+
if (highs_isInfinity(-lower)) {
|
|
3369
|
+
// Only upper bounded: a positive dual is infeasible
|
|
3370
|
+
dual_infeasibility = dual;
|
|
3371
|
+
} else {
|
|
3372
|
+
// Boxed or fixed: any dual value is feasible
|
|
3373
|
+
dual_infeasibility = 0;
|
|
3374
|
+
}
|
|
3375
|
+
}
|
|
3376
|
+
if (dual_infeasibility > 0) {
|
|
3377
|
+
if (dual_infeasibility >= scaled_dual_feasibility_tolerance)
|
|
3378
|
+
num_dual_infeasibility++;
|
|
3379
|
+
max_dual_infeasibility =
|
|
3380
|
+
std::max(dual_infeasibility, max_dual_infeasibility);
|
|
3381
|
+
sum_dual_infeasibility += dual_infeasibility;
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
for (HighsInt iRow = 0; iRow < lp_.num_row_; iRow++) {
|
|
3385
|
+
HighsInt iVar = lp_.num_col_ + iRow;
|
|
3386
|
+
if (!basis_.nonbasicFlag_[iVar]) continue;
|
|
3387
|
+
// Nonbasic row
|
|
3388
|
+
const double dual = -info_.workDual_[iVar];
|
|
3389
|
+
const double lower = lp_.row_lower_[iRow];
|
|
3390
|
+
const double upper = lp_.row_upper_[iRow];
|
|
3391
|
+
double dual_infeasibility = 0;
|
|
3392
|
+
if (highs_isInfinity(upper)) {
|
|
3393
|
+
if (highs_isInfinity(-lower)) {
|
|
3394
|
+
// Free: any nonzero dual value is infeasible
|
|
3395
|
+
dual_infeasibility = fabs(dual);
|
|
3396
|
+
} else {
|
|
3397
|
+
// Only lower bounded: a negative dual is infeasible
|
|
3398
|
+
dual_infeasibility = -dual;
|
|
3399
|
+
}
|
|
3400
|
+
} else {
|
|
3401
|
+
if (highs_isInfinity(-lower)) {
|
|
3402
|
+
// Only upper bounded: a positive dual is infeasible
|
|
3403
|
+
dual_infeasibility = dual;
|
|
3404
|
+
} else {
|
|
3405
|
+
// Boxed or fixed: any dual value is feasible
|
|
3406
|
+
dual_infeasibility = 0;
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3409
|
+
if (dual_infeasibility > 0) {
|
|
3410
|
+
if (dual_infeasibility >= scaled_dual_feasibility_tolerance)
|
|
3411
|
+
num_dual_infeasibility++;
|
|
3412
|
+
max_dual_infeasibility =
|
|
3413
|
+
std::max(dual_infeasibility, max_dual_infeasibility);
|
|
3414
|
+
sum_dual_infeasibility += dual_infeasibility;
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
}
|
|
3418
|
+
|
|
3419
|
+
void HEkk::invalidatePrimalMaxSumInfeasibilityRecord() {
|
|
3420
|
+
info_.max_primal_infeasibility = kHighsIllegalInfeasibilityMeasure;
|
|
3421
|
+
info_.sum_primal_infeasibilities = kHighsIllegalInfeasibilityMeasure;
|
|
3422
|
+
}
|
|
3423
|
+
|
|
3424
|
+
void HEkk::invalidatePrimalInfeasibilityRecord() {
|
|
3425
|
+
info_.num_primal_infeasibilities = kHighsIllegalInfeasibilityCount;
|
|
3426
|
+
invalidatePrimalMaxSumInfeasibilityRecord();
|
|
3427
|
+
}
|
|
3428
|
+
|
|
3429
|
+
void HEkk::invalidateDualMaxSumInfeasibilityRecord() {
|
|
3430
|
+
info_.max_dual_infeasibility = kHighsIllegalInfeasibilityMeasure;
|
|
3431
|
+
info_.sum_dual_infeasibilities = kHighsIllegalInfeasibilityMeasure;
|
|
3432
|
+
}
|
|
3433
|
+
|
|
3434
|
+
void HEkk::invalidateDualInfeasibilityRecord() {
|
|
3435
|
+
info_.num_dual_infeasibilities = kHighsIllegalInfeasibilityCount;
|
|
3436
|
+
invalidateDualMaxSumInfeasibilityRecord();
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3439
|
+
bool HEkk::bailout() {
|
|
3440
|
+
if (solve_bailout_) {
|
|
3441
|
+
// Bailout has already been decided: check that it's for one of these
|
|
3442
|
+
// reasons
|
|
3443
|
+
assert(model_status_ == HighsModelStatus::kTimeLimit ||
|
|
3444
|
+
model_status_ == HighsModelStatus::kIterationLimit ||
|
|
3445
|
+
model_status_ == HighsModelStatus::kObjectiveBound ||
|
|
3446
|
+
model_status_ == HighsModelStatus::kObjectiveTarget);
|
|
3447
|
+
} else if (options_->time_limit < kHighsInf &&
|
|
3448
|
+
timer_->read() > options_->time_limit) {
|
|
3449
|
+
solve_bailout_ = true;
|
|
3450
|
+
model_status_ = HighsModelStatus::kTimeLimit;
|
|
3451
|
+
} else if (iteration_count_ >= options_->simplex_iteration_limit) {
|
|
3452
|
+
solve_bailout_ = true;
|
|
3453
|
+
model_status_ = HighsModelStatus::kIterationLimit;
|
|
3454
|
+
} else if (callback_->user_callback &&
|
|
3455
|
+
callback_->active[kCallbackSimplexInterrupt]) {
|
|
3456
|
+
callback_->clearHighsCallbackOutput();
|
|
3457
|
+
callback_->data_out.simplex_iteration_count = iteration_count_;
|
|
3458
|
+
if (callback_->callbackAction(kCallbackSimplexInterrupt,
|
|
3459
|
+
"Simplex interrupt")) {
|
|
3460
|
+
highsLogDev(options_->log_options, HighsLogType::kInfo,
|
|
3461
|
+
"User interrupt\n");
|
|
3462
|
+
solve_bailout_ = true;
|
|
3463
|
+
model_status_ = HighsModelStatus::kInterrupt;
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
return solve_bailout_;
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3469
|
+
HighsStatus HEkk::returnFromEkkSolve(const HighsStatus return_status) {
|
|
3470
|
+
if (analysis_.analyse_simplex_time)
|
|
3471
|
+
analysis_.simplexTimerStop(SimplexTotalClock);
|
|
3472
|
+
// Restore any modified development or timing settings and analyse
|
|
3473
|
+
// solver timing
|
|
3474
|
+
if (debug_solve_report_) debugReporting(1);
|
|
3475
|
+
if (time_report_) timeReporting(1);
|
|
3476
|
+
// Note that in timeReporting(1), analysis_.analyse_simplex_time
|
|
3477
|
+
// reverts to its value given by options_
|
|
3478
|
+
if (analysis_.analyse_simplex_time) analysis_.reportSimplexTimer();
|
|
3479
|
+
simplex_stats_.valid = true;
|
|
3480
|
+
// Since HEkk::iteration_count_ includes iteration on presolved LP,
|
|
3481
|
+
// simplex_stats_.iteration_count is initialised to -
|
|
3482
|
+
// HEkk::iteration_count_
|
|
3483
|
+
simplex_stats_.iteration_count += iteration_count_;
|
|
3484
|
+
// simplex_stats_.num_invert is incremented internally
|
|
3485
|
+
simplex_stats_.last_invert_num_el = simplex_nla_.factor_.invert_num_el;
|
|
3486
|
+
simplex_stats_.last_factored_basis_num_el =
|
|
3487
|
+
simplex_nla_.factor_.basis_matrix_num_el;
|
|
3488
|
+
simplex_stats_.col_aq_density = analysis_.col_aq_density;
|
|
3489
|
+
simplex_stats_.row_ep_density = analysis_.row_ep_density;
|
|
3490
|
+
simplex_stats_.row_ap_density = analysis_.row_ap_density;
|
|
3491
|
+
simplex_stats_.row_DSE_density = analysis_.row_DSE_density;
|
|
3492
|
+
return return_status;
|
|
3493
|
+
}
|
|
3494
|
+
|
|
3495
|
+
HighsStatus HEkk::returnFromSolve(const HighsStatus return_status) {
|
|
3496
|
+
// Always called before returning from HEkkPrimal/Dual::solve()
|
|
3497
|
+
if (solve_bailout_) {
|
|
3498
|
+
// If bailout has already been decided: check that it's for one of
|
|
3499
|
+
// these reasons
|
|
3500
|
+
assert(model_status_ == HighsModelStatus::kTimeLimit ||
|
|
3501
|
+
model_status_ == HighsModelStatus::kIterationLimit ||
|
|
3502
|
+
model_status_ == HighsModelStatus::kObjectiveBound ||
|
|
3503
|
+
model_status_ == HighsModelStatus::kObjectiveTarget ||
|
|
3504
|
+
model_status_ == HighsModelStatus::kInterrupt);
|
|
3505
|
+
}
|
|
3506
|
+
// Check that returnFromSolve has not already been called: it should
|
|
3507
|
+
// be called exactly once per solve
|
|
3508
|
+
assert(!called_return_from_solve_);
|
|
3509
|
+
called_return_from_solve_ = true;
|
|
3510
|
+
info_.valid_backtracking_basis_ = false;
|
|
3511
|
+
|
|
3512
|
+
// Initialise the status of the primal and dual solutions
|
|
3513
|
+
return_primal_solution_status_ = kSolutionStatusNone;
|
|
3514
|
+
return_dual_solution_status_ = kSolutionStatusNone;
|
|
3515
|
+
// Nothing more is known about the solve after an error return
|
|
3516
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
3517
|
+
|
|
3518
|
+
// Check that an invert exists
|
|
3519
|
+
assert(status_.has_invert);
|
|
3520
|
+
|
|
3521
|
+
// Determine a primal and dual solution, removing the effects of
|
|
3522
|
+
// perturbations and shifts
|
|
3523
|
+
//
|
|
3524
|
+
// Unless the solution is optimal, invalidate the infeasibility data
|
|
3525
|
+
if (model_status_ != HighsModelStatus::kOptimal) {
|
|
3526
|
+
invalidatePrimalInfeasibilityRecord();
|
|
3527
|
+
invalidateDualInfeasibilityRecord();
|
|
3528
|
+
}
|
|
3529
|
+
// The simplex algorithm used on exit should be set
|
|
3530
|
+
assert(exit_algorithm_ != SimplexAlgorithm::kNone);
|
|
3531
|
+
switch (model_status_) {
|
|
3532
|
+
case HighsModelStatus::kOptimal: {
|
|
3533
|
+
if (info_.num_primal_infeasibilities) {
|
|
3534
|
+
// Optimal - but not to desired primal feasibility tolerance
|
|
3535
|
+
return_primal_solution_status_ = kSolutionStatusInfeasible;
|
|
3536
|
+
} else {
|
|
3537
|
+
return_primal_solution_status_ = kSolutionStatusFeasible;
|
|
3538
|
+
}
|
|
3539
|
+
if (info_.num_dual_infeasibilities) {
|
|
3540
|
+
// Optimal - but not to desired dual feasibility tolerance
|
|
3541
|
+
return_dual_solution_status_ = kSolutionStatusInfeasible;
|
|
3542
|
+
} else {
|
|
3543
|
+
return_dual_solution_status_ = kSolutionStatusFeasible;
|
|
3544
|
+
}
|
|
3545
|
+
break;
|
|
3546
|
+
}
|
|
3547
|
+
case HighsModelStatus::kInfeasible: {
|
|
3548
|
+
// Primal infeasibility has been identified in primal phase 1,
|
|
3549
|
+
// or proved in dual phase 2. There should be no primal
|
|
3550
|
+
// perturbations or shifts
|
|
3551
|
+
assert(!info_.bounds_shifted);
|
|
3552
|
+
assert(!info_.bounds_perturbed);
|
|
3553
|
+
if (exit_algorithm_ == SimplexAlgorithm::kPrimal) {
|
|
3554
|
+
// Reset the simplex costs and recompute duals after primal
|
|
3555
|
+
// phase 1
|
|
3556
|
+
initialiseCost(SimplexAlgorithm::kDual, kSolvePhase2);
|
|
3557
|
+
computeDual();
|
|
3558
|
+
}
|
|
3559
|
+
computeSimplexInfeasible();
|
|
3560
|
+
// Primal solution shouldn't be feasible
|
|
3561
|
+
assert(info_.num_primal_infeasibilities > 0);
|
|
3562
|
+
break;
|
|
3563
|
+
}
|
|
3564
|
+
case HighsModelStatus::kUnboundedOrInfeasible: {
|
|
3565
|
+
// Dual simplex has identified dual infeasibility in phase
|
|
3566
|
+
// 1. There should be no dual perturbations
|
|
3567
|
+
assert(exit_algorithm_ == SimplexAlgorithm::kDual);
|
|
3568
|
+
assert(!info_.costs_shifted);
|
|
3569
|
+
assert(!info_.costs_perturbed);
|
|
3570
|
+
// Reset the simplex bounds and recompute primals
|
|
3571
|
+
initialiseBound(SimplexAlgorithm::kDual, kSolvePhase2);
|
|
3572
|
+
computePrimal();
|
|
3573
|
+
computeSimplexInfeasible();
|
|
3574
|
+
// Dual solution shouldn't be feasible
|
|
3575
|
+
assert(info_.num_dual_infeasibilities > 0);
|
|
3576
|
+
break;
|
|
3577
|
+
}
|
|
3578
|
+
case HighsModelStatus::kUnbounded: {
|
|
3579
|
+
// Primal simplex has identified unboundedness in phase 2. There
|
|
3580
|
+
// should be no primal or dual perturbations
|
|
3581
|
+
assert(exit_algorithm_ == SimplexAlgorithm::kPrimal);
|
|
3582
|
+
assert(!info_.costs_shifted);
|
|
3583
|
+
assert(!info_.costs_perturbed);
|
|
3584
|
+
assert(!info_.bounds_shifted);
|
|
3585
|
+
assert(!info_.bounds_perturbed);
|
|
3586
|
+
computeSimplexInfeasible();
|
|
3587
|
+
// Primal solution should be feasible
|
|
3588
|
+
assert(info_.num_primal_infeasibilities == 0);
|
|
3589
|
+
break;
|
|
3590
|
+
}
|
|
3591
|
+
case HighsModelStatus::kObjectiveBound:
|
|
3592
|
+
case HighsModelStatus::kObjectiveTarget:
|
|
3593
|
+
case HighsModelStatus::kTimeLimit:
|
|
3594
|
+
case HighsModelStatus::kIterationLimit:
|
|
3595
|
+
case HighsModelStatus::kInterrupt:
|
|
3596
|
+
case HighsModelStatus::kUnknown: {
|
|
3597
|
+
// Simplex has failed to conclude a model property. Either it
|
|
3598
|
+
// has bailed out due to reaching the objective bound, target,
|
|
3599
|
+
// time, iteration limit or user interrupt, or it has not been
|
|
3600
|
+
// set (cycling is the only reason). Could happen anywhere.
|
|
3601
|
+
//
|
|
3602
|
+
// Reset the simplex bounds and recompute primals
|
|
3603
|
+
initialiseBound(SimplexAlgorithm::kDual, kSolvePhase2);
|
|
3604
|
+
initialiseNonbasicValueAndMove();
|
|
3605
|
+
computePrimal();
|
|
3606
|
+
// Reset the simplex costs and recompute duals
|
|
3607
|
+
initialiseCost(SimplexAlgorithm::kDual, kSolvePhase2);
|
|
3608
|
+
computeDual();
|
|
3609
|
+
computeSimplexInfeasible();
|
|
3610
|
+
break;
|
|
3611
|
+
}
|
|
3612
|
+
default: {
|
|
3613
|
+
highsLogDev(
|
|
3614
|
+
options_->log_options, HighsLogType::kError,
|
|
3615
|
+
"%s simplex solver returns status %s\n",
|
|
3616
|
+
exit_algorithm_ == SimplexAlgorithm::kPrimal ? "primal" : "dual",
|
|
3617
|
+
utilModelStatusToString(model_status_).c_str());
|
|
3618
|
+
return HighsStatus::kError;
|
|
3619
|
+
break;
|
|
3620
|
+
}
|
|
3621
|
+
}
|
|
3622
|
+
this->zeroBasicDuals();
|
|
3623
|
+
assert(info_.num_primal_infeasibilities >= 0);
|
|
3624
|
+
assert(info_.num_dual_infeasibilities >= 0);
|
|
3625
|
+
if (info_.num_primal_infeasibilities == 0) {
|
|
3626
|
+
return_primal_solution_status_ = kSolutionStatusFeasible;
|
|
3627
|
+
} else {
|
|
3628
|
+
return_primal_solution_status_ = kSolutionStatusInfeasible;
|
|
3629
|
+
}
|
|
3630
|
+
if (info_.num_dual_infeasibilities == 0) {
|
|
3631
|
+
return_dual_solution_status_ = kSolutionStatusFeasible;
|
|
3632
|
+
} else {
|
|
3633
|
+
return_dual_solution_status_ = kSolutionStatusInfeasible;
|
|
3634
|
+
}
|
|
3635
|
+
assert(debugNoShiftsOrPerturbations());
|
|
3636
|
+
computePrimalObjectiveValue();
|
|
3637
|
+
if (!options_->log_dev_level) {
|
|
3638
|
+
const bool force = true;
|
|
3639
|
+
analysis_.userInvertReport(force);
|
|
3640
|
+
}
|
|
3641
|
+
return return_status;
|
|
3642
|
+
}
|
|
3643
|
+
|
|
3644
|
+
double HEkk::computeBasisCondition(const HighsLp& lp, const bool exact,
|
|
3645
|
+
const bool report) const {
|
|
3646
|
+
HighsInt solver_num_row = lp.num_row_;
|
|
3647
|
+
HighsInt solver_num_col = lp.num_col_;
|
|
3648
|
+
vector<double> bs_cond_x;
|
|
3649
|
+
vector<double> bs_cond_y;
|
|
3650
|
+
vector<double> bs_cond_z;
|
|
3651
|
+
vector<double> bs_cond_w;
|
|
3652
|
+
HVector row_ep;
|
|
3653
|
+
row_ep.setup(solver_num_row);
|
|
3654
|
+
|
|
3655
|
+
const HighsInt* Astart = lp.a_matrix_.start_.data();
|
|
3656
|
+
const double* Avalue = lp.a_matrix_.value_.data();
|
|
3657
|
+
double exact_norm_Binv = 0;
|
|
3658
|
+
if (exact) {
|
|
3659
|
+
// Compute the exact norm of B^{-1}
|
|
3660
|
+
for (HighsInt r_n = 0; r_n < solver_num_row; r_n++) {
|
|
3661
|
+
row_ep.clear();
|
|
3662
|
+
row_ep.index[row_ep.count] = r_n;
|
|
3663
|
+
row_ep.array[r_n] = 1.0;
|
|
3664
|
+
row_ep.count++;
|
|
3665
|
+
row_ep.packFlag = false;
|
|
3666
|
+
simplex_nla_.ftran(row_ep, 0.1);
|
|
3667
|
+
assert(row_ep.count <= solver_num_row);
|
|
3668
|
+
double c_norm = 0.0;
|
|
3669
|
+
for (HighsInt iX = 0; iX < row_ep.count; iX++)
|
|
3670
|
+
c_norm += std::fabs(row_ep.array[row_ep.index[iX]]);
|
|
3671
|
+
exact_norm_Binv = std::max(c_norm, exact_norm_Binv);
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
// Compute the Hager condition number estimate for the basis matrix
|
|
3675
|
+
const double expected_density = 1;
|
|
3676
|
+
bs_cond_x.resize(solver_num_row);
|
|
3677
|
+
bs_cond_y.resize(solver_num_row);
|
|
3678
|
+
bs_cond_z.resize(solver_num_row);
|
|
3679
|
+
bs_cond_w.resize(solver_num_row);
|
|
3680
|
+
// x = ones(n,1)/n;
|
|
3681
|
+
// y = A\x;
|
|
3682
|
+
double mu = 1.0 / solver_num_row;
|
|
3683
|
+
double norm_Binv = 0;
|
|
3684
|
+
for (HighsInt r_n = 0; r_n < solver_num_row; r_n++) bs_cond_x[r_n] = mu;
|
|
3685
|
+
row_ep.clear();
|
|
3686
|
+
for (HighsInt r_n = 0; r_n < solver_num_row; r_n++) {
|
|
3687
|
+
double value = bs_cond_x[r_n];
|
|
3688
|
+
if (value) {
|
|
3689
|
+
row_ep.index[row_ep.count] = r_n;
|
|
3690
|
+
row_ep.array[r_n] = value;
|
|
3691
|
+
row_ep.count++;
|
|
3692
|
+
}
|
|
3693
|
+
}
|
|
3694
|
+
for (HighsInt ps_n = 1; ps_n <= 5; ps_n++) {
|
|
3695
|
+
row_ep.packFlag = false;
|
|
3696
|
+
simplex_nla_.ftran(row_ep, expected_density);
|
|
3697
|
+
|
|
3698
|
+
// zeta = sign(y);
|
|
3699
|
+
for (HighsInt r_n = 0; r_n < solver_num_row; r_n++) {
|
|
3700
|
+
bs_cond_y[r_n] = row_ep.array[r_n];
|
|
3701
|
+
if (bs_cond_y[r_n] > 0)
|
|
3702
|
+
bs_cond_w[r_n] = 1.0;
|
|
3703
|
+
else if (bs_cond_y[r_n] < 0)
|
|
3704
|
+
bs_cond_w[r_n] = -1.0;
|
|
3705
|
+
else
|
|
3706
|
+
bs_cond_w[r_n] = 0.0;
|
|
3707
|
+
}
|
|
3708
|
+
// z=A'\zeta;
|
|
3709
|
+
row_ep.clear();
|
|
3710
|
+
for (HighsInt r_n = 0; r_n < solver_num_row; r_n++) {
|
|
3711
|
+
double value = bs_cond_w[r_n];
|
|
3712
|
+
if (value) {
|
|
3713
|
+
row_ep.index[row_ep.count] = r_n;
|
|
3714
|
+
row_ep.array[r_n] = value;
|
|
3715
|
+
row_ep.count++;
|
|
3716
|
+
}
|
|
3717
|
+
}
|
|
3718
|
+
row_ep.packFlag = false;
|
|
3719
|
+
simplex_nla_.btran(row_ep, expected_density);
|
|
3720
|
+
double norm_z = 0.0;
|
|
3721
|
+
double ztx = 0.0;
|
|
3722
|
+
norm_Binv = 0.0;
|
|
3723
|
+
HighsInt argmax_z = -1;
|
|
3724
|
+
for (HighsInt r_n = 0; r_n < solver_num_row; r_n++) {
|
|
3725
|
+
bs_cond_z[r_n] = row_ep.array[r_n];
|
|
3726
|
+
double abs_z_v = fabs(bs_cond_z[r_n]);
|
|
3727
|
+
if (abs_z_v > norm_z) {
|
|
3728
|
+
norm_z = abs_z_v;
|
|
3729
|
+
argmax_z = r_n;
|
|
3730
|
+
}
|
|
3731
|
+
ztx += bs_cond_z[r_n] * bs_cond_x[r_n];
|
|
3732
|
+
norm_Binv += fabs(bs_cond_y[r_n]);
|
|
3733
|
+
}
|
|
3734
|
+
if (norm_z <= ztx) break;
|
|
3735
|
+
// x = zeros(n,1);
|
|
3736
|
+
// x(fd_i) = 1;
|
|
3737
|
+
for (HighsInt r_n = 0; r_n < solver_num_row; r_n++) bs_cond_x[r_n] = 0.0;
|
|
3738
|
+
row_ep.clear();
|
|
3739
|
+
row_ep.count = 1;
|
|
3740
|
+
row_ep.index[0] = argmax_z;
|
|
3741
|
+
row_ep.array[argmax_z] = 1.0;
|
|
3742
|
+
bs_cond_x[argmax_z] = 1.0;
|
|
3743
|
+
}
|
|
3744
|
+
double norm_B = 0.0;
|
|
3745
|
+
for (HighsInt r_n = 0; r_n < solver_num_row; r_n++) {
|
|
3746
|
+
HighsInt vr_n = basis_.basicIndex_[r_n];
|
|
3747
|
+
double c_norm = 0.0;
|
|
3748
|
+
if (vr_n < solver_num_col)
|
|
3749
|
+
for (HighsInt el_n = Astart[vr_n]; el_n < Astart[vr_n + 1]; el_n++)
|
|
3750
|
+
c_norm += fabs(Avalue[el_n]);
|
|
3751
|
+
else
|
|
3752
|
+
c_norm += 1.0;
|
|
3753
|
+
norm_B = max(c_norm, norm_B);
|
|
3754
|
+
}
|
|
3755
|
+
double cond_B = norm_Binv * norm_B;
|
|
3756
|
+
double exact_cond_B = exact_norm_Binv * norm_B;
|
|
3757
|
+
if (exact) {
|
|
3758
|
+
assert(exact_norm_Binv > 0);
|
|
3759
|
+
if (report)
|
|
3760
|
+
highsLogUser(
|
|
3761
|
+
options_->log_options, HighsLogType::kInfo,
|
|
3762
|
+
"HEkk::computeBasisCondition: grep_kappa model,||B||_1,approx "
|
|
3763
|
+
"||B^{-1}||_1,approx_kappa,||B^{-1}||_1,kappa = ,%s,%g,%g,%g,%g,%g\n",
|
|
3764
|
+
lp.model_name_.c_str(), norm_B, norm_Binv, cond_B, exact_norm_Binv,
|
|
3765
|
+
exact_cond_B);
|
|
3766
|
+
return exact_cond_B;
|
|
3767
|
+
}
|
|
3768
|
+
return cond_B;
|
|
3769
|
+
}
|
|
3770
|
+
|
|
3771
|
+
void HEkk::initialiseAnalysis() {
|
|
3772
|
+
analysis_.setup(lp_name_, lp_, *options_, iteration_count_);
|
|
3773
|
+
}
|
|
3774
|
+
|
|
3775
|
+
std::string HEkk::rebuildReason(const HighsInt rebuild_reason) const {
|
|
3776
|
+
std::string rebuild_reason_string;
|
|
3777
|
+
if (rebuild_reason == kRebuildReasonCleanup) {
|
|
3778
|
+
rebuild_reason_string = "Perturbation cleanup";
|
|
3779
|
+
} else if (rebuild_reason == kRebuildReasonNo) {
|
|
3780
|
+
rebuild_reason_string = "No reason";
|
|
3781
|
+
} else if (rebuild_reason == kRebuildReasonUpdateLimitReached) {
|
|
3782
|
+
rebuild_reason_string = "Update limit reached";
|
|
3783
|
+
} else if (rebuild_reason == kRebuildReasonSyntheticClockSaysInvert) {
|
|
3784
|
+
rebuild_reason_string = "Synthetic clock";
|
|
3785
|
+
} else if (rebuild_reason == kRebuildReasonPossiblyOptimal) {
|
|
3786
|
+
rebuild_reason_string = "Possibly optimal";
|
|
3787
|
+
} else if (rebuild_reason == kRebuildReasonPossiblyPhase1Feasible) {
|
|
3788
|
+
rebuild_reason_string = "Possibly phase 1 feasible";
|
|
3789
|
+
} else if (rebuild_reason == kRebuildReasonPossiblyPrimalUnbounded) {
|
|
3790
|
+
rebuild_reason_string = "Possibly primal unbounded";
|
|
3791
|
+
} else if (rebuild_reason == kRebuildReasonPossiblyDualUnbounded) {
|
|
3792
|
+
rebuild_reason_string = "Possibly dual unbounded";
|
|
3793
|
+
} else if (rebuild_reason == kRebuildReasonPossiblySingularBasis) {
|
|
3794
|
+
rebuild_reason_string = "Possibly singular basis";
|
|
3795
|
+
} else if (rebuild_reason == kRebuildReasonPrimalInfeasibleInPrimalSimplex) {
|
|
3796
|
+
rebuild_reason_string = "Primal infeasible in primal simplex";
|
|
3797
|
+
} else if (rebuild_reason == kRebuildReasonChooseColumnFail) {
|
|
3798
|
+
rebuild_reason_string = "Choose column failure";
|
|
3799
|
+
} else {
|
|
3800
|
+
rebuild_reason_string = "Unidentified";
|
|
3801
|
+
assert(1 == 0);
|
|
3802
|
+
}
|
|
3803
|
+
return rebuild_reason_string;
|
|
3804
|
+
}
|
|
3805
|
+
|
|
3806
|
+
void HEkk::putIterate() {
|
|
3807
|
+
assert(this->status_.has_invert);
|
|
3808
|
+
SimplexIterate& iterate = this->simplex_nla_.simplex_iterate_;
|
|
3809
|
+
this->simplex_nla_.putInvert();
|
|
3810
|
+
iterate.basis_ = this->basis_;
|
|
3811
|
+
if (this->status_.has_dual_steepest_edge_weights) {
|
|
3812
|
+
// Copy the dual edge weights
|
|
3813
|
+
iterate.dual_edge_weight_ = this->dual_edge_weight_;
|
|
3814
|
+
} else {
|
|
3815
|
+
// Clear to indicate no weights
|
|
3816
|
+
iterate.dual_edge_weight_.clear();
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
|
|
3820
|
+
HighsStatus HEkk::getIterate() {
|
|
3821
|
+
SimplexIterate& iterate = this->simplex_nla_.simplex_iterate_;
|
|
3822
|
+
if (!iterate.valid_) return HighsStatus::kError;
|
|
3823
|
+
this->simplex_nla_.getInvert();
|
|
3824
|
+
this->basis_ = iterate.basis_;
|
|
3825
|
+
if (iterate.dual_edge_weight_.size()) {
|
|
3826
|
+
this->dual_edge_weight_ = iterate.dual_edge_weight_;
|
|
3827
|
+
} else {
|
|
3828
|
+
this->status_.has_dual_steepest_edge_weights = false;
|
|
3829
|
+
}
|
|
3830
|
+
this->status_.has_invert = true;
|
|
3831
|
+
return HighsStatus::kOk;
|
|
3832
|
+
}
|
|
3833
|
+
|
|
3834
|
+
double HEkk::factorSolveError() {
|
|
3835
|
+
// Cheap assessment of factor accuracy.
|
|
3836
|
+
//
|
|
3837
|
+
// Forms a random solution with at most 50 nonzeros, solves for
|
|
3838
|
+
// the corresponding RHS, and then checks the 50 solution values.
|
|
3839
|
+
const HighsInt num_col = this->lp_.num_col_;
|
|
3840
|
+
const HighsInt num_row = this->lp_.num_row_;
|
|
3841
|
+
const HighsSparseMatrix& a_matrix = this->lp_.a_matrix_;
|
|
3842
|
+
const vector<HighsInt>& basic_index = this->basis_.basicIndex_;
|
|
3843
|
+
const HighsSparseMatrix& ar_matrix = this->ar_matrix_;
|
|
3844
|
+
HVector btran_rhs;
|
|
3845
|
+
HVector ftran_rhs;
|
|
3846
|
+
btran_rhs.setup(num_row);
|
|
3847
|
+
ftran_rhs.setup(num_row);
|
|
3848
|
+
|
|
3849
|
+
// Solve for a random solution
|
|
3850
|
+
HighsRandom random(1);
|
|
3851
|
+
|
|
3852
|
+
ftran_rhs.clear();
|
|
3853
|
+
const HighsInt ideal_solution_num_nz = 50;
|
|
3854
|
+
HighsInt solution_num_nz = min(ideal_solution_num_nz, (num_row + 1) / 2);
|
|
3855
|
+
assert(solution_num_nz > 0);
|
|
3856
|
+
vector<double> solution_value;
|
|
3857
|
+
vector<HighsInt> solution_index;
|
|
3858
|
+
vector<int8_t> solution_nonzero;
|
|
3859
|
+
solution_nonzero.assign(num_row, 0);
|
|
3860
|
+
for (;;) {
|
|
3861
|
+
HighsInt iRow = random.integer(num_row);
|
|
3862
|
+
assert(iRow < num_row);
|
|
3863
|
+
if (solution_nonzero[iRow]) continue;
|
|
3864
|
+
double value = random.fraction();
|
|
3865
|
+
solution_value.push_back(value);
|
|
3866
|
+
solution_index.push_back(iRow);
|
|
3867
|
+
solution_nonzero[iRow] = 1;
|
|
3868
|
+
HighsInt iCol = basic_index[iRow];
|
|
3869
|
+
a_matrix.collectAj(ftran_rhs, iCol, value);
|
|
3870
|
+
if ((int)solution_value.size() == solution_num_nz) break;
|
|
3871
|
+
}
|
|
3872
|
+
|
|
3873
|
+
btran_rhs.clear();
|
|
3874
|
+
vector<double> btran_solution;
|
|
3875
|
+
btran_solution.assign(num_row, 0);
|
|
3876
|
+
for (size_t iX = 0; iX < solution_value.size(); iX++)
|
|
3877
|
+
btran_solution[solution_index[iX]] = solution_value[iX];
|
|
3878
|
+
vector<double> btran_scattered_rhs;
|
|
3879
|
+
btran_scattered_rhs.assign(num_col + num_row, 0);
|
|
3880
|
+
for (size_t iX = 0; iX < solution_value.size(); iX++) {
|
|
3881
|
+
HighsInt iRow = solution_index[iX];
|
|
3882
|
+
for (HighsInt iEl = ar_matrix.p_end_[iRow];
|
|
3883
|
+
iEl < ar_matrix.start_[iRow + 1]; iEl++) {
|
|
3884
|
+
HighsInt iCol = ar_matrix.index_[iEl];
|
|
3885
|
+
btran_scattered_rhs[iCol] += ar_matrix.value_[iEl] * solution_value[iX];
|
|
3886
|
+
}
|
|
3887
|
+
HighsInt iCol = num_col + iRow;
|
|
3888
|
+
if (this->basis_.nonbasicFlag_[iCol] == 0)
|
|
3889
|
+
btran_scattered_rhs[iCol] = solution_value[iX];
|
|
3890
|
+
}
|
|
3891
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
3892
|
+
HighsInt iCol = basic_index[iRow];
|
|
3893
|
+
if (btran_scattered_rhs[iCol] == 0) continue;
|
|
3894
|
+
btran_rhs.array[iRow] = btran_scattered_rhs[iCol];
|
|
3895
|
+
btran_rhs.index[btran_rhs.count++] = iRow;
|
|
3896
|
+
}
|
|
3897
|
+
|
|
3898
|
+
const double expected_density = solution_num_nz * info_.col_aq_density;
|
|
3899
|
+
ftran(ftran_rhs, expected_density);
|
|
3900
|
+
btran(btran_rhs, expected_density);
|
|
3901
|
+
|
|
3902
|
+
double ftran_solution_error = 0;
|
|
3903
|
+
for (size_t iX = 0; iX < solution_value.size(); iX++)
|
|
3904
|
+
ftran_solution_error =
|
|
3905
|
+
max(fabs(ftran_rhs.array[solution_index[iX]] - solution_value[iX]),
|
|
3906
|
+
ftran_solution_error);
|
|
3907
|
+
double btran_solution_error = 0;
|
|
3908
|
+
for (size_t iX = 0; iX < solution_value.size(); iX++)
|
|
3909
|
+
btran_solution_error =
|
|
3910
|
+
max(fabs(btran_rhs.array[solution_index[iX]] - solution_value[iX]),
|
|
3911
|
+
btran_solution_error);
|
|
3912
|
+
double solution_error = max(ftran_solution_error, btran_solution_error);
|
|
3913
|
+
return solution_error;
|
|
3914
|
+
}
|
|
3915
|
+
|
|
3916
|
+
void HEkk::clearBadBasisChange(const BadBasisChangeReason reason) {
|
|
3917
|
+
if (reason == BadBasisChangeReason::kAll) {
|
|
3918
|
+
bad_basis_change_.clear();
|
|
3919
|
+
} else {
|
|
3920
|
+
bad_basis_change_.erase(
|
|
3921
|
+
std::remove_if(
|
|
3922
|
+
bad_basis_change_.begin(), bad_basis_change_.end(),
|
|
3923
|
+
[reason](const HighsSimplexBadBasisChangeRecord& record) {
|
|
3924
|
+
return record.reason == reason;
|
|
3925
|
+
}),
|
|
3926
|
+
bad_basis_change_.end());
|
|
3927
|
+
}
|
|
3928
|
+
}
|
|
3929
|
+
|
|
3930
|
+
void HEkk::updateBadBasisChange(const HVector& col_aq, double theta_primal) {
|
|
3931
|
+
if (!bad_basis_change_.empty()) {
|
|
3932
|
+
bad_basis_change_.erase(
|
|
3933
|
+
std::remove_if(bad_basis_change_.begin(), bad_basis_change_.end(),
|
|
3934
|
+
[&](const HighsSimplexBadBasisChangeRecord& record) {
|
|
3935
|
+
return std::fabs(col_aq.array[record.row_out] *
|
|
3936
|
+
theta_primal) >=
|
|
3937
|
+
options_->primal_feasibility_tolerance;
|
|
3938
|
+
}),
|
|
3939
|
+
bad_basis_change_.end());
|
|
3940
|
+
}
|
|
3941
|
+
}
|
|
3942
|
+
|
|
3943
|
+
HighsInt HEkk::addBadBasisChange(const HighsInt row_out,
|
|
3944
|
+
const HighsInt variable_out,
|
|
3945
|
+
const HighsInt variable_in,
|
|
3946
|
+
const BadBasisChangeReason reason,
|
|
3947
|
+
const bool taboo) {
|
|
3948
|
+
assert(0 <= row_out && row_out <= lp_.num_row_);
|
|
3949
|
+
assert(0 <= variable_out && variable_out <= lp_.num_col_ + lp_.num_row_);
|
|
3950
|
+
if (variable_in >= 0) {
|
|
3951
|
+
assert(0 <= variable_in && variable_in <= lp_.num_col_ + lp_.num_row_);
|
|
3952
|
+
} else {
|
|
3953
|
+
assert(variable_in == -1);
|
|
3954
|
+
}
|
|
3955
|
+
// Check that this is not already on the list
|
|
3956
|
+
const HighsInt num_bad_basis_change = bad_basis_change_.size();
|
|
3957
|
+
HighsInt bad_basis_change_num = -1;
|
|
3958
|
+
for (HighsInt Ix = 0; Ix < num_bad_basis_change; Ix++) {
|
|
3959
|
+
HighsSimplexBadBasisChangeRecord& record = bad_basis_change_[Ix];
|
|
3960
|
+
if (record.row_out == row_out && record.variable_out == variable_out &&
|
|
3961
|
+
record.variable_in == variable_in && record.reason == reason) {
|
|
3962
|
+
bad_basis_change_num = Ix;
|
|
3963
|
+
break;
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
if (bad_basis_change_num < 0) {
|
|
3967
|
+
// Not on the list so create record
|
|
3968
|
+
HighsSimplexBadBasisChangeRecord record;
|
|
3969
|
+
record.taboo = taboo;
|
|
3970
|
+
record.row_out = row_out;
|
|
3971
|
+
record.variable_out = variable_out;
|
|
3972
|
+
record.variable_in = variable_in;
|
|
3973
|
+
record.reason = reason;
|
|
3974
|
+
bad_basis_change_.push_back(record);
|
|
3975
|
+
bad_basis_change_num = bad_basis_change_.size() - 1;
|
|
3976
|
+
} else {
|
|
3977
|
+
// On the list so just update whether it is taboo
|
|
3978
|
+
bad_basis_change_[bad_basis_change_num].taboo = taboo;
|
|
3979
|
+
}
|
|
3980
|
+
return bad_basis_change_num;
|
|
3981
|
+
}
|
|
3982
|
+
|
|
3983
|
+
void HEkk::clearBadBasisChangeTabooFlag() {
|
|
3984
|
+
for (auto& change : bad_basis_change_) change.taboo = false;
|
|
3985
|
+
}
|
|
3986
|
+
|
|
3987
|
+
bool HEkk::tabooBadBasisChange() const {
|
|
3988
|
+
for (const auto& change : bad_basis_change_) {
|
|
3989
|
+
if (change.taboo) return true;
|
|
3990
|
+
}
|
|
3991
|
+
return false;
|
|
3992
|
+
}
|
|
3993
|
+
|
|
3994
|
+
void HEkk::applyTabooRowOut(vector<double>& values,
|
|
3995
|
+
const double overwrite_with) {
|
|
3996
|
+
assert(values.size() >= static_cast<size_t>(lp_.num_row_));
|
|
3997
|
+
for (auto& change : bad_basis_change_) {
|
|
3998
|
+
if (change.taboo) {
|
|
3999
|
+
HighsInt iRow = change.row_out;
|
|
4000
|
+
change.save_value = values[iRow];
|
|
4001
|
+
values[iRow] = overwrite_with;
|
|
4002
|
+
}
|
|
4003
|
+
}
|
|
4004
|
+
}
|
|
4005
|
+
|
|
4006
|
+
void HEkk::unapplyTabooRowOut(vector<double>& values) {
|
|
4007
|
+
assert((HighsInt)values.size() >= lp_.num_row_);
|
|
4008
|
+
// Unapply taboo rows in opposite order in case the row appears
|
|
4009
|
+
// twice in the list. This way the first saved value for the row is
|
|
4010
|
+
// what remains, not overwrite_with
|
|
4011
|
+
for (HighsInt iX = (HighsInt)bad_basis_change_.size() - 1; iX >= 0; iX--) {
|
|
4012
|
+
if (bad_basis_change_[iX].taboo)
|
|
4013
|
+
values[bad_basis_change_[iX].row_out] = bad_basis_change_[iX].save_value;
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
|
|
4017
|
+
void HEkk::applyTabooVariableIn(vector<double>& values,
|
|
4018
|
+
const double overwrite_with) {
|
|
4019
|
+
assert(values.size() >=
|
|
4020
|
+
static_cast<size_t>(lp_.num_col_) + static_cast<size_t>(lp_.num_row_));
|
|
4021
|
+
for (auto& change : bad_basis_change_) {
|
|
4022
|
+
if (change.taboo) {
|
|
4023
|
+
HighsInt iCol = change.variable_in;
|
|
4024
|
+
change.save_value = values[iCol];
|
|
4025
|
+
values[iCol] = overwrite_with;
|
|
4026
|
+
}
|
|
4027
|
+
}
|
|
4028
|
+
}
|
|
4029
|
+
|
|
4030
|
+
void HEkk::unapplyTabooVariableIn(vector<double>& values) {
|
|
4031
|
+
assert((HighsInt)values.size() >= lp_.num_col_ + lp_.num_row_);
|
|
4032
|
+
// Unapply taboo variables in opposite order in case the row appears
|
|
4033
|
+
// twice in the list. This way the first saved value for the
|
|
4034
|
+
// variable is what remains, not overwrite_with
|
|
4035
|
+
for (HighsInt iX = (HighsInt)bad_basis_change_.size() - 1; iX >= 0; iX--) {
|
|
4036
|
+
if (bad_basis_change_[iX].taboo)
|
|
4037
|
+
values[bad_basis_change_[iX].variable_in] =
|
|
4038
|
+
bad_basis_change_[iX].save_value;
|
|
4039
|
+
}
|
|
4040
|
+
}
|
|
4041
|
+
|
|
4042
|
+
bool HEkk::logicalBasis() const {
|
|
4043
|
+
for (HighsInt iRow = 0; iRow < this->lp_.num_row_; iRow++) {
|
|
4044
|
+
if (basis_.basicIndex_[iRow] < this->lp_.num_col_) return false;
|
|
4045
|
+
}
|
|
4046
|
+
return true;
|
|
4047
|
+
}
|
|
4048
|
+
|
|
4049
|
+
bool HEkk::proofOfPrimalInfeasibility() {
|
|
4050
|
+
// To be called from outside HEkk when row_ep is not known
|
|
4051
|
+
assert(dual_ray_record_.index >= 0);
|
|
4052
|
+
HighsLp& lp = this->lp_;
|
|
4053
|
+
HighsInt move_out = dual_ray_record_.sign;
|
|
4054
|
+
HighsInt row_out = dual_ray_record_.index;
|
|
4055
|
+
// Compute the basis inverse row
|
|
4056
|
+
HVector row_ep;
|
|
4057
|
+
row_ep.setup(lp.num_row_);
|
|
4058
|
+
unitBtran(row_out, row_ep);
|
|
4059
|
+
return proofOfPrimalInfeasibility(row_ep, move_out, row_out);
|
|
4060
|
+
}
|
|
4061
|
+
|
|
4062
|
+
bool HEkk::proofOfPrimalInfeasibility(HVector& row_ep, const HighsInt move_out,
|
|
4063
|
+
const HighsInt row_out) {
|
|
4064
|
+
// To be called from inside HEkkDual
|
|
4065
|
+
HighsLp& lp = this->lp_;
|
|
4066
|
+
|
|
4067
|
+
HighsInt debug_product_report = kDebugReportOff;
|
|
4068
|
+
const bool debug_proof_report_on = true;
|
|
4069
|
+
bool debug_rows_report = false;
|
|
4070
|
+
bool debug_proof_report = false;
|
|
4071
|
+
if (debug_iteration_report_) {
|
|
4072
|
+
if (debug_proof_report_on)
|
|
4073
|
+
debug_product_report = kDebugReportOff; // kDebugReportAll; //
|
|
4074
|
+
debug_rows_report = debug_proof_report_on;
|
|
4075
|
+
debug_proof_report = debug_proof_report_on;
|
|
4076
|
+
}
|
|
4077
|
+
|
|
4078
|
+
const bool use_row_wise_matrix = status_.has_ar_matrix;
|
|
4079
|
+
const bool use_iterative_refinement = false; // debug_iteration_report_;//
|
|
4080
|
+
if (use_iterative_refinement) {
|
|
4081
|
+
simplex_nla_.reportArray("Row e_p.0", lp.num_col_, &row_ep, true);
|
|
4082
|
+
unitBtranIterativeRefinement(row_out, row_ep);
|
|
4083
|
+
simplex_nla_.reportArray("Row e_p.1", lp.num_col_, &row_ep, true);
|
|
4084
|
+
}
|
|
4085
|
+
|
|
4086
|
+
// Refine row_ep by removing relatively small values
|
|
4087
|
+
double row_ep_scale = 0;
|
|
4088
|
+
// if (use_refinement) refineArray(row_ep, row_ep_scale,
|
|
4089
|
+
// refinement_tolerance);
|
|
4090
|
+
// Determine the maximum absolute value in row_ep
|
|
4091
|
+
HighsCDouble proof_lower = 0.0;
|
|
4092
|
+
const HighsInt max_num_basic_proof_report = 25;
|
|
4093
|
+
const HighsInt max_num_zeroed_report = 25;
|
|
4094
|
+
HighsInt num_zeroed_for_small_report = 0;
|
|
4095
|
+
double max_zeroed_for_small_value = 0;
|
|
4096
|
+
HighsInt num_zeroed_for_lb_report = 0;
|
|
4097
|
+
double max_zeroed_for_lb_value = 0;
|
|
4098
|
+
HighsInt num_zeroed_for_ub_report = 0;
|
|
4099
|
+
double max_zeroed_for_ub_value = 0;
|
|
4100
|
+
for (HighsInt iX = 0; iX < row_ep.count; iX++) {
|
|
4101
|
+
HighsInt iRow = row_ep.index[iX];
|
|
4102
|
+
// Give row_ep the sign of the leaving row - as is done in
|
|
4103
|
+
// getDualRayInterface.
|
|
4104
|
+
const double row_ep_value = row_ep.array[iRow];
|
|
4105
|
+
assert(row_ep_value);
|
|
4106
|
+
if (std::abs(row_ep_value * getMaxAbsRowValue(iRow)) <=
|
|
4107
|
+
options_->small_matrix_value) {
|
|
4108
|
+
if (debug_proof_report) {
|
|
4109
|
+
const double abs_row_ep_value = std::abs(row_ep_value);
|
|
4110
|
+
if (num_zeroed_for_small_report < max_num_zeroed_report &&
|
|
4111
|
+
max_zeroed_for_small_value < abs_row_ep_value) {
|
|
4112
|
+
printf(
|
|
4113
|
+
"Zeroed row_ep.array[%6d] = %11.4g due to being small in "
|
|
4114
|
+
"contribution\n",
|
|
4115
|
+
(int)iRow, row_ep_value);
|
|
4116
|
+
num_zeroed_for_small_report++;
|
|
4117
|
+
max_zeroed_for_small_value = abs_row_ep_value;
|
|
4118
|
+
}
|
|
4119
|
+
}
|
|
4120
|
+
row_ep.array[iRow] = 0.0;
|
|
4121
|
+
continue;
|
|
4122
|
+
}
|
|
4123
|
+
|
|
4124
|
+
row_ep.array[iRow] *= move_out;
|
|
4125
|
+
|
|
4126
|
+
// make sure infinite sides are not used
|
|
4127
|
+
double rowBound;
|
|
4128
|
+
if (row_ep.array[iRow] > 0) {
|
|
4129
|
+
rowBound = lp.row_lower_[iRow];
|
|
4130
|
+
if (highs_isInfinity(-rowBound)) {
|
|
4131
|
+
// row lower bound is infinite
|
|
4132
|
+
if (debug_proof_report) {
|
|
4133
|
+
const double abs_row_ep_value = std::abs(row_ep_value);
|
|
4134
|
+
if (num_zeroed_for_lb_report < max_num_zeroed_report &&
|
|
4135
|
+
max_zeroed_for_lb_value < abs_row_ep_value) {
|
|
4136
|
+
printf(
|
|
4137
|
+
"Zeroed row_ep.array[%6d] = %11.4g due to infinite lower "
|
|
4138
|
+
"bound\n",
|
|
4139
|
+
(int)iRow, row_ep_value);
|
|
4140
|
+
num_zeroed_for_lb_report++;
|
|
4141
|
+
max_zeroed_for_lb_value = abs_row_ep_value;
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
4144
|
+
row_ep.array[iRow] = 0.0;
|
|
4145
|
+
continue;
|
|
4146
|
+
}
|
|
4147
|
+
|
|
4148
|
+
} else {
|
|
4149
|
+
rowBound = lp.row_upper_[iRow];
|
|
4150
|
+
if (highs_isInfinity(rowBound)) {
|
|
4151
|
+
// row upper bound is infinite
|
|
4152
|
+
if (debug_proof_report) {
|
|
4153
|
+
const double abs_row_ep_value = std::abs(row_ep_value);
|
|
4154
|
+
if (num_zeroed_for_ub_report < max_num_zeroed_report &&
|
|
4155
|
+
max_zeroed_for_ub_value < abs_row_ep_value) {
|
|
4156
|
+
printf(
|
|
4157
|
+
"Zeroed row_ep.array[%6d] = %11.4g due to infinite upper "
|
|
4158
|
+
"bound\n",
|
|
4159
|
+
(int)iRow, row_ep_value);
|
|
4160
|
+
num_zeroed_for_ub_report++;
|
|
4161
|
+
max_zeroed_for_ub_value = abs_row_ep_value;
|
|
4162
|
+
}
|
|
4163
|
+
}
|
|
4164
|
+
row_ep.array[iRow] = 0.0;
|
|
4165
|
+
continue;
|
|
4166
|
+
}
|
|
4167
|
+
}
|
|
4168
|
+
// add up lower bound of proof constraint
|
|
4169
|
+
proof_lower += row_ep.array[iRow] * rowBound;
|
|
4170
|
+
}
|
|
4171
|
+
// Form the proof constraint coefficients
|
|
4172
|
+
proof_value_.clear();
|
|
4173
|
+
proof_index_.clear();
|
|
4174
|
+
vector<double>& proof_value = this->proof_value_;
|
|
4175
|
+
vector<HighsInt>& proof_index = this->proof_index_;
|
|
4176
|
+
if (use_row_wise_matrix) {
|
|
4177
|
+
this->ar_matrix_.productTransposeQuad(proof_value, proof_index, row_ep,
|
|
4178
|
+
debug_product_report);
|
|
4179
|
+
} else {
|
|
4180
|
+
lp.a_matrix_.productTransposeQuad(proof_value, proof_index, row_ep,
|
|
4181
|
+
debug_product_report);
|
|
4182
|
+
}
|
|
4183
|
+
|
|
4184
|
+
HighsInt proof_num_nz = proof_index.size();
|
|
4185
|
+
if (debug_rows_report) {
|
|
4186
|
+
simplex_nla_.reportArray("Row e_p", lp.num_col_, &row_ep, true);
|
|
4187
|
+
simplex_nla_.reportVector("Proof", proof_num_nz, proof_value, proof_index,
|
|
4188
|
+
true);
|
|
4189
|
+
}
|
|
4190
|
+
if (debug_proof_report) {
|
|
4191
|
+
printf(
|
|
4192
|
+
"HEkk::proofOfPrimalInfeasibility row_ep.count = %d; proof_num_nz = "
|
|
4193
|
+
"%d; row_ep_scale = %g\n",
|
|
4194
|
+
(int)row_ep.count, (int)proof_num_nz, row_ep_scale);
|
|
4195
|
+
HighsInt num_basic_proof_report = 0;
|
|
4196
|
+
double max_basic_proof_value = 0;
|
|
4197
|
+
for (HighsInt i = 0; i < proof_num_nz; ++i) {
|
|
4198
|
+
const HighsInt iCol = proof_index[i];
|
|
4199
|
+
const double value = proof_value[i];
|
|
4200
|
+
const double abs_value = std::abs(value);
|
|
4201
|
+
if (!basis_.nonbasicFlag_[iCol] && max_basic_proof_value < abs_value &&
|
|
4202
|
+
num_basic_proof_report < max_num_basic_proof_report) {
|
|
4203
|
+
printf("Proof entry %6d (Column %6d) is basic with value %11.4g\n",
|
|
4204
|
+
(int)i, (int)iCol, value);
|
|
4205
|
+
max_basic_proof_value = abs_value;
|
|
4206
|
+
num_basic_proof_report++;
|
|
4207
|
+
}
|
|
4208
|
+
}
|
|
4209
|
+
}
|
|
4210
|
+
HighsCDouble implied_upper = 0.0;
|
|
4211
|
+
HighsCDouble sumInf = 0.0;
|
|
4212
|
+
for (HighsInt i = 0; i < proof_num_nz; ++i) {
|
|
4213
|
+
const HighsInt iCol = proof_index[i];
|
|
4214
|
+
const double value = proof_value[i];
|
|
4215
|
+
if (value > 0) {
|
|
4216
|
+
if (highs_isInfinity(lp.col_upper_[iCol])) {
|
|
4217
|
+
sumInf += value;
|
|
4218
|
+
if (sumInf > options_->small_matrix_value) break;
|
|
4219
|
+
continue;
|
|
4220
|
+
// Commented out unreachable code
|
|
4221
|
+
// if (value <= options_->small_matrix_value) continue;
|
|
4222
|
+
}
|
|
4223
|
+
implied_upper += value * lp.col_upper_[iCol];
|
|
4224
|
+
} else {
|
|
4225
|
+
if (highs_isInfinity(-lp.col_lower_[iCol])) {
|
|
4226
|
+
sumInf += -value;
|
|
4227
|
+
if (sumInf > options_->small_matrix_value) break;
|
|
4228
|
+
continue;
|
|
4229
|
+
}
|
|
4230
|
+
implied_upper += value * lp.col_lower_[iCol];
|
|
4231
|
+
}
|
|
4232
|
+
}
|
|
4233
|
+
bool infinite_implied_upper = sumInf > options_->small_matrix_value;
|
|
4234
|
+
const double gap = double(proof_lower - implied_upper);
|
|
4235
|
+
const bool gap_ok = gap > options_->primal_feasibility_tolerance;
|
|
4236
|
+
const bool proof_of_primal_infeasibility = !infinite_implied_upper && gap_ok;
|
|
4237
|
+
|
|
4238
|
+
const double local_report = false;
|
|
4239
|
+
if (!proof_of_primal_infeasibility && local_report) {
|
|
4240
|
+
printf(
|
|
4241
|
+
"HEkk::proofOfPrimalInfeasibility: row %6d; gap = %11.4g (%s); "
|
|
4242
|
+
"sumInf = %11.4g (%s) so proof is %s\n",
|
|
4243
|
+
(int)row_out, gap, highsBoolToString(gap_ok).c_str(), (double)sumInf,
|
|
4244
|
+
highsBoolToString(infinite_implied_upper).c_str(),
|
|
4245
|
+
highsBoolToString(proof_of_primal_infeasibility).c_str());
|
|
4246
|
+
}
|
|
4247
|
+
if (debug_proof_report) {
|
|
4248
|
+
printf("HEkk::proofOfPrimalInfeasibility has %sfinite implied upper bound",
|
|
4249
|
+
infinite_implied_upper ? "in" : "");
|
|
4250
|
+
if (!infinite_implied_upper) printf(" and gap = %g", gap);
|
|
4251
|
+
printf(" so proof is %s\n",
|
|
4252
|
+
proof_of_primal_infeasibility ? "true" : "false");
|
|
4253
|
+
}
|
|
4254
|
+
return proof_of_primal_infeasibility;
|
|
4255
|
+
}
|
|
4256
|
+
|
|
4257
|
+
double HEkk::getValueScale(const HighsInt count,
|
|
4258
|
+
const vector<double>& value) const {
|
|
4259
|
+
if (count <= 0) return 1;
|
|
4260
|
+
double max_abs_value = 0;
|
|
4261
|
+
for (HighsInt iX = 0; iX < count; iX++)
|
|
4262
|
+
max_abs_value = std::max(fabs(value[iX]), max_abs_value);
|
|
4263
|
+
return nearestPowerOfTwoScale(max_abs_value);
|
|
4264
|
+
}
|
|
4265
|
+
|
|
4266
|
+
double HEkk::getMaxAbsRowValue(HighsInt row) {
|
|
4267
|
+
if (!status_.has_ar_matrix) initialisePartitionedRowwiseMatrix();
|
|
4268
|
+
|
|
4269
|
+
double val = -1.0;
|
|
4270
|
+
for (HighsInt i = ar_matrix_.start_[row]; i < ar_matrix_.start_[row + 1]; ++i)
|
|
4271
|
+
val = std::max(val, std::abs(ar_matrix_.value_[i]));
|
|
4272
|
+
|
|
4273
|
+
return val;
|
|
4274
|
+
}
|
|
4275
|
+
|
|
4276
|
+
void HEkk::unitBtranIterativeRefinement(const HighsInt row_out,
|
|
4277
|
+
HVector& row_ep) {
|
|
4278
|
+
// Perform an iteration of refinement
|
|
4279
|
+
HighsLp& lp = this->lp_;
|
|
4280
|
+
HVector residual;
|
|
4281
|
+
double residual_norm = 0;
|
|
4282
|
+
double correction_norm = 0;
|
|
4283
|
+
const double expected_density = 1;
|
|
4284
|
+
residual.setup(lp.num_row_);
|
|
4285
|
+
unitBtranResidual(row_out, row_ep, residual, residual_norm);
|
|
4286
|
+
const bool debug_iterative_refinement_report_on = false;
|
|
4287
|
+
bool debug_iterative_refinement_report = false;
|
|
4288
|
+
if (debug_iteration_report_) {
|
|
4289
|
+
debug_iterative_refinement_report = debug_iterative_refinement_report_on;
|
|
4290
|
+
}
|
|
4291
|
+
if (debug_iterative_refinement_report)
|
|
4292
|
+
printf(
|
|
4293
|
+
"HEkk::unitBtranIterativeRefinement: Residual has %6d / %6d nonzeros "
|
|
4294
|
+
"and norm of %g\n",
|
|
4295
|
+
(int)residual.count, (int)lp.num_row_, residual_norm);
|
|
4296
|
+
if (!residual_norm) return;
|
|
4297
|
+
// Normalise using nearest power of 2 to ||correction_rhs|| so kHighsTiny
|
|
4298
|
+
// isn't used adversely
|
|
4299
|
+
const double residual_scale = nearestPowerOfTwoScale(residual_norm);
|
|
4300
|
+
for (HighsInt iEl = 0; iEl < residual.count; iEl++)
|
|
4301
|
+
residual.array[residual.index[iEl]] *= residual_scale;
|
|
4302
|
+
btran(residual, expected_density);
|
|
4303
|
+
row_ep.count = 0;
|
|
4304
|
+
correction_norm = 0;
|
|
4305
|
+
// Adding two (possibly sparse) vectors, so have to loop over all rows
|
|
4306
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
4307
|
+
if (residual.array[iRow]) {
|
|
4308
|
+
const double correction_value = residual.array[iRow] / residual_scale;
|
|
4309
|
+
correction_norm = max(fabs(correction_value), correction_norm);
|
|
4310
|
+
row_ep.array[iRow] -= correction_value;
|
|
4311
|
+
}
|
|
4312
|
+
if (fabs(row_ep.array[iRow]) < kHighsTiny) {
|
|
4313
|
+
row_ep.array[iRow] = 0;
|
|
4314
|
+
} else {
|
|
4315
|
+
row_ep.index[row_ep.count++] = iRow;
|
|
4316
|
+
}
|
|
4317
|
+
}
|
|
4318
|
+
if (debug_iterative_refinement_report)
|
|
4319
|
+
printf(
|
|
4320
|
+
"HEkk::unitBtranIterativeRefinement: Correction has %6d / %6d nonzeros "
|
|
4321
|
+
"and norm of %g\n",
|
|
4322
|
+
(int)residual.count, (int)lp.num_row_, correction_norm);
|
|
4323
|
+
}
|
|
4324
|
+
|
|
4325
|
+
void HEkk::unitBtranResidual(const HighsInt row_out, const HVector& row_ep,
|
|
4326
|
+
HVector& residual, double& residual_norm) {
|
|
4327
|
+
HighsLp& lp = this->lp_;
|
|
4328
|
+
vector<HighsCDouble> quad_residual;
|
|
4329
|
+
quad_residual.assign(lp.num_row_, 0);
|
|
4330
|
+
quad_residual[row_out] = -1.0;
|
|
4331
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
4332
|
+
HighsInt iVar = basis_.basicIndex_[iRow];
|
|
4333
|
+
HighsCDouble value = quad_residual[iRow];
|
|
4334
|
+
if (iVar < lp.num_col_) {
|
|
4335
|
+
for (HighsInt iEl = lp.a_matrix_.start_[iVar];
|
|
4336
|
+
iEl < lp.a_matrix_.start_[iVar + 1]; iEl++)
|
|
4337
|
+
value +=
|
|
4338
|
+
lp.a_matrix_.value_[iEl] * row_ep.array[lp.a_matrix_.index_[iEl]];
|
|
4339
|
+
} else {
|
|
4340
|
+
value += row_ep.array[iVar - lp.num_col_];
|
|
4341
|
+
}
|
|
4342
|
+
quad_residual[iRow] = value;
|
|
4343
|
+
}
|
|
4344
|
+
residual.clear();
|
|
4345
|
+
residual.packFlag = false;
|
|
4346
|
+
residual_norm = 0;
|
|
4347
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
4348
|
+
const double value = (double)quad_residual[iRow];
|
|
4349
|
+
if (value) {
|
|
4350
|
+
residual.array[iRow] = value;
|
|
4351
|
+
residual.index[residual.count++] = iRow;
|
|
4352
|
+
}
|
|
4353
|
+
residual_norm = max(fabs(residual.array[iRow]), residual_norm);
|
|
4354
|
+
}
|
|
4355
|
+
}
|
|
4356
|
+
|
|
4357
|
+
void HighsSimplexStats::report(FILE* file, std::string message) const {
|
|
4358
|
+
fprintf(file, "\nSimplex stats: %s\n", message.c_str());
|
|
4359
|
+
fprintf(file, " valid = %d\n", this->valid);
|
|
4360
|
+
fprintf(file, " iteration_count = %d\n",
|
|
4361
|
+
static_cast<int>(this->iteration_count));
|
|
4362
|
+
fprintf(file, " num_invert = %d\n",
|
|
4363
|
+
static_cast<int>(this->num_invert));
|
|
4364
|
+
fprintf(file, " last_invert_num_el = %d\n",
|
|
4365
|
+
static_cast<int>(this->last_invert_num_el));
|
|
4366
|
+
fprintf(file, " last_factored_basis_num_el = %d\n",
|
|
4367
|
+
static_cast<int>(this->last_factored_basis_num_el));
|
|
4368
|
+
fprintf(file, " col_aq_density = %g\n", this->col_aq_density);
|
|
4369
|
+
fprintf(file, " row_ep_density = %g\n", this->row_ep_density);
|
|
4370
|
+
fprintf(file, " row_ap_density = %g\n", this->row_ap_density);
|
|
4371
|
+
fprintf(file, " row_DSE_density = %g\n", this->row_DSE_density);
|
|
4372
|
+
}
|
|
4373
|
+
|
|
4374
|
+
void HighsSimplexStats::initialise(const HighsInt iteration_count_) {
|
|
4375
|
+
valid = false;
|
|
4376
|
+
iteration_count = -iteration_count_;
|
|
4377
|
+
num_invert = 0;
|
|
4378
|
+
last_invert_num_el = 0;
|
|
4379
|
+
last_factored_basis_num_el = 0;
|
|
4380
|
+
col_aq_density = 0;
|
|
4381
|
+
row_ep_density = 0;
|
|
4382
|
+
row_ap_density = 0;
|
|
4383
|
+
row_DSE_density = 0;
|
|
4384
|
+
}
|
|
4385
|
+
|
|
4386
|
+
HighsRayRecord HighsRayRecord::getRayRecord() const {
|
|
4387
|
+
HighsRayRecord record;
|
|
4388
|
+
record.index = this->index;
|
|
4389
|
+
record.sign = this->sign;
|
|
4390
|
+
record.value = this->value;
|
|
4391
|
+
return record;
|
|
4392
|
+
}
|
|
4393
|
+
|
|
4394
|
+
void HighsRayRecord::setRayRecord(const HighsRayRecord& from_record) {
|
|
4395
|
+
this->index = from_record.index;
|
|
4396
|
+
this->sign = from_record.sign;
|
|
4397
|
+
this->value = from_record.value;
|
|
4398
|
+
}
|
|
4399
|
+
|
|
4400
|
+
void HighsRayRecord::clear() {
|
|
4401
|
+
this->index = kNoRayIndex;
|
|
4402
|
+
this->sign = kNoRaySign;
|
|
4403
|
+
this->value.clear();
|
|
4404
|
+
}
|