lpsolver 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/README.md +70 -26
- data/ext/lpsolver/Makefile +273 -0
- data/ext/lpsolver/ext.c +353 -0
- data/ext/lpsolver/ext.o +0 -0
- data/ext/lpsolver/extconf.rb +79 -0
- data/ext/lpsolver/native.so +0 -0
- data/ext/lpsolver-highs/AUTHORS +7 -0
- data/ext/lpsolver-highs/BUILD.bazel +243 -0
- data/ext/lpsolver-highs/CITATION.cff +29 -0
- data/ext/lpsolver-highs/CMakeCache.txt +406 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeCCompiler.cmake +81 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeCXXCompiler.cmake +101 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeDetermineCompilerABI_C.bin +0 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeDetermineCompilerABI_CXX.bin +0 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CMakeSystem.cmake +15 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CompilerIdC/CMakeCCompilerId.c +904 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CompilerIdC/a.out +0 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CompilerIdCXX/CMakeCXXCompilerId.cpp +919 -0
- data/ext/lpsolver-highs/CMakeFiles/3.31.4/CompilerIdCXX/a.out +0 -0
- data/ext/lpsolver-highs/CMakeFiles/CMakeConfigureLog.yaml +576 -0
- data/ext/lpsolver-highs/CMakeFiles/cmake.check_cache +1 -0
- data/ext/lpsolver-highs/CMakeLists.txt +983 -0
- data/ext/lpsolver-highs/CODE_OF_CONDUCT.md +128 -0
- data/ext/lpsolver-highs/CONTRIBUTING.md +31 -0
- data/ext/lpsolver-highs/FEATURES.md +61 -0
- data/ext/lpsolver-highs/LICENSE.txt +21 -0
- data/ext/lpsolver-highs/MODULE.bazel +38 -0
- data/ext/lpsolver-highs/README.md +281 -0
- data/ext/lpsolver-highs/THIRD_PARTY_NOTICES.md +78 -0
- data/ext/lpsolver-highs/Version.txt +4 -0
- data/ext/lpsolver-highs/WORKSPACE +33 -0
- data/ext/lpsolver-highs/app/CMakeLists.txt +110 -0
- data/ext/lpsolver-highs/app/HighsRuntimeOptions.h +292 -0
- data/ext/lpsolver-highs/app/RunHighs.cpp +147 -0
- data/ext/lpsolver-highs/app/highs_webdemo_shell.html +73 -0
- data/ext/lpsolver-highs/build/bin/highs +0 -0
- data/ext/lpsolver-highs/build/include/highs/HConfig.h +22 -0
- data/ext/lpsolver-highs/build/include/highs/Highs.h +1812 -0
- data/ext/lpsolver-highs/build/include/highs/interfaces/highs_c_api.h +2651 -0
- data/ext/lpsolver-highs/build/include/highs/io/Filereader.h +45 -0
- data/ext/lpsolver-highs/build/include/highs/io/FilereaderLp.h +49 -0
- data/ext/lpsolver-highs/build/include/highs/io/FilereaderMps.h +27 -0
- data/ext/lpsolver-highs/build/include/highs/io/HMPSIO.h +78 -0
- data/ext/lpsolver-highs/build/include/highs/io/HMpsFF.h +245 -0
- data/ext/lpsolver-highs/build/include/highs/io/HighsIO.h +118 -0
- data/ext/lpsolver-highs/build/include/highs/io/LoadOptions.h +24 -0
- data/ext/lpsolver-highs/build/include/highs/io/filereaderlp/builder.hpp +25 -0
- data/ext/lpsolver-highs/build/include/highs/io/filereaderlp/def.hpp +19 -0
- data/ext/lpsolver-highs/build/include/highs/io/filereaderlp/model.hpp +68 -0
- data/ext/lpsolver-highs/build/include/highs/io/filereaderlp/reader.hpp +10 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/IpxSolution.h +32 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/IpxWrapper.h +106 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu.h +161 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_factorize.h +247 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_get_factors.h +108 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_initialize.h +119 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_factorize.h +34 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_free.h +19 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_get_factors.h +34 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_initialize.h +46 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_solve_dense.h +29 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_solve_for_update.h +42 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_solve_sparse.h +32 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_obj_update.h +31 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_object.h +30 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_solve_dense.h +75 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_solve_for_update.h +169 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_solve_sparse.h +112 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/basiclu_update.h +125 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/lu_def.h +39 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/lu_file.h +21 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/lu_internal.h +220 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/basiclu/lu_list.h +173 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/basiclu_kernel.h +20 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/basiclu_wrapper.h +47 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/basis.h +350 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/conjugate_residuals.h +74 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/control.h +167 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/crossover.h +157 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/diagonal_precond.h +45 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/forrest_tomlin.h +102 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/guess_basis.h +21 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/indexed_vector.h +113 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/info.h +27 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipm.h +94 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_c.h +47 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_config.h +9 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_info.h +111 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_internal.h +89 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_parameters.h +76 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/ipx_status.h +57 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/iterate.h +331 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/kkt_solver.h +70 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/kkt_solver_basis.h +66 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/kkt_solver_diag.h +48 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/linear_operator.h +26 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/lp_solver.h +204 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/lu_factorization.h +79 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/lu_update.h +129 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/maxvolume.h +54 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/model.h +413 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/multistream.h +52 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/normal_matrix.h +44 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/power_method.h +44 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/sparse_matrix.h +195 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/sparse_utils.h +58 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/splitted_normal_matrix.h +63 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/starting_basis.h +39 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/symbolic_invert.h +29 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/timer.h +25 -0
- data/ext/lpsolver-highs/build/include/highs/ipm/ipx/utils.h +37 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HConst.h +430 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HStruct.h +213 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsAnalysis.h +23 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsCallback.h +104 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsCallbackStruct.h +70 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsDebug.h +34 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsIis.h +139 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsInfo.h +421 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsInfoDebug.h +27 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsLp.h +97 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsLpSolverObject.h +47 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsLpUtils.h +330 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsModelUtils.h +129 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsOptions.h +1715 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsRanging.h +43 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsSolution.h +179 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsSolutionDebug.h +87 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsSolve.h +29 -0
- data/ext/lpsolver-highs/build/include/highs/lp_data/HighsStatus.h +29 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsCliqueTable.h +329 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsConflictPool.h +109 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsCutGeneration.h +108 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsCutPool.h +168 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsDebugSol.h +133 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsDomain.h +657 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsDomainChange.h +48 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsDynamicRowMatrix.h +104 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsGFkSolve.h +439 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsImplications.h +194 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsLpAggregator.h +50 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsLpRelaxation.h +361 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsMipAnalysis.h +71 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsMipSolver.h +159 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsMipSolverData.h +313 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsModkSeparator.h +60 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsNodeQueue.h +312 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsObjectiveFunction.h +71 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsPathSeparator.h +39 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsPrimalHeuristics.h +75 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsPseudocost.h +366 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsRedcostFixing.h +42 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsSearch.h +241 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsSeparation.h +41 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsSeparator.h +60 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsTableauSeparator.h +34 -0
- data/ext/lpsolver-highs/build/include/highs/mip/HighsTransformedLp.h +63 -0
- data/ext/lpsolver-highs/build/include/highs/mip/MipTimer.h +544 -0
- data/ext/lpsolver-highs/build/include/highs/mip/feasibilityjump.hh +800 -0
- data/ext/lpsolver-highs/build/include/highs/model/HighsHessian.h +54 -0
- data/ext/lpsolver-highs/build/include/highs/model/HighsHessianUtils.h +47 -0
- data/ext/lpsolver-highs/build/include/highs/model/HighsModel.h +42 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsBinarySemaphore.h +108 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsCacheAlign.h +82 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsCombinable.h +116 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsMutex.h +124 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsParallel.h +128 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsRaceTimer.h +38 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsSchedulerConstants.h +19 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsSpinMutex.h +48 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsSplitDeque.h +606 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsTask.h +170 -0
- data/ext/lpsolver-highs/build/include/highs/parallel/HighsTaskExecutor.h +217 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/CupdlpWrapper.h +108 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/HiPdlpTimer.h +155 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/HiPdlpWrapper.h +26 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_cs.h +40 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_defs.h +447 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_linalg.h +189 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_proj.h +19 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_restart.h +31 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_scaling.h +26 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_solver.h +105 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_step.h +37 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/cupdlp/cupdlp_utils.c +1850 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/defs.hpp +222 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/linalg.hpp +61 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/logger.hpp +80 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/pdhg.hpp +358 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/restart.hpp +96 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/scaling.hpp +74 -0
- data/ext/lpsolver-highs/build/include/highs/pdlp/hipdlp/solver_results.hpp +65 -0
- data/ext/lpsolver-highs/build/include/highs/pdqsort/pdqsort.h +532 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/HPresolve.h +505 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/HPresolveAnalysis.h +52 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/HighsPostsolveStack.h +943 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/HighsSymmetry.h +284 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/ICrash.h +124 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/ICrashUtil.h +62 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/ICrashX.h +23 -0
- data/ext/lpsolver-highs/build/include/highs/presolve/PresolveComponent.h +90 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/a_asm.hpp +77 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/a_quass.hpp +22 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/basis.hpp +159 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/crashsolution.hpp +20 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/dantzigpricing.hpp +80 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/devexpricing.hpp +108 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/eventhandler.hpp +30 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/factor.hpp +408 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/feasibility_bounded.hpp +114 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/feasibility_highs.hpp +301 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/gradient.hpp +46 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/instance.hpp +70 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/matrix.hpp +342 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/perturbation.hpp +15 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/pricing.hpp +22 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/qpconst.hpp +34 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/qpvector.hpp +242 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/quass.hpp +27 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/ratiotest.hpp +26 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/runtime.hpp +45 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/scaling.hpp +15 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/settings.hpp +84 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/snippets.hpp +36 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/statistics.hpp +30 -0
- data/ext/lpsolver-highs/build/include/highs/qpsolver/steepestedgepricing.hpp +173 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HApp.h +550 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkk.h +419 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkkDual.h +513 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkkDualRHS.h +134 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkkDualRow.h +201 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HEkkPrimal.h +191 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HSimplex.h +42 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HSimplexDebug.h +48 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HSimplexNla.h +158 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HSimplexReport.h +21 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/HighsSimplexAnalysis.h +500 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/SimplexConst.h +273 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/SimplexStruct.h +263 -0
- data/ext/lpsolver-highs/build/include/highs/simplex/SimplexTimer.h +414 -0
- data/ext/lpsolver-highs/build/include/highs/test_kkt/DevKkt.h +143 -0
- data/ext/lpsolver-highs/build/include/highs/test_kkt/KktCh2.h +79 -0
- data/ext/lpsolver-highs/build/include/highs/util/FactorTimer.h +199 -0
- data/ext/lpsolver-highs/build/include/highs/util/HFactor.h +587 -0
- data/ext/lpsolver-highs/build/include/highs/util/HFactorConst.h +81 -0
- data/ext/lpsolver-highs/build/include/highs/util/HFactorDebug.h +55 -0
- data/ext/lpsolver-highs/build/include/highs/util/HSet.h +89 -0
- data/ext/lpsolver-highs/build/include/highs/util/HVector.h +22 -0
- data/ext/lpsolver-highs/build/include/highs/util/HVectorBase.h +102 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsCDouble.h +323 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsComponent.h +53 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsDataStack.h +83 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsDisjointSets.h +107 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsHash.h +1274 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsHashTree.h +1461 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsInt.h +36 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsIntegers.h +212 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsLinearSumBounds.h +203 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsMatrixPic.h +37 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsMatrixSlice.h +561 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsMatrixUtils.h +57 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsMemoryAllocation.h +63 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsRandom.h +242 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsRbTree.h +452 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsSort.h +131 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsSparseMatrix.h +151 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsSparseVectorSum.h +95 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsSplay.h +135 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsTimer.h +385 -0
- data/ext/lpsolver-highs/build/include/highs/util/HighsUtils.h +272 -0
- data/ext/lpsolver-highs/build/include/highs/util/stringutil.h +46 -0
- data/ext/lpsolver-highs/build/include/highs/zstr/strict_fstream.hpp +237 -0
- data/ext/lpsolver-highs/build/include/highs/zstr/zstr.hpp +473 -0
- data/ext/lpsolver-highs/build/include/highs_export.h +43 -0
- data/ext/lpsolver-highs/build/lib/cmake/highs/highs-config-version.cmake +65 -0
- data/ext/lpsolver-highs/build/lib/cmake/highs/highs-config.cmake +36 -0
- data/ext/lpsolver-highs/build/lib/cmake/highs/highs-targets-release.cmake +19 -0
- data/ext/lpsolver-highs/build/lib/cmake/highs/highs-targets.cmake +111 -0
- data/ext/lpsolver-highs/build/lib/libhighs.a +0 -0
- data/ext/lpsolver-highs/build/lib/pkgconfig/highs.pc +12 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/AUTHORS +7 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/CITATION.cff +29 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/CODE_OF_CONDUCT.md +128 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/CONTRIBUTING.md +31 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/FEATURES.md +61 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/LICENSE.txt +21 -0
- data/ext/lpsolver-highs/build/share/doc/HIGHS/README.md +281 -0
- data/ext/lpsolver-highs/build_webdemo.sh +46 -0
- data/ext/lpsolver-highs/check/Avgas.cpp +245 -0
- data/ext/lpsolver-highs/check/Avgas.h +44 -0
- data/ext/lpsolver-highs/check/CMakeLists.txt +573 -0
- data/ext/lpsolver-highs/check/HCheckConfig.h.bazel.in +6 -0
- data/ext/lpsolver-highs/check/HCheckConfig.h.in +12 -0
- data/ext/lpsolver-highs/check/HCheckConfig.h.meson.in +6 -0
- data/ext/lpsolver-highs/check/SpecialLps.h +405 -0
- data/ext/lpsolver-highs/check/TestAlienBasis.cpp +720 -0
- data/ext/lpsolver-highs/check/TestBasis.cpp +359 -0
- data/ext/lpsolver-highs/check/TestBasisSolves.cpp +669 -0
- data/ext/lpsolver-highs/check/TestCAPI.c +2513 -0
- data/ext/lpsolver-highs/check/TestCallbacks.cpp +608 -0
- data/ext/lpsolver-highs/check/TestCheckSolution.cpp +740 -0
- data/ext/lpsolver-highs/check/TestCrossover.cpp +111 -0
- data/ext/lpsolver-highs/check/TestDualize.cpp +172 -0
- data/ext/lpsolver-highs/check/TestEkk.cpp +100 -0
- data/ext/lpsolver-highs/check/TestFactor.cpp +389 -0
- data/ext/lpsolver-highs/check/TestFilereader.cpp +568 -0
- data/ext/lpsolver-highs/check/TestFortranAPI.f90 +65 -0
- data/ext/lpsolver-highs/check/TestHSet.cpp +80 -0
- data/ext/lpsolver-highs/check/TestHighsCDouble.cpp +109 -0
- data/ext/lpsolver-highs/check/TestHighsGFkSolve.cpp +102 -0
- data/ext/lpsolver-highs/check/TestHighsHash.cpp +126 -0
- data/ext/lpsolver-highs/check/TestHighsHessian.cpp +329 -0
- data/ext/lpsolver-highs/check/TestHighsIntegers.cpp +42 -0
- data/ext/lpsolver-highs/check/TestHighsModel.cpp +134 -0
- data/ext/lpsolver-highs/check/TestHighsParallel.cpp +277 -0
- data/ext/lpsolver-highs/check/TestHighsRbTree.cpp +109 -0
- data/ext/lpsolver-highs/check/TestHighsSparseMatrix.cpp +126 -0
- data/ext/lpsolver-highs/check/TestHighsVersion.cpp +61 -0
- data/ext/lpsolver-highs/check/TestHipo.cpp +122 -0
- data/ext/lpsolver-highs/check/TestICrash.cpp +46 -0
- data/ext/lpsolver-highs/check/TestIO.cpp +163 -0
- data/ext/lpsolver-highs/check/TestIis.cpp +1063 -0
- data/ext/lpsolver-highs/check/TestInfo.cpp +116 -0
- data/ext/lpsolver-highs/check/TestIpm.cpp +226 -0
- data/ext/lpsolver-highs/check/TestIpx.cpp +96 -0
- data/ext/lpsolver-highs/check/TestLPFileFormat.cpp +22 -0
- data/ext/lpsolver-highs/check/TestLogging.cpp +69 -0
- data/ext/lpsolver-highs/check/TestLpModification.cpp +2497 -0
- data/ext/lpsolver-highs/check/TestLpOrientation.cpp +121 -0
- data/ext/lpsolver-highs/check/TestLpSolvers.cpp +555 -0
- data/ext/lpsolver-highs/check/TestLpValidation.cpp +689 -0
- data/ext/lpsolver-highs/check/TestMain.cpp +6 -0
- data/ext/lpsolver-highs/check/TestMipSolver.cpp +1406 -0
- data/ext/lpsolver-highs/check/TestModelProperties.cpp +143 -0
- data/ext/lpsolver-highs/check/TestMultiObjective.cpp +198 -0
- data/ext/lpsolver-highs/check/TestNames.cpp +187 -0
- data/ext/lpsolver-highs/check/TestOptions.cpp +544 -0
- data/ext/lpsolver-highs/check/TestPdlp.cpp +327 -0
- data/ext/lpsolver-highs/check/TestPdlpHi.cpp +40 -0
- data/ext/lpsolver-highs/check/TestPresolve.cpp +912 -0
- data/ext/lpsolver-highs/check/TestQpSolver.cpp +1345 -0
- data/ext/lpsolver-highs/check/TestRanging.cpp +558 -0
- data/ext/lpsolver-highs/check/TestRays.cpp +1010 -0
- data/ext/lpsolver-highs/check/TestSemiVariables.cpp +329 -0
- data/ext/lpsolver-highs/check/TestSetup.cpp +12 -0
- data/ext/lpsolver-highs/check/TestSort.cpp +247 -0
- data/ext/lpsolver-highs/check/TestSpecialLps.cpp +775 -0
- data/ext/lpsolver-highs/check/TestThrow.cpp +83 -0
- data/ext/lpsolver-highs/check/TestTspSolver.cpp +19 -0
- data/ext/lpsolver-highs/check/TestUserScale.cpp +444 -0
- data/ext/lpsolver-highs/check/cublas_example.cpp +76 -0
- data/ext/lpsolver-highs/check/cublas_gpu_start.cpp +88 -0
- data/ext/lpsolver-highs/check/hipo_test_option_files/hipo_options_0 +1 -0
- data/ext/lpsolver-highs/check/instances/1448.lp +1 -0
- data/ext/lpsolver-highs/check/instances/1449a.lp +1 -0
- data/ext/lpsolver-highs/check/instances/1449b.lp +1 -0
- data/ext/lpsolver-highs/check/instances/1451.lp +8 -0
- data/ext/lpsolver-highs/check/instances/2122.lp +1822 -0
- data/ext/lpsolver-highs/check/instances/2171.mps +717 -0
- data/ext/lpsolver-highs/check/instances/25fv47.mps +6919 -0
- data/ext/lpsolver-highs/check/instances/2821-duplicate.mps +31 -0
- data/ext/lpsolver-highs/check/instances/2821-qmatrix.mps +31 -0
- data/ext/lpsolver-highs/check/instances/2821-quadobj.mps +29 -0
- data/ext/lpsolver-highs/check/instances/2821-summation.mps +30 -0
- data/ext/lpsolver-highs/check/instances/2821.mps +29 -0
- data/ext/lpsolver-highs/check/instances/2894.mps +89 -0
- data/ext/lpsolver-highs/check/instances/80bau3b.mps +23732 -0
- data/ext/lpsolver-highs/check/instances/WithInf.set +3 -0
- data/ext/lpsolver-highs/check/instances/adlittle.mps +335 -0
- data/ext/lpsolver-highs/check/instances/afiro.mps +83 -0
- data/ext/lpsolver-highs/check/instances/avgas.mps +51 -0
- data/ext/lpsolver-highs/check/instances/bell5.mps +384 -0
- data/ext/lpsolver-highs/check/instances/bgetam.mps +2112 -0
- data/ext/lpsolver-highs/check/instances/blending.mps +13 -0
- data/ext/lpsolver-highs/check/instances/box1.mps +1085 -0
- data/ext/lpsolver-highs/check/instances/chip.mps +13 -0
- data/ext/lpsolver-highs/check/instances/comment.mps +23 -0
- data/ext/lpsolver-highs/check/instances/cplex1.mps +9674 -0
- data/ext/lpsolver-highs/check/instances/dD2e.mps +10 -0
- data/ext/lpsolver-highs/check/instances/dcmulti.mps +2310 -0
- data/ext/lpsolver-highs/check/instances/e226.mps +1733 -0
- data/ext/lpsolver-highs/check/instances/egout-ac.mps +473 -0
- data/ext/lpsolver-highs/check/instances/egout.mps +403 -0
- data/ext/lpsolver-highs/check/instances/etamacro.mps +2084 -0
- data/ext/lpsolver-highs/check/instances/ex72a.mps +849 -0
- data/ext/lpsolver-highs/check/instances/fixed-binary.lp +11 -0
- data/ext/lpsolver-highs/check/instances/flugpl.mps +111 -0
- data/ext/lpsolver-highs/check/instances/flugpl_illegal_integer.sol +24 -0
- data/ext/lpsolver-highs/check/instances/flugpl_integer.sol +25 -0
- data/ext/lpsolver-highs/check/instances/forest6.mps +261 -0
- data/ext/lpsolver-highs/check/instances/galenet.mps +34 -0
- data/ext/lpsolver-highs/check/instances/gams10am.mps +478 -0
- data/ext/lpsolver-highs/check/instances/garbage.ems +3 -0
- data/ext/lpsolver-highs/check/instances/garbage.lp +3 -0
- data/ext/lpsolver-highs/check/instances/garbage.mps +3 -0
- data/ext/lpsolver-highs/check/instances/gas11.mps +2924 -0
- data/ext/lpsolver-highs/check/instances/gesa2.mps +5459 -0
- data/ext/lpsolver-highs/check/instances/greenbea.mps +19215 -0
- data/ext/lpsolver-highs/check/instances/gt2.mps +534 -0
- data/ext/lpsolver-highs/check/instances/infeasible-mip0.mps +140 -0
- data/ext/lpsolver-highs/check/instances/infeasible-mip1.mps +371 -0
- data/ext/lpsolver-highs/check/instances/israel.mps +1490 -0
- data/ext/lpsolver-highs/check/instances/issue-2095.mps +836 -0
- data/ext/lpsolver-highs/check/instances/issue-2173.mps +3331 -0
- data/ext/lpsolver-highs/check/instances/issue-2204.mps +143 -0
- data/ext/lpsolver-highs/check/instances/issue-2290.mps +158 -0
- data/ext/lpsolver-highs/check/instances/issue-2388.lp +76 -0
- data/ext/lpsolver-highs/check/instances/issue-2402.mps +435 -0
- data/ext/lpsolver-highs/check/instances/issue-2446.mps +9154 -0
- data/ext/lpsolver-highs/check/instances/issue-2585.lp +16 -0
- data/ext/lpsolver-highs/check/instances/issue-2874-3.mps +97 -0
- data/ext/lpsolver-highs/check/instances/klein1.mps +422 -0
- data/ext/lpsolver-highs/check/instances/lseu.mps +371 -0
- data/ext/lpsolver-highs/check/instances/model.xyz +1 -0
- data/ext/lpsolver-highs/check/instances/nan0.mps +13 -0
- data/ext/lpsolver-highs/check/instances/nan1.mps +13 -0
- data/ext/lpsolver-highs/check/instances/nan2.mps +13 -0
- data/ext/lpsolver-highs/check/instances/no-newline-eof.lp +5 -0
- data/ext/lpsolver-highs/check/instances/p01.mps +909 -0
- data/ext/lpsolver-highs/check/instances/p0548.mps +1992 -0
- data/ext/lpsolver-highs/check/instances/primal1.mps +3909 -0
- data/ext/lpsolver-highs/check/instances/qap04.mps +606 -0
- data/ext/lpsolver-highs/check/instances/qcqp.lp +8 -0
- data/ext/lpsolver-highs/check/instances/qjh.lp +9 -0
- data/ext/lpsolver-highs/check/instances/qjh.mps +18 -0
- data/ext/lpsolver-highs/check/instances/qjh_qmatrix.mps +19 -0
- data/ext/lpsolver-highs/check/instances/qjh_quadobj.mps +18 -0
- data/ext/lpsolver-highs/check/instances/qjh_quadobj_qmatrix.mps +25 -0
- data/ext/lpsolver-highs/check/instances/qjh_uncon.lp +10 -0
- data/ext/lpsolver-highs/check/instances/qjh_uncon.mps +17 -0
- data/ext/lpsolver-highs/check/instances/qpinfeasible.lp +8 -0
- data/ext/lpsolver-highs/check/instances/qptestnw.lp +7 -0
- data/ext/lpsolver-highs/check/instances/qpunbounded.lp +5 -0
- data/ext/lpsolver-highs/check/instances/refinery.mps +1882 -0
- data/ext/lpsolver-highs/check/instances/rgn.mps +559 -0
- data/ext/lpsolver-highs/check/instances/scrs8.mps +2717 -0
- data/ext/lpsolver-highs/check/instances/sctest.mps +66 -0
- data/ext/lpsolver-highs/check/instances/semi-continuous.lp +13 -0
- data/ext/lpsolver-highs/check/instances/semi-continuous.mps +24 -0
- data/ext/lpsolver-highs/check/instances/semi-integer.lp +15 -0
- data/ext/lpsolver-highs/check/instances/semi-integer.mps +22 -0
- data/ext/lpsolver-highs/check/instances/shell.mps +4039 -0
- data/ext/lpsolver-highs/check/instances/silly-names.mps +14 -0
- data/ext/lpsolver-highs/check/instances/small_mip.mps +87 -0
- data/ext/lpsolver-highs/check/instances/smalllp.mps +21 -0
- data/ext/lpsolver-highs/check/instances/sp150x300d.mps +1983 -0
- data/ext/lpsolver-highs/check/instances/stair.mps +2499 -0
- data/ext/lpsolver-highs/check/instances/standata.mps +2317 -0
- data/ext/lpsolver-highs/check/instances/standgub.mps +2428 -0
- data/ext/lpsolver-highs/check/instances/standmps.mps +2695 -0
- data/ext/lpsolver-highs/check/instances/test.mps +53 -0
- data/ext/lpsolver-highs/check/instances/vol1.mps +1895 -0
- data/ext/lpsolver-highs/check/instances/warnings.mps +68 -0
- data/ext/lpsolver-highs/check/instances/woodinfe.mps +216 -0
- data/ext/lpsolver-highs/check/matrix_multiplication.hpp +49 -0
- data/ext/lpsolver-highs/check/meson.build +92 -0
- data/ext/lpsolver-highs/check/pythontest.py +11 -0
- data/ext/lpsolver-highs/check/sample_options_file +8 -0
- data/ext/lpsolver-highs/cmake/CheckAtomic.cmake +74 -0
- data/ext/lpsolver-highs/cmake/FindCUDAConf.cmake +44 -0
- data/ext/lpsolver-highs/cmake/FindHipoDeps.cmake +351 -0
- data/ext/lpsolver-highs/cmake/README.md +243 -0
- data/ext/lpsolver-highs/cmake/cpp-highs.cmake +243 -0
- data/ext/lpsolver-highs/cmake/dotnet.cmake +94 -0
- data/ext/lpsolver-highs/cmake/highs-config.cmake.in +22 -0
- data/ext/lpsolver-highs/cmake/python-highs.cmake +74 -0
- data/ext/lpsolver-highs/cmake/set-version.cmake +26 -0
- data/ext/lpsolver-highs/cmake/sources-python.cmake +461 -0
- data/ext/lpsolver-highs/cmake/sources.cmake +618 -0
- data/ext/lpsolver-highs/docs/HiGHS_CopyrightHeader.pl +78 -0
- data/ext/lpsolver-highs/docs/HiGHS_CopyrightHeaderUpdateAll +32 -0
- data/ext/lpsolver-highs/docs/Project.toml +7 -0
- data/ext/lpsolver-highs/docs/README.md +27 -0
- data/ext/lpsolver-highs/docs/c_api_gen/HConfig.h +1 -0
- data/ext/lpsolver-highs/docs/c_api_gen/build.jl +48 -0
- data/ext/lpsolver-highs/docs/make.jl +115 -0
- data/ext/lpsolver-highs/docs/src/assets/logo.png +0 -0
- data/ext/lpsolver-highs/docs/src/callbacks.md +171 -0
- data/ext/lpsolver-highs/docs/src/executable.md +88 -0
- data/ext/lpsolver-highs/docs/src/guide/advanced.md +66 -0
- data/ext/lpsolver-highs/docs/src/guide/basic.md +116 -0
- data/ext/lpsolver-highs/docs/src/guide/further.md +193 -0
- data/ext/lpsolver-highs/docs/src/guide/gpu.md +58 -0
- data/ext/lpsolver-highs/docs/src/guide/index.md +18 -0
- data/ext/lpsolver-highs/docs/src/guide/kkt.md +219 -0
- data/ext/lpsolver-highs/docs/src/guide/numerics.md +55 -0
- data/ext/lpsolver-highs/docs/src/index.md +86 -0
- data/ext/lpsolver-highs/docs/src/installation.md +130 -0
- data/ext/lpsolver-highs/docs/src/interfaces/c_api.md +6 -0
- data/ext/lpsolver-highs/docs/src/interfaces/cpp/examples.md +1 -0
- data/ext/lpsolver-highs/docs/src/interfaces/cpp/index.md +29 -0
- data/ext/lpsolver-highs/docs/src/interfaces/cpp/library.md +107 -0
- data/ext/lpsolver-highs/docs/src/interfaces/csharp.md +55 -0
- data/ext/lpsolver-highs/docs/src/interfaces/fortran.md +11 -0
- data/ext/lpsolver-highs/docs/src/interfaces/julia/index.md +130 -0
- data/ext/lpsolver-highs/docs/src/interfaces/other.md +41 -0
- data/ext/lpsolver-highs/docs/src/interfaces/python/example-py.md +275 -0
- data/ext/lpsolver-highs/docs/src/interfaces/python/index.md +91 -0
- data/ext/lpsolver-highs/docs/src/interfaces/python/model-py.md +90 -0
- data/ext/lpsolver-highs/docs/src/options/definitions.md +529 -0
- data/ext/lpsolver-highs/docs/src/options/intro.md +46 -0
- data/ext/lpsolver-highs/docs/src/parallel.md +88 -0
- data/ext/lpsolver-highs/docs/src/solvers.md +168 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsHessian.md +9 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsIis.md +16 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsLp.md +19 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsModel.md +6 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/HighsSparseMatrix.md +10 -0
- data/ext/lpsolver-highs/docs/src/structures/classes/index.md +11 -0
- data/ext/lpsolver-highs/docs/src/structures/enums.md +114 -0
- data/ext/lpsolver-highs/docs/src/structures/index.md +12 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/HighsBasis.md +8 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/HighsInfo.md +148 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/HighsLinearObjective.md +11 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/HighsSolution.md +10 -0
- data/ext/lpsolver-highs/docs/src/structures/structs/index.md +10 -0
- data/ext/lpsolver-highs/docs/src/terminology.md +163 -0
- data/ext/lpsolver-highs/examples/CMakeLists.txt +26 -0
- data/ext/lpsolver-highs/examples/Docs.py +104 -0
- data/ext/lpsolver-highs/examples/branch-and-price.py +465 -0
- data/ext/lpsolver-highs/examples/call_highs_from_c.c +685 -0
- data/ext/lpsolver-highs/examples/call_highs_from_c_minimal.c +659 -0
- data/ext/lpsolver-highs/examples/call_highs_from_cpp.cpp +178 -0
- data/ext/lpsolver-highs/examples/call_highs_from_csharp.cs +83 -0
- data/ext/lpsolver-highs/examples/call_highs_from_fortran.f90 +579 -0
- data/ext/lpsolver-highs/examples/call_highs_from_python.py +448 -0
- data/ext/lpsolver-highs/examples/call_highs_from_python_highspy.py +71 -0
- data/ext/lpsolver-highs/examples/call_highs_from_python_mps.py +59 -0
- data/ext/lpsolver-highs/examples/callback_gap.py +71 -0
- data/ext/lpsolver-highs/examples/chip.py +43 -0
- data/ext/lpsolver-highs/examples/chip0.py +29 -0
- data/ext/lpsolver-highs/examples/distillation.py +77 -0
- data/ext/lpsolver-highs/examples/knapsack.py +43 -0
- data/ext/lpsolver-highs/examples/minimal.py +11 -0
- data/ext/lpsolver-highs/examples/multi_objective.py +139 -0
- data/ext/lpsolver-highs/examples/multiple_objective.py +120 -0
- data/ext/lpsolver-highs/examples/network_flow.py +37 -0
- data/ext/lpsolver-highs/examples/nqueens.py +29 -0
- data/ext/lpsolver-highs/examples/plot_highs_log.py +134 -0
- data/ext/lpsolver-highs/extern/CLI11.hpp +11546 -0
- data/ext/lpsolver-highs/extern/LICENCE_1_0.txt +23 -0
- data/ext/lpsolver-highs/extern/amd/License.txt +35 -0
- data/ext/lpsolver-highs/extern/amd/SuiteSparse_config.c +54 -0
- data/ext/lpsolver-highs/extern/amd/SuiteSparse_config.h +56 -0
- data/ext/lpsolver-highs/extern/amd/amd.h +357 -0
- data/ext/lpsolver-highs/extern/amd/amd_1.c +172 -0
- data/ext/lpsolver-highs/extern/amd/amd_2.c +1761 -0
- data/ext/lpsolver-highs/extern/amd/amd_aat.c +179 -0
- data/ext/lpsolver-highs/extern/amd/amd_control.c +65 -0
- data/ext/lpsolver-highs/extern/amd/amd_defaults.c +37 -0
- data/ext/lpsolver-highs/extern/amd/amd_info.c +120 -0
- data/ext/lpsolver-highs/extern/amd/amd_internal.h +137 -0
- data/ext/lpsolver-highs/extern/amd/amd_order.c +195 -0
- data/ext/lpsolver-highs/extern/amd/amd_post_tree.c +105 -0
- data/ext/lpsolver-highs/extern/amd/amd_postorder.c +140 -0
- data/ext/lpsolver-highs/extern/amd/amd_preprocess.c +107 -0
- data/ext/lpsolver-highs/extern/amd/amd_valid.c +93 -0
- data/ext/lpsolver-highs/extern/amd/changes.txt +8 -0
- data/ext/lpsolver-highs/extern/catch.hpp +18861 -0
- data/ext/lpsolver-highs/extern/metis/Changes.txt +31 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/GKlib.h +62 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/error.c +21 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_arch.h +64 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_defs.h +19 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_macros.h +50 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mkblas.h +51 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mkmemory.h +80 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mkpqueue.h +329 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mkrandom.h +89 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_mksort.h +271 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_ms_inttypes.h +41 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_ms_stat.h +22 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_ms_stdint.h +41 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_proto.h +50 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_struct.h +66 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/gk_types.h +15 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/mcore.c +176 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/memory.c +23 -0
- data/ext/lpsolver-highs/extern/metis/GKlib/random.c +37 -0
- data/ext/lpsolver-highs/extern/metis/LICENSE.txt +18 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/auxapi.c +27 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/balance.c +491 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/bucketsort.c +44 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/coarsen.c +895 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/compress.c +231 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/contig.c +83 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/defs.h +39 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/fm.c +527 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/gklib.c +55 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/gklib_defs.h +33 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/graph.c +268 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/initpart.c +385 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/macros.h +59 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/mcutil.c +162 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/metislib.h +35 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/mmd.c +598 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/ometis.c +661 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/options.c +260 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/proto.h +172 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/refine.c +99 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/separator.c +57 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/sfm.c +581 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/srefine.c +152 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/stdheaders.h +29 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/struct.h +117 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/util.c +59 -0
- data/ext/lpsolver-highs/extern/metis/libmetis/wspace.c +91 -0
- data/ext/lpsolver-highs/extern/metis/metis.h +271 -0
- data/ext/lpsolver-highs/extern/pdqsort/license.txt +16 -0
- data/ext/lpsolver-highs/extern/pdqsort/pdqsort.h +532 -0
- data/ext/lpsolver-highs/extern/rcm/LICENSE +19 -0
- data/ext/lpsolver-highs/extern/rcm/rcm.cpp +873 -0
- data/ext/lpsolver-highs/extern/rcm/rcm.h +22 -0
- data/ext/lpsolver-highs/extern/zstr/LICENSE +21 -0
- data/ext/lpsolver-highs/extern/zstr/strict_fstream.hpp +237 -0
- data/ext/lpsolver-highs/extern/zstr/zstr.hpp +473 -0
- data/ext/lpsolver-highs/flake.lock +61 -0
- data/ext/lpsolver-highs/flake.nix +73 -0
- data/ext/lpsolver-highs/highs/CMakeLists.txt +499 -0
- data/ext/lpsolver-highs/highs/HConfig.h.bazel.in +25 -0
- data/ext/lpsolver-highs/highs/HConfig.h.in +22 -0
- data/ext/lpsolver-highs/highs/HConfig.h.meson.in +17 -0
- data/ext/lpsolver-highs/highs/Highs.h +1812 -0
- data/ext/lpsolver-highs/highs/HighsRun.md +143 -0
- data/ext/lpsolver-highs/highs/highs_bindings.cpp +1826 -0
- data/ext/lpsolver-highs/highs/highspy/__init__.py +93 -0
- data/ext/lpsolver-highs/highs/highspy/__init__.pyi +91 -0
- data/ext/lpsolver-highs/highs/highspy/_core/__init__.pyi +1058 -0
- data/ext/lpsolver-highs/highs/highspy/_core/cb.pyi +118 -0
- data/ext/lpsolver-highs/highs/highspy/_core/simplex_constants.pyi +472 -0
- data/ext/lpsolver-highs/highs/highspy/highs.py +2430 -0
- data/ext/lpsolver-highs/highs/interfaces/highs_c_api.cpp +1812 -0
- data/ext/lpsolver-highs/highs/interfaces/highs_c_api.h +2651 -0
- data/ext/lpsolver-highs/highs/interfaces/highs_csharp_api.cs +1142 -0
- data/ext/lpsolver-highs/highs/interfaces/highs_fortran_api.f90 +873 -0
- data/ext/lpsolver-highs/highs/io/Filereader.cpp +87 -0
- data/ext/lpsolver-highs/highs/io/Filereader.h +45 -0
- data/ext/lpsolver-highs/highs/io/FilereaderLp.cpp +539 -0
- data/ext/lpsolver-highs/highs/io/FilereaderLp.h +49 -0
- data/ext/lpsolver-highs/highs/io/FilereaderMps.cpp +86 -0
- data/ext/lpsolver-highs/highs/io/FilereaderMps.h +27 -0
- data/ext/lpsolver-highs/highs/io/HMPSIO.cpp +1001 -0
- data/ext/lpsolver-highs/highs/io/HMPSIO.h +78 -0
- data/ext/lpsolver-highs/highs/io/HMpsFF.cpp +2113 -0
- data/ext/lpsolver-highs/highs/io/HMpsFF.h +245 -0
- data/ext/lpsolver-highs/highs/io/HighsIO.cpp +371 -0
- data/ext/lpsolver-highs/highs/io/HighsIO.h +118 -0
- data/ext/lpsolver-highs/highs/io/LoadOptions.cpp +60 -0
- data/ext/lpsolver-highs/highs/io/LoadOptions.h +24 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/LICENSE +19 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/builder.hpp +25 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/def.hpp +19 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/model.hpp +68 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/reader.cpp +1375 -0
- data/ext/lpsolver-highs/highs/io/filereaderlp/reader.hpp +10 -0
- data/ext/lpsolver-highs/highs/ipm/IpxSolution.h +32 -0
- data/ext/lpsolver-highs/highs/ipm/IpxWrapper.cpp +1526 -0
- data/ext/lpsolver-highs/highs/ipm/IpxWrapper.h +106 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu.h +161 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_factorize.c +132 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_factorize.h +247 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_get_factors.c +148 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_get_factors.h +108 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_initialize.c +24 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_initialize.h +119 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_factorize.h +34 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_free.h +19 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_get_factors.h +34 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_initialize.h +46 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_solve_dense.h +29 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_solve_for_update.h +42 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_solve_sparse.h +32 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_obj_update.h +31 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_object.c +325 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_object.h +30 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_dense.c +46 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_dense.h +75 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_for_update.c +79 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_for_update.h +169 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_sparse.c +63 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_solve_sparse.h +112 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_update.c +44 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/basiclu_update.h +125 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_build_factors.c +441 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_condest.c +124 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_def.h +39 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_dfs.c +141 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_factorize_bump.c +56 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_file.c +184 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_file.h +21 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_garbage_perm.c +53 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_initialize.c +56 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_internal.c +352 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_internal.h +220 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_list.h +173 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_markowitz.c +188 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_matrix_norm.c +51 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_pivot.c +1247 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_residual_test.c +155 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_setup_bump.c +198 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_singletons.c +511 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_dense.c +129 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_for_update.c +360 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_sparse.c +284 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_symbolic.c +48 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_solve_triangular.c +140 -0
- data/ext/lpsolver-highs/highs/ipm/basiclu/lu_update.c +908 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/Auxiliary.cpp +301 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/Auxiliary.h +104 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/IntConfig.h +27 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/KrylovMethods.cpp +193 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/KrylovMethods.h +30 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/Log.cpp +60 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/Log.h +62 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/OrderingPrint.h +10 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/VectorOperations.cpp +117 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/VectorOperations.h +59 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/auxiliary/mycblas.h +85 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Analyse.cpp +1367 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Analyse.h +122 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/CallAndTimeBlas.cpp +114 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/CallAndTimeBlas.h +46 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/CliqueStack.cpp +82 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/CliqueStack.h +83 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DataCollector.cpp +326 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DataCollector.h +86 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DenseFact.h +48 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DenseFactHybrid.cpp +279 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DenseFactKernel.cpp +284 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DgemmParallel.cpp +38 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/DgemmParallel.h +32 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FactorHiGHS.cpp +57 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FactorHiGHS.h +112 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FactorHiGHSSettings.h +63 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Factorise.cpp +405 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Factorise.h +85 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FormatHandler.cpp +46 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/FormatHandler.h +95 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/HybridHybridFormatHandler.cpp +238 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/HybridHybridFormatHandler.h +31 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/HybridSolveHandler.cpp +272 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/HybridSolveHandler.h +26 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/KrylovMethodsIpm.cpp +83 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/KrylovMethodsIpm.h +45 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Numeric.cpp +54 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Numeric.h +46 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/ReturnValues.h +19 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/SolveHandler.cpp +10 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/SolveHandler.h +48 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Swaps.cpp +70 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Swaps.h +19 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Symbolic.cpp +101 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Symbolic.h +220 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/factorhighs/Timing.h +114 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Control.cpp +38 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Control.h +41 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/FactorHiGHSSolver.cpp +887 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/FactorHiGHSSolver.h +92 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Info.h +58 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/IpmData.cpp +8 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/IpmData.h +37 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Iterate.cpp +640 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Iterate.h +172 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/LinearSolver.h +81 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/LogHighs.cpp +71 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/LogHighs.h +33 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Model.cpp +403 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Model.h +136 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Options.h +35 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Parameters.h +63 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/PreProcess.cpp +646 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/PreProcess.h +94 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Refine.cpp +214 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Solver.cpp +1346 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Solver.h +338 -0
- data/ext/lpsolver-highs/highs/ipm/hipo/ipm/Status.h +88 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basiclu_kernel.cc +71 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basiclu_kernel.h +20 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basiclu_wrapper.cc +299 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basiclu_wrapper.h +47 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basis.cc +966 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/basis.h +350 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/conjugate_residuals.cc +217 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/conjugate_residuals.h +74 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/control.cc +151 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/control.h +167 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/crossover.cc +479 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/crossover.h +157 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/diagonal_precond.cc +70 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/diagonal_precond.h +45 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/forrest_tomlin.cc +360 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/forrest_tomlin.h +102 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/guess_basis.cc +233 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/guess_basis.h +21 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/indexed_vector.cc +30 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/indexed_vector.h +113 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/info.cc +124 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/info.h +27 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipm.cc +897 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipm.h +94 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_c.cc +83 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_c.h +47 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_config.h +9 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_info.h +111 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_internal.h +89 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_parameters.h +76 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/ipx_status.h +57 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/iterate.cc +683 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/iterate.h +331 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver.cc +23 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver.h +70 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver_basis.cc +387 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver_basis.h +66 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver_diag.cc +120 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/kkt_solver_diag.h +48 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/linear_operator.cc +10 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/linear_operator.h +26 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lp_solver.cc +686 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lp_solver.h +204 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lu_factorization.cc +131 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lu_factorization.h +79 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lu_update.cc +62 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/lu_update.h +129 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/maxvolume.cc +337 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/maxvolume.h +54 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/model.cc +1528 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/model.h +413 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/multistream.h +52 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/normal_matrix.cc +126 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/normal_matrix.h +44 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/power_method.h +44 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/sparse_matrix.cc +382 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/sparse_matrix.h +195 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/sparse_utils.cc +92 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/sparse_utils.h +58 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/splitted_normal_matrix.cc +117 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/splitted_normal_matrix.h +63 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/starting_basis.cc +182 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/starting_basis.h +39 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/symbolic_invert.cc +183 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/symbolic_invert.h +29 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/timer.cc +16 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/timer.h +25 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/utils.cc +95 -0
- data/ext/lpsolver-highs/highs/ipm/ipx/utils.h +37 -0
- data/ext/lpsolver-highs/highs/lp_data/HConst.h +430 -0
- data/ext/lpsolver-highs/highs/lp_data/HStruct.h +213 -0
- data/ext/lpsolver-highs/highs/lp_data/Highs.cpp +4949 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsAnalysis.h +23 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsCallback.cpp +323 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsCallback.h +104 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsCallbackStruct.h +70 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsDebug.cpp +54 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsDebug.h +34 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsDeprecated.cpp +181 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsIis.cpp +1290 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsIis.h +139 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInfo.cpp +426 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInfo.h +421 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInfoDebug.cpp +175 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInfoDebug.h +27 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsInterface.cpp +4344 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLp.cpp +564 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLp.h +97 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLpSolverObject.h +47 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLpUtils.cpp +3794 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsLpUtils.h +330 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsModelUtils.cpp +1650 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsModelUtils.h +129 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsOptions.cpp +1176 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsOptions.h +1715 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsRanging.cpp +733 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsRanging.h +43 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolution.cpp +2194 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolution.h +179 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolutionDebug.cpp +490 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolutionDebug.h +87 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolve.cpp +747 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsSolve.h +29 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsStatus.cpp +48 -0
- data/ext/lpsolver-highs/highs/lp_data/HighsStatus.h +29 -0
- data/ext/lpsolver-highs/highs/lp_data/Iis.md +113 -0
- data/ext/lpsolver-highs/highs/meson.build +433 -0
- data/ext/lpsolver-highs/highs/mip/HighsCliqueTable.cpp +2236 -0
- data/ext/lpsolver-highs/highs/mip/HighsCliqueTable.h +329 -0
- data/ext/lpsolver-highs/highs/mip/HighsConflictPool.cpp +201 -0
- data/ext/lpsolver-highs/highs/mip/HighsConflictPool.h +109 -0
- data/ext/lpsolver-highs/highs/mip/HighsCutGeneration.cpp +1491 -0
- data/ext/lpsolver-highs/highs/mip/HighsCutGeneration.h +108 -0
- data/ext/lpsolver-highs/highs/mip/HighsCutPool.cpp +526 -0
- data/ext/lpsolver-highs/highs/mip/HighsCutPool.h +168 -0
- data/ext/lpsolver-highs/highs/mip/HighsDebugSol.cpp +313 -0
- data/ext/lpsolver-highs/highs/mip/HighsDebugSol.h +133 -0
- data/ext/lpsolver-highs/highs/mip/HighsDomain.cpp +3861 -0
- data/ext/lpsolver-highs/highs/mip/HighsDomain.h +657 -0
- data/ext/lpsolver-highs/highs/mip/HighsDomainChange.h +48 -0
- data/ext/lpsolver-highs/highs/mip/HighsDynamicRowMatrix.cpp +199 -0
- data/ext/lpsolver-highs/highs/mip/HighsDynamicRowMatrix.h +104 -0
- data/ext/lpsolver-highs/highs/mip/HighsFeasibilityJump.cpp +139 -0
- data/ext/lpsolver-highs/highs/mip/HighsGFkSolve.cpp +106 -0
- data/ext/lpsolver-highs/highs/mip/HighsGFkSolve.h +439 -0
- data/ext/lpsolver-highs/highs/mip/HighsImplications.cpp +915 -0
- data/ext/lpsolver-highs/highs/mip/HighsImplications.h +194 -0
- data/ext/lpsolver-highs/highs/mip/HighsLpAggregator.cpp +56 -0
- data/ext/lpsolver-highs/highs/mip/HighsLpAggregator.h +50 -0
- data/ext/lpsolver-highs/highs/mip/HighsLpRelaxation.cpp +1609 -0
- data/ext/lpsolver-highs/highs/mip/HighsLpRelaxation.h +361 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipAnalysis.cpp +313 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipAnalysis.h +71 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipSolver.cpp +1002 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipSolver.h +159 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipSolverData.cpp +2936 -0
- data/ext/lpsolver-highs/highs/mip/HighsMipSolverData.h +313 -0
- data/ext/lpsolver-highs/highs/mip/HighsModkSeparator.cpp +267 -0
- data/ext/lpsolver-highs/highs/mip/HighsModkSeparator.h +60 -0
- data/ext/lpsolver-highs/highs/mip/HighsNodeQueue.cpp +443 -0
- data/ext/lpsolver-highs/highs/mip/HighsNodeQueue.h +312 -0
- data/ext/lpsolver-highs/highs/mip/HighsObjectiveFunction.cpp +124 -0
- data/ext/lpsolver-highs/highs/mip/HighsObjectiveFunction.h +71 -0
- data/ext/lpsolver-highs/highs/mip/HighsPathSeparator.cpp +549 -0
- data/ext/lpsolver-highs/highs/mip/HighsPathSeparator.h +39 -0
- data/ext/lpsolver-highs/highs/mip/HighsPrimalHeuristics.cpp +1673 -0
- data/ext/lpsolver-highs/highs/mip/HighsPrimalHeuristics.h +75 -0
- data/ext/lpsolver-highs/highs/mip/HighsPseudocost.cpp +129 -0
- data/ext/lpsolver-highs/highs/mip/HighsPseudocost.h +366 -0
- data/ext/lpsolver-highs/highs/mip/HighsRedcostFixing.cpp +316 -0
- data/ext/lpsolver-highs/highs/mip/HighsRedcostFixing.h +42 -0
- data/ext/lpsolver-highs/highs/mip/HighsSearch.cpp +1881 -0
- data/ext/lpsolver-highs/highs/mip/HighsSearch.h +241 -0
- data/ext/lpsolver-highs/highs/mip/HighsSeparation.cpp +186 -0
- data/ext/lpsolver-highs/highs/mip/HighsSeparation.h +41 -0
- data/ext/lpsolver-highs/highs/mip/HighsSeparator.cpp +39 -0
- data/ext/lpsolver-highs/highs/mip/HighsSeparator.h +60 -0
- data/ext/lpsolver-highs/highs/mip/HighsTableauSeparator.cpp +244 -0
- data/ext/lpsolver-highs/highs/mip/HighsTableauSeparator.h +34 -0
- data/ext/lpsolver-highs/highs/mip/HighsTransformedLp.cpp +563 -0
- data/ext/lpsolver-highs/highs/mip/HighsTransformedLp.h +63 -0
- data/ext/lpsolver-highs/highs/mip/MipTimer.h +544 -0
- data/ext/lpsolver-highs/highs/mip/feasibilityjump.hh +800 -0
- data/ext/lpsolver-highs/highs/model/HighsHessian.cpp +263 -0
- data/ext/lpsolver-highs/highs/model/HighsHessian.h +54 -0
- data/ext/lpsolver-highs/highs/model/HighsHessianUtils.cpp +584 -0
- data/ext/lpsolver-highs/highs/model/HighsHessianUtils.h +47 -0
- data/ext/lpsolver-highs/highs/model/HighsModel.cpp +46 -0
- data/ext/lpsolver-highs/highs/model/HighsModel.h +42 -0
- data/ext/lpsolver-highs/highs/parallel/HighsBinarySemaphore.h +108 -0
- data/ext/lpsolver-highs/highs/parallel/HighsCacheAlign.h +82 -0
- data/ext/lpsolver-highs/highs/parallel/HighsCombinable.h +116 -0
- data/ext/lpsolver-highs/highs/parallel/HighsMutex.h +124 -0
- data/ext/lpsolver-highs/highs/parallel/HighsParallel.h +128 -0
- data/ext/lpsolver-highs/highs/parallel/HighsRaceTimer.h +38 -0
- data/ext/lpsolver-highs/highs/parallel/HighsSchedulerConstants.h +19 -0
- data/ext/lpsolver-highs/highs/parallel/HighsSpinMutex.h +48 -0
- data/ext/lpsolver-highs/highs/parallel/HighsSplitDeque.h +606 -0
- data/ext/lpsolver-highs/highs/parallel/HighsTask.h +170 -0
- data/ext/lpsolver-highs/highs/parallel/HighsTaskExecutor.cpp +43 -0
- data/ext/lpsolver-highs/highs/parallel/HighsTaskExecutor.h +217 -0
- data/ext/lpsolver-highs/highs/pdlp/CupdlpWrapper.cpp +848 -0
- data/ext/lpsolver-highs/highs/pdlp/CupdlpWrapper.h +108 -0
- data/ext/lpsolver-highs/highs/pdlp/HiPdlpTimer.h +155 -0
- data/ext/lpsolver-highs/highs/pdlp/HiPdlpWrapper.cpp +141 -0
- data/ext/lpsolver-highs/highs/pdlp/HiPdlpWrapper.h +26 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/Diff +12 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/Meld +7 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/Merge +2 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/README.md +95 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/CMakeLists.txt +58 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/cupdlp_cuda_kernels.cu +338 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/cupdlp_cuda_kernels.cuh +319 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/cupdlp_cudalinalg.cu +386 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/cupdlp_cudalinalg.cuh +149 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/test_cublas.c +154 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cuda/test_cuda_linalg.c +79 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp.h +16 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_cs.c +214 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_cs.h +40 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_defs.h +447 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_linalg.c +802 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_linalg.h +189 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_proj.c +148 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_proj.h +19 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_restart.c +124 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_restart.h +31 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_scaling.c +425 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_scaling.h +26 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_solver.c +1498 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_solver.h +105 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_step.c +478 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_step.h +37 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_utils.c +1850 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/cupdlp_utils.h +212 -0
- data/ext/lpsolver-highs/highs/pdlp/cupdlp/glbopts.h +342 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/defs.hpp +222 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/linalg.cc +231 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/linalg.hpp +61 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/logger.cc +225 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/logger.hpp +80 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdhg.cc +2798 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdhg.cu +497 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdhg.hpp +358 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdhg_kernels.hpp +77 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/pdlp_gpu_debug.hpp +62 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/restart.cc +132 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/restart.hpp +96 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/scaling.cc +307 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/scaling.hpp +74 -0
- data/ext/lpsolver-highs/highs/pdlp/hipdlp/solver_results.hpp +65 -0
- data/ext/lpsolver-highs/highs/presolve/HPresolve.cpp +8511 -0
- data/ext/lpsolver-highs/highs/presolve/HPresolve.h +505 -0
- data/ext/lpsolver-highs/highs/presolve/HPresolveAnalysis.cpp +239 -0
- data/ext/lpsolver-highs/highs/presolve/HPresolveAnalysis.h +52 -0
- data/ext/lpsolver-highs/highs/presolve/HighsPostsolveStack.cpp +1368 -0
- data/ext/lpsolver-highs/highs/presolve/HighsPostsolveStack.h +943 -0
- data/ext/lpsolver-highs/highs/presolve/HighsSymmetry.cpp +1921 -0
- data/ext/lpsolver-highs/highs/presolve/HighsSymmetry.h +284 -0
- data/ext/lpsolver-highs/highs/presolve/ICrash.cpp +474 -0
- data/ext/lpsolver-highs/highs/presolve/ICrash.h +124 -0
- data/ext/lpsolver-highs/highs/presolve/ICrashUtil.cpp +267 -0
- data/ext/lpsolver-highs/highs/presolve/ICrashUtil.h +62 -0
- data/ext/lpsolver-highs/highs/presolve/ICrashX.cpp +173 -0
- data/ext/lpsolver-highs/highs/presolve/ICrashX.h +23 -0
- data/ext/lpsolver-highs/highs/presolve/PresolveComponent.cpp +45 -0
- data/ext/lpsolver-highs/highs/presolve/PresolveComponent.h +90 -0
- data/ext/lpsolver-highs/highs/qpsolver/README.md +185 -0
- data/ext/lpsolver-highs/highs/qpsolver/a_asm.cpp +139 -0
- data/ext/lpsolver-highs/highs/qpsolver/a_asm.hpp +77 -0
- data/ext/lpsolver-highs/highs/qpsolver/a_quass.cpp +194 -0
- data/ext/lpsolver-highs/highs/qpsolver/a_quass.hpp +22 -0
- data/ext/lpsolver-highs/highs/qpsolver/basis.cpp +443 -0
- data/ext/lpsolver-highs/highs/qpsolver/basis.hpp +159 -0
- data/ext/lpsolver-highs/highs/qpsolver/crashsolution.hpp +20 -0
- data/ext/lpsolver-highs/highs/qpsolver/dantzigpricing.hpp +80 -0
- data/ext/lpsolver-highs/highs/qpsolver/devexharrispricing.hpp +98 -0
- data/ext/lpsolver-highs/highs/qpsolver/devexpricing.hpp +108 -0
- data/ext/lpsolver-highs/highs/qpsolver/eventhandler.hpp +30 -0
- data/ext/lpsolver-highs/highs/qpsolver/factor.hpp +408 -0
- data/ext/lpsolver-highs/highs/qpsolver/feasibility_bounded.hpp +114 -0
- data/ext/lpsolver-highs/highs/qpsolver/feasibility_highs.hpp +301 -0
- data/ext/lpsolver-highs/highs/qpsolver/gradient.hpp +46 -0
- data/ext/lpsolver-highs/highs/qpsolver/instance.hpp +70 -0
- data/ext/lpsolver-highs/highs/qpsolver/matrix.hpp +342 -0
- data/ext/lpsolver-highs/highs/qpsolver/perturbation.cpp +41 -0
- data/ext/lpsolver-highs/highs/qpsolver/perturbation.hpp +15 -0
- data/ext/lpsolver-highs/highs/qpsolver/pricing.hpp +22 -0
- data/ext/lpsolver-highs/highs/qpsolver/qpconst.hpp +34 -0
- data/ext/lpsolver-highs/highs/qpsolver/qpvector.hpp +242 -0
- data/ext/lpsolver-highs/highs/qpsolver/quass.cpp +551 -0
- data/ext/lpsolver-highs/highs/qpsolver/quass.hpp +27 -0
- data/ext/lpsolver-highs/highs/qpsolver/ratiotest.cpp +146 -0
- data/ext/lpsolver-highs/highs/qpsolver/ratiotest.hpp +26 -0
- data/ext/lpsolver-highs/highs/qpsolver/reducedcosts.hpp +46 -0
- data/ext/lpsolver-highs/highs/qpsolver/reducedgradient.hpp +95 -0
- data/ext/lpsolver-highs/highs/qpsolver/runtime.hpp +45 -0
- data/ext/lpsolver-highs/highs/qpsolver/scaling.cpp +123 -0
- data/ext/lpsolver-highs/highs/qpsolver/scaling.hpp +15 -0
- data/ext/lpsolver-highs/highs/qpsolver/settings.hpp +84 -0
- data/ext/lpsolver-highs/highs/qpsolver/snippets.hpp +36 -0
- data/ext/lpsolver-highs/highs/qpsolver/statistics.hpp +30 -0
- data/ext/lpsolver-highs/highs/qpsolver/steepestedgepricing.hpp +173 -0
- data/ext/lpsolver-highs/highs/simplex/HApp.h +550 -0
- data/ext/lpsolver-highs/highs/simplex/HEkk.cpp +4404 -0
- data/ext/lpsolver-highs/highs/simplex/HEkk.h +419 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkControl.cpp +146 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDebug.cpp +1722 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDual.cpp +3003 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDual.h +513 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualMulti.cpp +1020 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualRHS.cpp +535 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualRHS.h +134 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualRow.cpp +697 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkDualRow.h +201 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkInterface.cpp +26 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkPrimal.cpp +2984 -0
- data/ext/lpsolver-highs/highs/simplex/HEkkPrimal.h +191 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplex.cpp +330 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplex.h +42 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexDebug.cpp +145 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexDebug.h +48 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNla.cpp +517 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNla.h +158 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNlaDebug.cpp +373 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNlaFreeze.cpp +28 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexNlaProductForm.cpp +113 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexReport.cpp +77 -0
- data/ext/lpsolver-highs/highs/simplex/HSimplexReport.h +21 -0
- data/ext/lpsolver-highs/highs/simplex/HighsSimplexAnalysis.cpp +1495 -0
- data/ext/lpsolver-highs/highs/simplex/HighsSimplexAnalysis.h +500 -0
- data/ext/lpsolver-highs/highs/simplex/SimplexConst.h +273 -0
- data/ext/lpsolver-highs/highs/simplex/SimplexStruct.h +263 -0
- data/ext/lpsolver-highs/highs/simplex/SimplexTimer.h +414 -0
- data/ext/lpsolver-highs/highs/test_kkt/DevKkt.cpp +469 -0
- data/ext/lpsolver-highs/highs/test_kkt/DevKkt.h +143 -0
- data/ext/lpsolver-highs/highs/test_kkt/KktCh2.cpp +305 -0
- data/ext/lpsolver-highs/highs/test_kkt/KktCh2.h +79 -0
- data/ext/lpsolver-highs/highs/util/FactorTimer.h +199 -0
- data/ext/lpsolver-highs/highs/util/HFactor.cpp +2597 -0
- data/ext/lpsolver-highs/highs/util/HFactor.h +587 -0
- data/ext/lpsolver-highs/highs/util/HFactorConst.h +81 -0
- data/ext/lpsolver-highs/highs/util/HFactorDebug.cpp +231 -0
- data/ext/lpsolver-highs/highs/util/HFactorDebug.h +55 -0
- data/ext/lpsolver-highs/highs/util/HFactorExtend.cpp +229 -0
- data/ext/lpsolver-highs/highs/util/HFactorRefactor.cpp +304 -0
- data/ext/lpsolver-highs/highs/util/HFactorUtils.cpp +122 -0
- data/ext/lpsolver-highs/highs/util/HSet.cpp +197 -0
- data/ext/lpsolver-highs/highs/util/HSet.h +89 -0
- data/ext/lpsolver-highs/highs/util/HVector.h +22 -0
- data/ext/lpsolver-highs/highs/util/HVectorBase.cpp +271 -0
- data/ext/lpsolver-highs/highs/util/HVectorBase.h +102 -0
- data/ext/lpsolver-highs/highs/util/HighsCDouble.h +323 -0
- data/ext/lpsolver-highs/highs/util/HighsComponent.h +53 -0
- data/ext/lpsolver-highs/highs/util/HighsDataStack.h +83 -0
- data/ext/lpsolver-highs/highs/util/HighsDisjointSets.h +107 -0
- data/ext/lpsolver-highs/highs/util/HighsHash.cpp +10 -0
- data/ext/lpsolver-highs/highs/util/HighsHash.h +1274 -0
- data/ext/lpsolver-highs/highs/util/HighsHashTree.h +1461 -0
- data/ext/lpsolver-highs/highs/util/HighsInt.h +36 -0
- data/ext/lpsolver-highs/highs/util/HighsIntegers.h +212 -0
- data/ext/lpsolver-highs/highs/util/HighsLinearSumBounds.cpp +267 -0
- data/ext/lpsolver-highs/highs/util/HighsLinearSumBounds.h +203 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixPic.cpp +146 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixPic.h +37 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixSlice.h +561 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixUtils.cpp +407 -0
- data/ext/lpsolver-highs/highs/util/HighsMatrixUtils.h +57 -0
- data/ext/lpsolver-highs/highs/util/HighsMemoryAllocation.h +63 -0
- data/ext/lpsolver-highs/highs/util/HighsRandom.h +242 -0
- data/ext/lpsolver-highs/highs/util/HighsRbTree.h +452 -0
- data/ext/lpsolver-highs/highs/util/HighsSort.cpp +364 -0
- data/ext/lpsolver-highs/highs/util/HighsSort.h +131 -0
- data/ext/lpsolver-highs/highs/util/HighsSparseMatrix.cpp +1746 -0
- data/ext/lpsolver-highs/highs/util/HighsSparseMatrix.h +151 -0
- data/ext/lpsolver-highs/highs/util/HighsSparseVectorSum.h +95 -0
- data/ext/lpsolver-highs/highs/util/HighsSplay.h +135 -0
- data/ext/lpsolver-highs/highs/util/HighsTimer.h +385 -0
- data/ext/lpsolver-highs/highs/util/HighsUtils.cpp +1259 -0
- data/ext/lpsolver-highs/highs/util/HighsUtils.h +272 -0
- data/ext/lpsolver-highs/highs/util/stringutil.cpp +131 -0
- data/ext/lpsolver-highs/highs/util/stringutil.h +46 -0
- data/ext/lpsolver-highs/highs.pc.in +12 -0
- data/ext/lpsolver-highs/meson.build +198 -0
- data/ext/lpsolver-highs/meson_options.txt +31 -0
- data/ext/lpsolver-highs/nuget/HiGHS_Logo.png +0 -0
- data/ext/lpsolver-highs/nuget/Highs.csproj +25 -0
- data/ext/lpsolver-highs/nuget/Highs.csproj.in +36 -0
- data/ext/lpsolver-highs/nuget/HowToAlternative.md +77 -0
- data/ext/lpsolver-highs/nuget/README.md +38 -0
- data/ext/lpsolver-highs/nuget/arm-toolchain.cmake +15 -0
- data/ext/lpsolver-highs/nuget/build_linux-arm.sh +13 -0
- data/ext/lpsolver-highs/nuget/build_linux.sh +10 -0
- data/ext/lpsolver-highs/nuget/build_windows.ps1 +27 -0
- data/ext/lpsolver-highs/nuget/generatePackage.ps1 +28 -0
- data/ext/lpsolver-highs/pyproject.toml +221 -0
- data/ext/lpsolver-highs/subprojects/pybind11.wrap +13 -0
- data/ext/lpsolver-highs/tests/test_highspy.py +2310 -0
- data/ext/lpsolver-highs/version.rc.in +50 -0
- data/lib/lpsolver/highs +0 -0
- data/lib/lpsolver/model.rb +28 -4
- data/lib/lpsolver/native.so +0 -0
- data/lib/lpsolver/native_model.rb +261 -0
- data/lib/lpsolver/solution.rb +72 -7
- data/lib/lpsolver/version.rb +1 -1
- data/lpsolver.gemspec +4 -1
- metadata +1176 -4
|
@@ -0,0 +1,4344 @@
|
|
|
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 lp_data/HighsInterface.cpp
|
|
9
|
+
* @brief
|
|
10
|
+
*/
|
|
11
|
+
#include <sstream>
|
|
12
|
+
#include <unordered_set>
|
|
13
|
+
|
|
14
|
+
#include "Highs.h"
|
|
15
|
+
#include "lp_data/HighsLpUtils.h"
|
|
16
|
+
#include "lp_data/HighsModelUtils.h"
|
|
17
|
+
#include "mip/HighsMipSolver.h" // For getGapString
|
|
18
|
+
#include "model/HighsHessianUtils.h"
|
|
19
|
+
#include "simplex/HSimplex.h"
|
|
20
|
+
#include "util/HighsMatrixUtils.h"
|
|
21
|
+
#include "util/HighsSort.h"
|
|
22
|
+
|
|
23
|
+
void Highs::reportModelStats() const {
|
|
24
|
+
const HighsLp& lp = this->model_.lp_;
|
|
25
|
+
const HighsHessian& hessian = this->model_.hessian_;
|
|
26
|
+
const HighsLogOptions& log_options = this->options_.log_options;
|
|
27
|
+
if (!*log_options.output_flag) return;
|
|
28
|
+
HighsInt num_integer = 0;
|
|
29
|
+
HighsInt num_binary = 0;
|
|
30
|
+
HighsInt num_semi_continuous = 0;
|
|
31
|
+
HighsInt num_semi_integer = 0;
|
|
32
|
+
for (HighsInt iCol = 0; iCol < static_cast<HighsInt>(lp.integrality_.size());
|
|
33
|
+
iCol++) {
|
|
34
|
+
switch (lp.integrality_[iCol]) {
|
|
35
|
+
case HighsVarType::kInteger:
|
|
36
|
+
num_integer++;
|
|
37
|
+
if (lp.col_lower_[iCol] == 0 && lp.col_upper_[iCol] == 1) num_binary++;
|
|
38
|
+
break;
|
|
39
|
+
case HighsVarType::kSemiContinuous:
|
|
40
|
+
num_semi_continuous++;
|
|
41
|
+
break;
|
|
42
|
+
case HighsVarType::kSemiInteger:
|
|
43
|
+
num_semi_integer++;
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
std::string problem_type;
|
|
50
|
+
const bool non_continuous =
|
|
51
|
+
num_integer + num_semi_continuous + num_semi_integer;
|
|
52
|
+
if (hessian.dim_) {
|
|
53
|
+
if (non_continuous) {
|
|
54
|
+
problem_type = "MIQP";
|
|
55
|
+
} else {
|
|
56
|
+
problem_type = "QP";
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
if (non_continuous) {
|
|
60
|
+
problem_type = "MIP";
|
|
61
|
+
} else {
|
|
62
|
+
problem_type = "LP";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const HighsInt a_num_nz = lp.a_matrix_.numNz();
|
|
66
|
+
const HighsInt q_num_nz = hessian.dim_ > 0 ? hessian.numNz() : 0;
|
|
67
|
+
if (*log_options.log_dev_level) {
|
|
68
|
+
highsLogDev(log_options, HighsLogType::kInfo, "%4s : %s\n",
|
|
69
|
+
problem_type.c_str(), lp.model_name_.c_str());
|
|
70
|
+
highsLogDev(log_options, HighsLogType::kInfo,
|
|
71
|
+
"Row%s : %" HIGHSINT_FORMAT "\n",
|
|
72
|
+
lp.num_row_ == 1 ? "" : "s", lp.num_row_);
|
|
73
|
+
highsLogDev(log_options, HighsLogType::kInfo,
|
|
74
|
+
"Col%s : %" HIGHSINT_FORMAT "\n",
|
|
75
|
+
lp.num_col_ == 1 ? "" : "s", lp.num_col_);
|
|
76
|
+
if (q_num_nz) {
|
|
77
|
+
highsLogDev(log_options, HighsLogType::kInfo,
|
|
78
|
+
"Matrix Nz : %" HIGHSINT_FORMAT "\n", a_num_nz);
|
|
79
|
+
highsLogDev(log_options, HighsLogType::kInfo,
|
|
80
|
+
"Hessian Nz: %" HIGHSINT_FORMAT "\n", q_num_nz);
|
|
81
|
+
} else {
|
|
82
|
+
highsLogDev(log_options, HighsLogType::kInfo,
|
|
83
|
+
"Nonzero%s : %" HIGHSINT_FORMAT "\n",
|
|
84
|
+
a_num_nz == 1 ? "" : "s", a_num_nz);
|
|
85
|
+
}
|
|
86
|
+
if (num_integer)
|
|
87
|
+
highsLogDev(log_options, HighsLogType::kInfo,
|
|
88
|
+
"Integer : %" HIGHSINT_FORMAT " (%" HIGHSINT_FORMAT
|
|
89
|
+
" binary)\n",
|
|
90
|
+
num_integer, num_binary);
|
|
91
|
+
if (num_semi_continuous)
|
|
92
|
+
highsLogDev(log_options, HighsLogType::kInfo,
|
|
93
|
+
"SemiConts : %" HIGHSINT_FORMAT "\n", num_semi_continuous);
|
|
94
|
+
if (num_semi_integer)
|
|
95
|
+
highsLogDev(log_options, HighsLogType::kInfo,
|
|
96
|
+
"SemiInt : %" HIGHSINT_FORMAT "\n", num_semi_integer);
|
|
97
|
+
} else {
|
|
98
|
+
std::stringstream stats_line;
|
|
99
|
+
stats_line << problem_type;
|
|
100
|
+
if (lp.model_name_.length()) stats_line << " " << lp.model_name_;
|
|
101
|
+
stats_line << " has " << lp.num_row_ << " row"
|
|
102
|
+
<< (lp.num_row_ == 1 ? "" : "s") << "; " << lp.num_col_ << " col"
|
|
103
|
+
<< (lp.num_col_ == 1 ? "" : "s");
|
|
104
|
+
if (q_num_nz) {
|
|
105
|
+
stats_line << "; " << a_num_nz << " matrix nonzero"
|
|
106
|
+
<< (a_num_nz == 1 ? "" : "s");
|
|
107
|
+
stats_line << "; " << q_num_nz << " Hessian nonzero"
|
|
108
|
+
<< (q_num_nz == 1 ? "" : "s");
|
|
109
|
+
} else {
|
|
110
|
+
stats_line << "; " << a_num_nz << " nonzero"
|
|
111
|
+
<< (a_num_nz == 1 ? "" : "s");
|
|
112
|
+
}
|
|
113
|
+
if (num_integer)
|
|
114
|
+
stats_line << "; " << num_integer << " integer variable"
|
|
115
|
+
<< (a_num_nz == 1 ? "" : "s") << " (" << num_binary
|
|
116
|
+
<< " binary)";
|
|
117
|
+
if (num_semi_continuous)
|
|
118
|
+
stats_line << "; " << num_semi_continuous << " semi-continuous variables";
|
|
119
|
+
if (num_semi_integer)
|
|
120
|
+
stats_line << "; " << num_semi_integer << " semi-integer variables";
|
|
121
|
+
highsLogUser(log_options, HighsLogType::kInfo, "%s\n",
|
|
122
|
+
stats_line.str().c_str());
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
HighsStatus Highs::formStandardFormLp() {
|
|
127
|
+
this->clearStandardFormLp();
|
|
128
|
+
HighsLp& lp = this->model_.lp_;
|
|
129
|
+
HighsSparseMatrix& matrix = lp.a_matrix_;
|
|
130
|
+
// Ensure that the incumbent LP and standard form LP matrices are rowwise
|
|
131
|
+
matrix.ensureRowwise();
|
|
132
|
+
// Original rows are processed before columns, so that any original
|
|
133
|
+
// boxed rows can be transformed to pairs of one-sided rows,
|
|
134
|
+
// requiring the standard form matrix to be row-wise. The original
|
|
135
|
+
// columns are assumed to come before any new columns, so their
|
|
136
|
+
// costs (as a minimization) must be defined befor costs of new
|
|
137
|
+
// columns.
|
|
138
|
+
// Determine the objective scaling, and apply it to any offset
|
|
139
|
+
HighsInt sense = HighsInt(lp.sense_);
|
|
140
|
+
this->standard_form_offset_ = sense * lp.offset_;
|
|
141
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
|
|
142
|
+
this->standard_form_cost_.push_back(sense * lp.col_cost_[iCol]);
|
|
143
|
+
this->standard_form_matrix_.format_ = MatrixFormat::kRowwise;
|
|
144
|
+
this->standard_form_matrix_.num_col_ = lp.num_col_;
|
|
145
|
+
// Create a HighsSparseMatrix instance to store rows extracted from
|
|
146
|
+
// the original constraint matrix
|
|
147
|
+
HighsInt local_row_min_nnz = std::max(lp.num_col_, HighsInt(2));
|
|
148
|
+
HighsSparseMatrix local_row;
|
|
149
|
+
local_row.ensureRowwise();
|
|
150
|
+
local_row.num_row_ = 1;
|
|
151
|
+
local_row.num_col_ = lp.num_col_;
|
|
152
|
+
local_row.index_.resize(local_row_min_nnz);
|
|
153
|
+
local_row.value_.resize(local_row_min_nnz);
|
|
154
|
+
local_row.start_.resize(2);
|
|
155
|
+
HighsInt& num_nz = local_row.start_[1];
|
|
156
|
+
local_row.start_[0] = 0;
|
|
157
|
+
HighsInt num_fixed_row = 0;
|
|
158
|
+
HighsInt num_boxed_row = 0;
|
|
159
|
+
HighsInt num_lower_row = 0;
|
|
160
|
+
HighsInt num_upper_row = 0;
|
|
161
|
+
HighsInt num_free_row = 0;
|
|
162
|
+
HighsInt num_fixed_col = 0;
|
|
163
|
+
HighsInt num_boxed_col = 0;
|
|
164
|
+
HighsInt num_lower_col = 0;
|
|
165
|
+
HighsInt num_upper_col = 0;
|
|
166
|
+
HighsInt num_free_col = 0;
|
|
167
|
+
std::vector<HighsInt> slack_ix;
|
|
168
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
169
|
+
double lower = lp.row_lower_[iRow];
|
|
170
|
+
double upper = lp.row_upper_[iRow];
|
|
171
|
+
if (lower <= -kHighsInf && upper >= kHighsInf) {
|
|
172
|
+
assert(0 == 1);
|
|
173
|
+
// Free row
|
|
174
|
+
num_free_row++;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (lower == upper) {
|
|
178
|
+
// Equality row
|
|
179
|
+
num_fixed_row++;
|
|
180
|
+
matrix.getRow(iRow, num_nz, local_row.index_.data(),
|
|
181
|
+
local_row.value_.data());
|
|
182
|
+
this->standard_form_matrix_.addRows(local_row);
|
|
183
|
+
this->standard_form_rhs_.push_back(upper);
|
|
184
|
+
continue;
|
|
185
|
+
} else if (lower <= -kHighsInf) {
|
|
186
|
+
// Upper bounded row, so record the slack
|
|
187
|
+
num_upper_row++;
|
|
188
|
+
assert(upper < kHighsInf);
|
|
189
|
+
HighsInt standard_form_row = this->standard_form_rhs_.size();
|
|
190
|
+
slack_ix.push_back(standard_form_row + 1);
|
|
191
|
+
matrix.getRow(iRow, num_nz, local_row.index_.data(),
|
|
192
|
+
local_row.value_.data());
|
|
193
|
+
this->standard_form_matrix_.addRows(local_row);
|
|
194
|
+
this->standard_form_rhs_.push_back(upper);
|
|
195
|
+
} else if (upper >= kHighsInf) {
|
|
196
|
+
// Lower bounded row, so record the slack
|
|
197
|
+
num_lower_row++;
|
|
198
|
+
assert(lower > -kHighsInf);
|
|
199
|
+
HighsInt standard_form_row = this->standard_form_rhs_.size();
|
|
200
|
+
slack_ix.push_back(-(standard_form_row + 1));
|
|
201
|
+
matrix.getRow(iRow, num_nz, local_row.index_.data(),
|
|
202
|
+
local_row.value_.data());
|
|
203
|
+
this->standard_form_matrix_.addRows(local_row);
|
|
204
|
+
this->standard_form_rhs_.push_back(lower);
|
|
205
|
+
} else {
|
|
206
|
+
// Boxed row, so record the lower slack
|
|
207
|
+
assert(lower > -kHighsInf);
|
|
208
|
+
assert(upper < kHighsInf);
|
|
209
|
+
num_boxed_row++;
|
|
210
|
+
HighsInt standard_form_row = this->standard_form_rhs_.size();
|
|
211
|
+
slack_ix.push_back(-(standard_form_row + 1));
|
|
212
|
+
matrix.getRow(iRow, num_nz, local_row.index_.data(),
|
|
213
|
+
local_row.value_.data());
|
|
214
|
+
this->standard_form_matrix_.addRows(local_row);
|
|
215
|
+
this->standard_form_rhs_.push_back(lower);
|
|
216
|
+
// .. and upper slack, adding a copy of the row
|
|
217
|
+
standard_form_row = this->standard_form_rhs_.size();
|
|
218
|
+
slack_ix.push_back(standard_form_row + 1);
|
|
219
|
+
this->standard_form_matrix_.addRows(local_row);
|
|
220
|
+
this->standard_form_rhs_.push_back(upper);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// Add rows corresponding to boxed columns
|
|
224
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
225
|
+
double lower = lp.col_lower_[iCol];
|
|
226
|
+
double upper = lp.col_upper_[iCol];
|
|
227
|
+
if (lower > -kHighsInf && upper < kHighsInf) {
|
|
228
|
+
// Boxed column
|
|
229
|
+
//
|
|
230
|
+
// x will be replaced by x = l + X (below) with X >= 0
|
|
231
|
+
//
|
|
232
|
+
// Introduce variable s >= 0 so that (with x >= l still)
|
|
233
|
+
//
|
|
234
|
+
// x = u - s => x + s = u
|
|
235
|
+
this->standard_form_cost_.push_back(0);
|
|
236
|
+
this->standard_form_matrix_.num_col_++;
|
|
237
|
+
local_row.num_col_++;
|
|
238
|
+
local_row.index_[0] = iCol;
|
|
239
|
+
local_row.index_[1] = this->standard_form_matrix_.num_col_ - 1;
|
|
240
|
+
local_row.value_[0] = 1;
|
|
241
|
+
local_row.value_[1] = 1;
|
|
242
|
+
local_row.start_[1] = 2;
|
|
243
|
+
this->standard_form_matrix_.addRows(local_row);
|
|
244
|
+
this->standard_form_rhs_.push_back(upper);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// Finished with both matrices, row-wise, so ensure that the
|
|
248
|
+
// incumbent matrix leaves col-wise, and that the standard form
|
|
249
|
+
// matrix is col-wise so RHS shifts can be applied and more columns
|
|
250
|
+
// can be added
|
|
251
|
+
matrix.ensureColwise();
|
|
252
|
+
this->standard_form_matrix_.ensureColwise();
|
|
253
|
+
// Work through the columns, ensuring that all have non-negativity bounds
|
|
254
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
255
|
+
double cost = sense * lp.col_cost_[iCol];
|
|
256
|
+
double lower = lp.col_lower_[iCol];
|
|
257
|
+
double upper = lp.col_upper_[iCol];
|
|
258
|
+
if (lower > -kHighsInf) {
|
|
259
|
+
// Finite lower bound
|
|
260
|
+
if (upper < kHighsInf) {
|
|
261
|
+
if (lower == upper) {
|
|
262
|
+
// Fixed column
|
|
263
|
+
num_fixed_col++;
|
|
264
|
+
} else {
|
|
265
|
+
// Boxed column
|
|
266
|
+
num_boxed_col++;
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
// Lower column
|
|
270
|
+
num_lower_col++;
|
|
271
|
+
}
|
|
272
|
+
if (lower != 0) {
|
|
273
|
+
// x >= l, so shift x-l = X >= 0, giving x = X + l
|
|
274
|
+
//
|
|
275
|
+
// Cost contribution c(X+l) = cX + cl
|
|
276
|
+
this->standard_form_offset_ += cost * lower;
|
|
277
|
+
// Constraint contribution a(X+l) = aX + al
|
|
278
|
+
for (HighsInt iEl = this->standard_form_matrix_.start_[iCol];
|
|
279
|
+
iEl < this->standard_form_matrix_.start_[iCol + 1]; iEl++)
|
|
280
|
+
this->standard_form_rhs_[this->standard_form_matrix_.index_[iEl]] -=
|
|
281
|
+
this->standard_form_matrix_.value_[iEl] * lower;
|
|
282
|
+
}
|
|
283
|
+
} else if (upper < kHighsInf) {
|
|
284
|
+
// Upper column
|
|
285
|
+
num_upper_col++;
|
|
286
|
+
// Have to operate even if u=0, since cost and column values are negated
|
|
287
|
+
//
|
|
288
|
+
// x <= u, so shift u-x = X >= 0, giving x = u - X
|
|
289
|
+
//
|
|
290
|
+
// Cost contribution c(u-X) = cu - cX
|
|
291
|
+
this->standard_form_offset_ += cost * upper;
|
|
292
|
+
this->standard_form_cost_[iCol] = -cost;
|
|
293
|
+
// Constraint contribution a(u-X) = -aX + au
|
|
294
|
+
for (HighsInt iEl = this->standard_form_matrix_.start_[iCol];
|
|
295
|
+
iEl < this->standard_form_matrix_.start_[iCol + 1]; iEl++) {
|
|
296
|
+
this->standard_form_rhs_[this->standard_form_matrix_.index_[iEl]] -=
|
|
297
|
+
this->standard_form_matrix_.value_[iEl] * upper;
|
|
298
|
+
this->standard_form_matrix_.value_[iEl] =
|
|
299
|
+
-this->standard_form_matrix_.value_[iEl];
|
|
300
|
+
}
|
|
301
|
+
} else {
|
|
302
|
+
// Free column
|
|
303
|
+
num_free_col++;
|
|
304
|
+
// Represent as x = x+ - x-
|
|
305
|
+
//
|
|
306
|
+
// where original column is now x+ >= 0
|
|
307
|
+
//
|
|
308
|
+
// and x- >= 0 has negation of its cost and matrix column
|
|
309
|
+
this->standard_form_cost_.push_back(-cost);
|
|
310
|
+
for (HighsInt iEl = this->standard_form_matrix_.start_[iCol];
|
|
311
|
+
iEl < this->standard_form_matrix_.start_[iCol + 1]; iEl++) {
|
|
312
|
+
this->standard_form_matrix_.index_.push_back(
|
|
313
|
+
this->standard_form_matrix_.index_[iEl]);
|
|
314
|
+
this->standard_form_matrix_.value_.push_back(
|
|
315
|
+
-this->standard_form_matrix_.value_[iEl]);
|
|
316
|
+
}
|
|
317
|
+
this->standard_form_matrix_.start_.push_back(
|
|
318
|
+
HighsInt(this->standard_form_matrix_.index_.size()));
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
// Now add the slack variables
|
|
322
|
+
for (HighsInt iRow : slack_ix) {
|
|
323
|
+
this->standard_form_cost_.push_back(0);
|
|
324
|
+
if (iRow > 0) {
|
|
325
|
+
this->standard_form_matrix_.index_.push_back(iRow - 1);
|
|
326
|
+
this->standard_form_matrix_.value_.push_back(1);
|
|
327
|
+
} else {
|
|
328
|
+
this->standard_form_matrix_.index_.push_back(-iRow - 1);
|
|
329
|
+
this->standard_form_matrix_.value_.push_back(-1);
|
|
330
|
+
}
|
|
331
|
+
this->standard_form_matrix_.start_.push_back(
|
|
332
|
+
HighsInt(this->standard_form_matrix_.index_.size()));
|
|
333
|
+
}
|
|
334
|
+
// Now set correct values for the dimensions of this->standard_form_matrix_
|
|
335
|
+
this->standard_form_matrix_.num_col_ = int(standard_form_cost_.size());
|
|
336
|
+
this->standard_form_matrix_.num_row_ = int(standard_form_rhs_.size());
|
|
337
|
+
this->standard_form_valid_ = true;
|
|
338
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
339
|
+
"Standard form LP obtained for LP with (free / lower / upper / "
|
|
340
|
+
"boxed / fixed) variables"
|
|
341
|
+
" (%d / %d / %d / %d / %d) and constraints"
|
|
342
|
+
" (%d / %d / %d / %d / %d) \n",
|
|
343
|
+
int(num_free_col), int(num_lower_col), int(num_upper_col),
|
|
344
|
+
int(num_boxed_col), int(num_fixed_col), int(num_free_row),
|
|
345
|
+
int(num_lower_row), int(num_upper_row), int(num_boxed_row),
|
|
346
|
+
int(num_fixed_row));
|
|
347
|
+
return HighsStatus::kOk;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
HighsStatus Highs::basisForSolution() {
|
|
351
|
+
HighsLp& lp = model_.lp_;
|
|
352
|
+
assert(!lp.isMip() || options_.solve_relaxation);
|
|
353
|
+
assert(solution_.value_valid);
|
|
354
|
+
invalidateBasis();
|
|
355
|
+
HighsInt num_basic = 0;
|
|
356
|
+
HighsBasis basis;
|
|
357
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
358
|
+
if (std::fabs(lp.col_lower_[iCol] - solution_.col_value[iCol]) <=
|
|
359
|
+
options_.primal_feasibility_tolerance) {
|
|
360
|
+
basis.col_status.push_back(HighsBasisStatus::kLower);
|
|
361
|
+
} else if (std::fabs(lp.col_upper_[iCol] - solution_.col_value[iCol]) <=
|
|
362
|
+
options_.primal_feasibility_tolerance) {
|
|
363
|
+
basis.col_status.push_back(HighsBasisStatus::kUpper);
|
|
364
|
+
} else {
|
|
365
|
+
num_basic++;
|
|
366
|
+
basis.col_status.push_back(HighsBasisStatus::kBasic);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
const HighsInt num_basic_col = num_basic;
|
|
370
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
371
|
+
if (std::fabs(lp.row_lower_[iRow] - solution_.row_value[iRow]) <=
|
|
372
|
+
options_.primal_feasibility_tolerance) {
|
|
373
|
+
basis.row_status.push_back(HighsBasisStatus::kLower);
|
|
374
|
+
} else if (std::fabs(lp.row_upper_[iRow] - solution_.row_value[iRow]) <=
|
|
375
|
+
options_.primal_feasibility_tolerance) {
|
|
376
|
+
basis.row_status.push_back(HighsBasisStatus::kUpper);
|
|
377
|
+
} else {
|
|
378
|
+
num_basic++;
|
|
379
|
+
basis.row_status.push_back(HighsBasisStatus::kBasic);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
const HighsInt num_basic_row = num_basic - num_basic_col;
|
|
383
|
+
assert((int)basis.col_status.size() == lp.num_col_);
|
|
384
|
+
assert((int)basis.row_status.size() == lp.num_row_);
|
|
385
|
+
highsLogDev(options_.log_options, HighsLogType::kInfo,
|
|
386
|
+
"LP has %d rows and solution yields %d possible basic variables "
|
|
387
|
+
"(%d / %d; %d / %d)\n",
|
|
388
|
+
(int)lp.num_row_, (int)num_basic, (int)num_basic_col,
|
|
389
|
+
(int)lp.num_col_, (int)num_basic_row, (int)lp.num_row_);
|
|
390
|
+
return this->setBasis(basis);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
HighsStatus Highs::addColsInterface(
|
|
394
|
+
HighsInt ext_num_new_col, const double* ext_col_cost,
|
|
395
|
+
const double* ext_col_lower, const double* ext_col_upper,
|
|
396
|
+
HighsInt ext_num_new_nz, const HighsInt* ext_a_start,
|
|
397
|
+
const HighsInt* ext_a_index, const double* ext_a_value) {
|
|
398
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
399
|
+
HighsOptions& options = options_;
|
|
400
|
+
if (ext_num_new_col < 0) return HighsStatus::kError;
|
|
401
|
+
if (ext_num_new_nz < 0) return HighsStatus::kError;
|
|
402
|
+
if (ext_num_new_col == 0) return HighsStatus::kOk;
|
|
403
|
+
if (ext_num_new_col > 0)
|
|
404
|
+
if (isColDataNull(options.log_options, ext_col_cost, ext_col_lower,
|
|
405
|
+
ext_col_upper))
|
|
406
|
+
return HighsStatus::kError;
|
|
407
|
+
if (ext_num_new_nz > 0)
|
|
408
|
+
if (isMatrixDataNull(options.log_options, ext_a_start, ext_a_index,
|
|
409
|
+
ext_a_value))
|
|
410
|
+
return HighsStatus::kError;
|
|
411
|
+
|
|
412
|
+
HighsLp& lp = model_.lp_;
|
|
413
|
+
HighsBasis& basis = basis_;
|
|
414
|
+
HighsScale& scale = lp.scale_;
|
|
415
|
+
bool& useful_basis = basis.useful;
|
|
416
|
+
bool& lp_has_scaling = lp.scale_.has_scaling;
|
|
417
|
+
|
|
418
|
+
// Check that if nonzeros are to be added then the model has a positive number
|
|
419
|
+
// of rows
|
|
420
|
+
if (lp.num_row_ <= 0 && ext_num_new_nz > 0) return HighsStatus::kError;
|
|
421
|
+
|
|
422
|
+
// Record the new number of columns
|
|
423
|
+
HighsInt newNumCol = lp.num_col_ + ext_num_new_col;
|
|
424
|
+
|
|
425
|
+
HighsIndexCollection index_collection;
|
|
426
|
+
index_collection.dimension_ = ext_num_new_col;
|
|
427
|
+
index_collection.is_interval_ = true;
|
|
428
|
+
index_collection.from_ = 0;
|
|
429
|
+
index_collection.to_ = ext_num_new_col - 1;
|
|
430
|
+
|
|
431
|
+
// Take a copy of the cost and bounds that can be normalised
|
|
432
|
+
std::vector<double> local_colCost{ext_col_cost,
|
|
433
|
+
ext_col_cost + ext_num_new_col};
|
|
434
|
+
std::vector<double> local_colLower{ext_col_lower,
|
|
435
|
+
ext_col_lower + ext_num_new_col};
|
|
436
|
+
std::vector<double> local_colUpper{ext_col_upper,
|
|
437
|
+
ext_col_upper + ext_num_new_col};
|
|
438
|
+
|
|
439
|
+
bool local_has_infinite_cost = false;
|
|
440
|
+
return_status = interpretCallStatus(
|
|
441
|
+
options_.log_options,
|
|
442
|
+
assessCosts(options, lp.num_col_, index_collection, local_colCost,
|
|
443
|
+
local_has_infinite_cost, options.infinite_cost),
|
|
444
|
+
return_status, "assessCosts");
|
|
445
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
446
|
+
// Assess the column bounds
|
|
447
|
+
return_status = interpretCallStatus(
|
|
448
|
+
options_.log_options,
|
|
449
|
+
assessBounds(options, "Col", lp.num_col_, index_collection,
|
|
450
|
+
local_colLower, local_colUpper, options.infinite_bound),
|
|
451
|
+
return_status, "assessBounds");
|
|
452
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
453
|
+
// Append the columns to the LP vectors and matrix
|
|
454
|
+
appendColsToLpVectors(lp, ext_num_new_col, local_colCost, local_colLower,
|
|
455
|
+
local_colUpper);
|
|
456
|
+
// Form a column-wise HighsSparseMatrix of the new matrix columns so
|
|
457
|
+
// that is easy to handle and, if there are nonzeros, it can be
|
|
458
|
+
// normalised
|
|
459
|
+
HighsSparseMatrix local_a_matrix;
|
|
460
|
+
local_a_matrix.num_col_ = ext_num_new_col;
|
|
461
|
+
local_a_matrix.num_row_ = lp.num_row_;
|
|
462
|
+
local_a_matrix.format_ = MatrixFormat::kColwise;
|
|
463
|
+
if (ext_num_new_nz) {
|
|
464
|
+
local_a_matrix.start_ = {ext_a_start, ext_a_start + ext_num_new_col};
|
|
465
|
+
local_a_matrix.start_.resize(ext_num_new_col + 1);
|
|
466
|
+
local_a_matrix.start_[ext_num_new_col] = ext_num_new_nz;
|
|
467
|
+
local_a_matrix.index_ = {ext_a_index, ext_a_index + ext_num_new_nz};
|
|
468
|
+
local_a_matrix.value_ = {ext_a_value, ext_a_value + ext_num_new_nz};
|
|
469
|
+
// Assess the matrix rows
|
|
470
|
+
return_status =
|
|
471
|
+
interpretCallStatus(options_.log_options,
|
|
472
|
+
local_a_matrix.assess(options.log_options, "LP",
|
|
473
|
+
options.small_matrix_value,
|
|
474
|
+
options.large_matrix_value),
|
|
475
|
+
return_status, "assessMatrix");
|
|
476
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
477
|
+
} else {
|
|
478
|
+
// No nonzeros so, whether the constraint matrix is column-wise or
|
|
479
|
+
// row-wise, adding the empty matrix is trivial. Complete the
|
|
480
|
+
// setup of an empty column-wise HighsSparseMatrix of the new
|
|
481
|
+
// matrix columns
|
|
482
|
+
local_a_matrix.start_.assign(ext_num_new_col + 1, 0);
|
|
483
|
+
}
|
|
484
|
+
// Append the columns to LP matrix
|
|
485
|
+
lp.a_matrix_.addCols(local_a_matrix);
|
|
486
|
+
if (lp_has_scaling) {
|
|
487
|
+
// Extend the column scaling factors
|
|
488
|
+
scale.col.resize(newNumCol);
|
|
489
|
+
for (HighsInt iCol = 0; iCol < ext_num_new_col; iCol++)
|
|
490
|
+
scale.col[lp.num_col_ + iCol] = 1.0;
|
|
491
|
+
scale.num_col = newNumCol;
|
|
492
|
+
// Apply the existing row scaling to the new columns
|
|
493
|
+
local_a_matrix.applyRowScale(scale);
|
|
494
|
+
// Consider applying column scaling to the new columns.
|
|
495
|
+
local_a_matrix.considerColScaling(options.allowed_matrix_scale_factor,
|
|
496
|
+
&scale.col[lp.num_col_]);
|
|
497
|
+
}
|
|
498
|
+
// Update the basis corresponding to new nonbasic columns
|
|
499
|
+
if (useful_basis) appendNonbasicColsToBasisInterface(ext_num_new_col);
|
|
500
|
+
|
|
501
|
+
// Possibly add blank column names
|
|
502
|
+
lp.addColNames("", ext_num_new_col);
|
|
503
|
+
|
|
504
|
+
// Increase the number of columns in the LP
|
|
505
|
+
lp.num_col_ += ext_num_new_col;
|
|
506
|
+
assert(lpDimensionsOk("addCols", lp, options.log_options));
|
|
507
|
+
|
|
508
|
+
// Interpret possible introduction of infinite costs
|
|
509
|
+
lp.has_infinite_cost_ = lp.has_infinite_cost_ || local_has_infinite_cost;
|
|
510
|
+
assert(lp.has_infinite_cost_ == lp.hasInfiniteCost(options.infinite_cost));
|
|
511
|
+
|
|
512
|
+
// Deduce the consequences of adding new columns
|
|
513
|
+
invalidateModelStatusSolutionAndInfo();
|
|
514
|
+
|
|
515
|
+
// Determine any implications for simplex data
|
|
516
|
+
ekk_instance_.addCols(lp, local_a_matrix);
|
|
517
|
+
|
|
518
|
+
// Extend any Hessian with zeros on the diagonal
|
|
519
|
+
if (this->model_.hessian_.dim_)
|
|
520
|
+
completeHessian(lp.num_col_, this->model_.hessian_);
|
|
521
|
+
return return_status;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
HighsStatus Highs::addRowsInterface(HighsInt ext_num_new_row,
|
|
525
|
+
const double* ext_row_lower,
|
|
526
|
+
const double* ext_row_upper,
|
|
527
|
+
HighsInt ext_num_new_nz,
|
|
528
|
+
const HighsInt* ext_ar_start,
|
|
529
|
+
const HighsInt* ext_ar_index,
|
|
530
|
+
const double* ext_ar_value) {
|
|
531
|
+
// addRows is fundamentally different from addCols, since the new
|
|
532
|
+
// matrix data are held row-wise, so we have to insert data into the
|
|
533
|
+
// column-wise matrix of the LP.
|
|
534
|
+
if (kExtendInvertWhenAddingRows) {
|
|
535
|
+
if (ekk_instance_.status_.has_nla)
|
|
536
|
+
ekk_instance_.debugNlaCheckInvert("Start of Highs::addRowsInterface",
|
|
537
|
+
kHighsDebugLevelExpensive + 1);
|
|
538
|
+
}
|
|
539
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
540
|
+
HighsOptions& options = options_;
|
|
541
|
+
if (ext_num_new_row < 0) return HighsStatus::kError;
|
|
542
|
+
if (ext_num_new_nz < 0) return HighsStatus::kError;
|
|
543
|
+
if (ext_num_new_row == 0) return HighsStatus::kOk;
|
|
544
|
+
if (ext_num_new_row > 0)
|
|
545
|
+
if (isRowDataNull(options.log_options, ext_row_lower, ext_row_upper))
|
|
546
|
+
return HighsStatus::kError;
|
|
547
|
+
if (ext_num_new_nz > 0)
|
|
548
|
+
if (isMatrixDataNull(options.log_options, ext_ar_start, ext_ar_index,
|
|
549
|
+
ext_ar_value))
|
|
550
|
+
return HighsStatus::kError;
|
|
551
|
+
|
|
552
|
+
HighsLp& lp = model_.lp_;
|
|
553
|
+
HighsBasis& basis = basis_;
|
|
554
|
+
HighsScale& scale = lp.scale_;
|
|
555
|
+
bool& useful_basis = basis.useful;
|
|
556
|
+
|
|
557
|
+
bool& lp_has_scaling = lp.scale_.has_scaling;
|
|
558
|
+
|
|
559
|
+
// Check that if nonzeros are to be added then the model has a positive number
|
|
560
|
+
// of columns
|
|
561
|
+
if (lp.num_col_ <= 0 && ext_num_new_nz > 0) return HighsStatus::kError;
|
|
562
|
+
|
|
563
|
+
// Record the new number of rows
|
|
564
|
+
HighsInt newNumRow = lp.num_row_ + ext_num_new_row;
|
|
565
|
+
|
|
566
|
+
HighsIndexCollection index_collection;
|
|
567
|
+
index_collection.dimension_ = ext_num_new_row;
|
|
568
|
+
index_collection.is_interval_ = true;
|
|
569
|
+
index_collection.from_ = 0;
|
|
570
|
+
index_collection.to_ = ext_num_new_row - 1;
|
|
571
|
+
// Take a copy of the bounds that can be normalised
|
|
572
|
+
std::vector<double> local_rowLower{ext_row_lower,
|
|
573
|
+
ext_row_lower + ext_num_new_row};
|
|
574
|
+
std::vector<double> local_rowUpper{ext_row_upper,
|
|
575
|
+
ext_row_upper + ext_num_new_row};
|
|
576
|
+
|
|
577
|
+
return_status = interpretCallStatus(
|
|
578
|
+
options_.log_options,
|
|
579
|
+
assessBounds(options, "Row", lp.num_row_, index_collection,
|
|
580
|
+
local_rowLower, local_rowUpper, options.infinite_bound),
|
|
581
|
+
return_status, "assessBounds");
|
|
582
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
583
|
+
// Append the rows to the LP vectors
|
|
584
|
+
appendRowsToLpVectors(lp, ext_num_new_row, local_rowLower, local_rowUpper);
|
|
585
|
+
|
|
586
|
+
// Form a row-wise HighsSparseMatrix of the new matrix rows so that
|
|
587
|
+
// is easy to handle and, if there are nonzeros, it can be
|
|
588
|
+
// normalised
|
|
589
|
+
HighsSparseMatrix local_ar_matrix;
|
|
590
|
+
local_ar_matrix.num_col_ = lp.num_col_;
|
|
591
|
+
local_ar_matrix.num_row_ = ext_num_new_row;
|
|
592
|
+
local_ar_matrix.format_ = MatrixFormat::kRowwise;
|
|
593
|
+
if (ext_num_new_nz) {
|
|
594
|
+
local_ar_matrix.start_ = {ext_ar_start, ext_ar_start + ext_num_new_row};
|
|
595
|
+
local_ar_matrix.start_.resize(ext_num_new_row + 1);
|
|
596
|
+
local_ar_matrix.start_[ext_num_new_row] = ext_num_new_nz;
|
|
597
|
+
local_ar_matrix.index_ = {ext_ar_index, ext_ar_index + ext_num_new_nz};
|
|
598
|
+
local_ar_matrix.value_ = {ext_ar_value, ext_ar_value + ext_num_new_nz};
|
|
599
|
+
// Assess the matrix columns
|
|
600
|
+
return_status =
|
|
601
|
+
interpretCallStatus(options_.log_options,
|
|
602
|
+
local_ar_matrix.assess(options.log_options, "LP",
|
|
603
|
+
options.small_matrix_value,
|
|
604
|
+
options.large_matrix_value),
|
|
605
|
+
return_status, "assessMatrix");
|
|
606
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
607
|
+
} else {
|
|
608
|
+
// No nonzeros so, whether the constraint matrix is row-wise or
|
|
609
|
+
// column-wise, adding the empty matrix is trivial. Complete the
|
|
610
|
+
// setup of an empty row-wise HighsSparseMatrix of the new matrix
|
|
611
|
+
// rows
|
|
612
|
+
local_ar_matrix.start_.assign(ext_num_new_row + 1, 0);
|
|
613
|
+
}
|
|
614
|
+
// Append the rows to LP matrix
|
|
615
|
+
lp.a_matrix_.addRows(local_ar_matrix);
|
|
616
|
+
if (lp_has_scaling) {
|
|
617
|
+
// Extend the row scaling factors
|
|
618
|
+
scale.row.resize(newNumRow);
|
|
619
|
+
for (HighsInt iRow = 0; iRow < ext_num_new_row; iRow++)
|
|
620
|
+
scale.row[lp.num_row_ + iRow] = 1.0;
|
|
621
|
+
scale.num_row = newNumRow;
|
|
622
|
+
// Apply the existing column scaling to the new rows
|
|
623
|
+
local_ar_matrix.applyColScale(scale);
|
|
624
|
+
// Consider applying row scaling to the new rows.
|
|
625
|
+
local_ar_matrix.considerRowScaling(options.allowed_matrix_scale_factor,
|
|
626
|
+
&scale.row[lp.num_row_]);
|
|
627
|
+
}
|
|
628
|
+
// Update the basis corresponding to new basic rows
|
|
629
|
+
if (useful_basis) appendBasicRowsToBasisInterface(ext_num_new_row);
|
|
630
|
+
|
|
631
|
+
// Possibly add blank row names
|
|
632
|
+
lp.addRowNames("", ext_num_new_row);
|
|
633
|
+
|
|
634
|
+
// Increase the number of rows in the LP
|
|
635
|
+
lp.num_row_ += ext_num_new_row;
|
|
636
|
+
assert(lpDimensionsOk("addRows", lp, options.log_options));
|
|
637
|
+
|
|
638
|
+
// Deduce the consequences of adding new rows
|
|
639
|
+
invalidateModelStatusSolutionAndInfo();
|
|
640
|
+
// Determine any implications for simplex data
|
|
641
|
+
ekk_instance_.addRows(lp, local_ar_matrix);
|
|
642
|
+
|
|
643
|
+
return return_status;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
static void deleteBasisEntries(std::vector<HighsBasisStatus>& status,
|
|
647
|
+
bool& deleted_basic, bool& deleted_nonbasic,
|
|
648
|
+
const HighsIndexCollection& index_collection,
|
|
649
|
+
const HighsInt entry_dim) {
|
|
650
|
+
assert(ok(index_collection));
|
|
651
|
+
assert(static_cast<size_t>(entry_dim) == status.size());
|
|
652
|
+
HighsInt from_k;
|
|
653
|
+
HighsInt to_k;
|
|
654
|
+
limits(index_collection, from_k, to_k);
|
|
655
|
+
if (from_k > to_k) return;
|
|
656
|
+
|
|
657
|
+
HighsInt delete_from_entry;
|
|
658
|
+
HighsInt delete_to_entry;
|
|
659
|
+
HighsInt keep_from_entry;
|
|
660
|
+
HighsInt keep_to_entry = -1;
|
|
661
|
+
HighsInt current_set_entry = 0;
|
|
662
|
+
HighsInt new_num_entry = 0;
|
|
663
|
+
deleted_basic = false;
|
|
664
|
+
deleted_nonbasic = false;
|
|
665
|
+
for (HighsInt k = from_k; k <= to_k; k++) {
|
|
666
|
+
updateOutInIndex(index_collection, delete_from_entry, delete_to_entry,
|
|
667
|
+
keep_from_entry, keep_to_entry, current_set_entry);
|
|
668
|
+
// Account for the initial entries being kept
|
|
669
|
+
if (k == from_k) new_num_entry = delete_from_entry;
|
|
670
|
+
// Identify whether a basic or a nonbasic entry has been deleted
|
|
671
|
+
for (HighsInt entry = delete_from_entry; entry <= delete_to_entry;
|
|
672
|
+
entry++) {
|
|
673
|
+
if (status[entry] == HighsBasisStatus::kBasic) {
|
|
674
|
+
deleted_basic = true;
|
|
675
|
+
} else {
|
|
676
|
+
deleted_nonbasic = true;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
if (delete_to_entry >= entry_dim - 1) break;
|
|
680
|
+
for (HighsInt entry = keep_from_entry; entry <= keep_to_entry; entry++) {
|
|
681
|
+
status[new_num_entry] = status[entry];
|
|
682
|
+
new_num_entry++;
|
|
683
|
+
}
|
|
684
|
+
if (keep_to_entry >= entry_dim - 1) break;
|
|
685
|
+
}
|
|
686
|
+
status.resize(new_num_entry);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
static void deleteBasisCols(HighsBasis& basis,
|
|
690
|
+
const HighsIndexCollection& index_collection,
|
|
691
|
+
const HighsInt original_num_col) {
|
|
692
|
+
bool deleted_basic;
|
|
693
|
+
bool deleted_nonbasic;
|
|
694
|
+
deleteBasisEntries(basis.col_status, deleted_basic, deleted_nonbasic,
|
|
695
|
+
index_collection, original_num_col);
|
|
696
|
+
if (deleted_basic) basis.valid = false;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
static void deleteBasisRows(HighsBasis& basis,
|
|
700
|
+
const HighsIndexCollection& index_collection,
|
|
701
|
+
const HighsInt original_num_row) {
|
|
702
|
+
bool deleted_basic;
|
|
703
|
+
bool deleted_nonbasic;
|
|
704
|
+
deleteBasisEntries(basis.row_status, deleted_basic, deleted_nonbasic,
|
|
705
|
+
index_collection, original_num_row);
|
|
706
|
+
if (deleted_nonbasic) basis.valid = false;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
void Highs::deleteColsInterface(HighsIndexCollection& index_collection) {
|
|
710
|
+
HighsLp& lp = model_.lp_;
|
|
711
|
+
HighsBasis& basis = basis_;
|
|
712
|
+
lp.ensureColwise();
|
|
713
|
+
|
|
714
|
+
// Keep a copy of the original number of columns to check whether
|
|
715
|
+
// any columns have been removed, and if there is mask to be updated
|
|
716
|
+
HighsInt original_num_col = lp.num_col_;
|
|
717
|
+
|
|
718
|
+
lp.deleteCols(index_collection);
|
|
719
|
+
model_.hessian_.deleteCols(index_collection);
|
|
720
|
+
// Bail out if no columns were actually deleted
|
|
721
|
+
if (lp.num_col_ == original_num_col) return;
|
|
722
|
+
|
|
723
|
+
assert(lp.num_col_ < original_num_col);
|
|
724
|
+
|
|
725
|
+
// Nontrivial deletion so reset the model_status and update any
|
|
726
|
+
// Highs basis
|
|
727
|
+
model_status_ = HighsModelStatus::kNotset;
|
|
728
|
+
if (basis_.useful) {
|
|
729
|
+
assert(basis_.col_status.size() == static_cast<size_t>(original_num_col));
|
|
730
|
+
// Have a full set of column basis status values, so maintain
|
|
731
|
+
// them, and only invalidate the basis if a basic column has been
|
|
732
|
+
// deleted
|
|
733
|
+
deleteBasisCols(basis_, index_collection, original_num_col);
|
|
734
|
+
} else {
|
|
735
|
+
assert(!basis.valid);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if (lp.scale_.has_scaling) {
|
|
739
|
+
deleteScale(lp.scale_.col, index_collection);
|
|
740
|
+
lp.scale_.col.resize(lp.num_col_);
|
|
741
|
+
lp.scale_.num_col = lp.num_col_;
|
|
742
|
+
}
|
|
743
|
+
// Deduce the consequences of deleting columns
|
|
744
|
+
invalidateModelStatusSolutionAndInfo();
|
|
745
|
+
|
|
746
|
+
// Determine any implications for simplex data
|
|
747
|
+
ekk_instance_.deleteCols(index_collection);
|
|
748
|
+
|
|
749
|
+
if (index_collection.is_mask_) {
|
|
750
|
+
// Set the mask values to indicate the new index value of the
|
|
751
|
+
// remaining columns
|
|
752
|
+
HighsInt new_col = 0;
|
|
753
|
+
for (HighsInt col = 0; col < original_num_col; col++) {
|
|
754
|
+
if (!index_collection.mask_[col]) {
|
|
755
|
+
index_collection.mask_[col] = new_col;
|
|
756
|
+
new_col++;
|
|
757
|
+
} else {
|
|
758
|
+
index_collection.mask_[col] = -1;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
assert(new_col == lp.num_col_);
|
|
762
|
+
}
|
|
763
|
+
assert(lpDimensionsOk("deleteCols", lp, options_.log_options));
|
|
764
|
+
lp.col_hash_.name2index.clear();
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
void Highs::deleteRowsInterface(HighsIndexCollection& index_collection) {
|
|
768
|
+
HighsLp& lp = model_.lp_;
|
|
769
|
+
HighsBasis& basis = basis_;
|
|
770
|
+
lp.ensureColwise();
|
|
771
|
+
// Keep a copy of the original number of rows to check whether
|
|
772
|
+
// any rows have been removed, and if there is mask to be updated
|
|
773
|
+
HighsInt original_num_row = lp.num_row_;
|
|
774
|
+
|
|
775
|
+
lp.deleteRows(index_collection);
|
|
776
|
+
// Bail out if no rows were actually deleted
|
|
777
|
+
if (lp.num_row_ == original_num_row) return;
|
|
778
|
+
|
|
779
|
+
assert(lp.num_row_ < original_num_row);
|
|
780
|
+
|
|
781
|
+
// Nontrivial deletion so reset the model_status and update any
|
|
782
|
+
// Highs basis
|
|
783
|
+
model_status_ = HighsModelStatus::kNotset;
|
|
784
|
+
if (basis_.useful) {
|
|
785
|
+
assert(basis_.row_status.size() == static_cast<size_t>(original_num_row));
|
|
786
|
+
// Have a full set of row basis status values, so maintain them,
|
|
787
|
+
// and only invalidate the basis if a nonbasic row has been
|
|
788
|
+
// deleted
|
|
789
|
+
deleteBasisRows(basis_, index_collection, original_num_row);
|
|
790
|
+
} else {
|
|
791
|
+
assert(!basis.valid);
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
if (lp.scale_.has_scaling) {
|
|
795
|
+
deleteScale(lp.scale_.row, index_collection);
|
|
796
|
+
lp.scale_.row.resize(lp.num_row_);
|
|
797
|
+
lp.scale_.num_row = lp.num_row_;
|
|
798
|
+
}
|
|
799
|
+
// Deduce the consequences of deleting rows
|
|
800
|
+
invalidateModelStatusSolutionAndInfo();
|
|
801
|
+
|
|
802
|
+
// Determine any implications for simplex data
|
|
803
|
+
ekk_instance_.deleteRows(index_collection);
|
|
804
|
+
if (index_collection.is_mask_) {
|
|
805
|
+
HighsInt new_row = 0;
|
|
806
|
+
for (HighsInt row = 0; row < original_num_row; row++) {
|
|
807
|
+
if (!index_collection.mask_[row]) {
|
|
808
|
+
index_collection.mask_[row] = new_row;
|
|
809
|
+
new_row++;
|
|
810
|
+
} else {
|
|
811
|
+
index_collection.mask_[row] = -1;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
assert(new_row == lp.num_row_);
|
|
815
|
+
}
|
|
816
|
+
assert(lpDimensionsOk("deleteRows", lp, options_.log_options));
|
|
817
|
+
lp.row_hash_.name2index.clear();
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
void Highs::getColsInterface(const HighsIndexCollection& index_collection,
|
|
821
|
+
HighsInt& num_col, double* cost, double* lower,
|
|
822
|
+
double* upper, HighsInt& num_nz, HighsInt* start,
|
|
823
|
+
HighsInt* index, double* value) const {
|
|
824
|
+
const HighsLp& lp = model_.lp_;
|
|
825
|
+
if (lp.a_matrix_.isColwise()) {
|
|
826
|
+
getSubVectors(index_collection, lp.num_col_, lp.col_cost_.data(),
|
|
827
|
+
lp.col_lower_.data(), lp.col_upper_.data(), lp.a_matrix_,
|
|
828
|
+
num_col, cost, lower, upper, num_nz, start, index, value);
|
|
829
|
+
} else {
|
|
830
|
+
getSubVectorsTranspose(index_collection, lp.num_col_, lp.col_cost_.data(),
|
|
831
|
+
lp.col_lower_.data(), lp.col_upper_.data(),
|
|
832
|
+
lp.a_matrix_, num_col, cost, lower, upper, num_nz,
|
|
833
|
+
start, index, value);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
void Highs::getRowsInterface(const HighsIndexCollection& index_collection,
|
|
838
|
+
HighsInt& num_row, double* lower, double* upper,
|
|
839
|
+
HighsInt& num_nz, HighsInt* start, HighsInt* index,
|
|
840
|
+
double* value) const {
|
|
841
|
+
const HighsLp& lp = model_.lp_;
|
|
842
|
+
if (lp.a_matrix_.isColwise()) {
|
|
843
|
+
getSubVectorsTranspose(index_collection, lp.num_row_, nullptr,
|
|
844
|
+
lp.row_lower_.data(), lp.row_upper_.data(),
|
|
845
|
+
lp.a_matrix_, num_row, nullptr, lower, upper, num_nz,
|
|
846
|
+
start, index, value);
|
|
847
|
+
} else {
|
|
848
|
+
getSubVectors(index_collection, lp.num_row_, nullptr, lp.row_lower_.data(),
|
|
849
|
+
lp.row_upper_.data(), lp.a_matrix_, num_row, nullptr, lower,
|
|
850
|
+
upper, num_nz, start, index, value);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
void Highs::getCoefficientInterface(const HighsInt ext_row,
|
|
855
|
+
const HighsInt ext_col,
|
|
856
|
+
double& value) const {
|
|
857
|
+
const HighsLp& lp = model_.lp_;
|
|
858
|
+
assert(0 <= ext_row && ext_row < lp.num_row_);
|
|
859
|
+
assert(0 <= ext_col && ext_col < lp.num_col_);
|
|
860
|
+
value = 0;
|
|
861
|
+
|
|
862
|
+
if (lp.a_matrix_.isColwise()) {
|
|
863
|
+
for (HighsInt el = lp.a_matrix_.start_[ext_col];
|
|
864
|
+
el < lp.a_matrix_.start_[ext_col + 1]; el++) {
|
|
865
|
+
if (lp.a_matrix_.index_[el] == ext_row) {
|
|
866
|
+
value = lp.a_matrix_.value_[el];
|
|
867
|
+
break;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
} else {
|
|
871
|
+
for (HighsInt el = lp.a_matrix_.start_[ext_row];
|
|
872
|
+
el < lp.a_matrix_.start_[ext_row + 1]; el++) {
|
|
873
|
+
if (lp.a_matrix_.index_[el] == ext_col) {
|
|
874
|
+
value = lp.a_matrix_.value_[el];
|
|
875
|
+
break;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
HighsStatus Highs::changeIntegralityInterface(
|
|
882
|
+
HighsIndexCollection& index_collection, const HighsVarType* integrality) {
|
|
883
|
+
HighsInt num_integrality = dataSize(index_collection);
|
|
884
|
+
// If a non-positive number of integrality (may) need changing nothing needs
|
|
885
|
+
// to be done
|
|
886
|
+
if (num_integrality <= 0) return HighsStatus::kOk;
|
|
887
|
+
if (highsVarTypeUserDataNotNull(options_.log_options, integrality,
|
|
888
|
+
"column integrality"))
|
|
889
|
+
return HighsStatus::kError;
|
|
890
|
+
// Take a copy of the integrality that can be normalised
|
|
891
|
+
std::vector<HighsVarType> local_integrality{integrality,
|
|
892
|
+
integrality + num_integrality};
|
|
893
|
+
// If changing the integrality for a set of columns, verify that the
|
|
894
|
+
// set entries are in ascending order
|
|
895
|
+
if (index_collection.is_set_)
|
|
896
|
+
assert(increasingSetOk(index_collection.set_, 0,
|
|
897
|
+
index_collection.dimension_, true));
|
|
898
|
+
HighsStatus return_status = changeLpIntegrality(model_.lp_, index_collection,
|
|
899
|
+
local_integrality, options_);
|
|
900
|
+
assert(return_status != HighsStatus::kError);
|
|
901
|
+
// Deduce the consequences of new integrality
|
|
902
|
+
invalidateModelStatus();
|
|
903
|
+
return return_status;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
HighsStatus Highs::changeCostsInterface(HighsIndexCollection& index_collection,
|
|
907
|
+
const double* cost) {
|
|
908
|
+
HighsInt num_cost = dataSize(index_collection);
|
|
909
|
+
// If a non-positive number of costs (may) need changing nothing needs to be
|
|
910
|
+
// done
|
|
911
|
+
if (num_cost <= 0) return HighsStatus::kOk;
|
|
912
|
+
if (doubleUserDataNotNull(options_.log_options, cost, "column costs"))
|
|
913
|
+
return HighsStatus::kError;
|
|
914
|
+
// Take a copy of the cost that can be normalised
|
|
915
|
+
std::vector<double> local_colCost{cost, cost + num_cost};
|
|
916
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
917
|
+
bool local_has_infinite_cost = false;
|
|
918
|
+
return_status = interpretCallStatus(
|
|
919
|
+
options_.log_options,
|
|
920
|
+
assessCosts(options_, 0, index_collection, local_colCost,
|
|
921
|
+
local_has_infinite_cost, options_.infinite_cost),
|
|
922
|
+
return_status, "assessCosts");
|
|
923
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
924
|
+
HighsLp& lp = model_.lp_;
|
|
925
|
+
changeLpCosts(lp, index_collection, local_colCost, options_.infinite_cost);
|
|
926
|
+
|
|
927
|
+
// Interpret possible introduction of infinite costs
|
|
928
|
+
lp.has_infinite_cost_ = lp.has_infinite_cost_ || local_has_infinite_cost;
|
|
929
|
+
assert(lp.has_infinite_cost_ == lp.hasInfiniteCost(options_.infinite_cost));
|
|
930
|
+
|
|
931
|
+
// Deduce the consequences of new costs
|
|
932
|
+
invalidateModelStatusSolutionAndInfo();
|
|
933
|
+
// Determine any implications for simplex data
|
|
934
|
+
ekk_instance_.updateStatus(LpAction::kNewCosts);
|
|
935
|
+
return HighsStatus::kOk;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
bool Highs::feasibleWrtBounds(const bool columns) const {
|
|
939
|
+
if (this->info_.primal_solution_status != kSolutionStatusFeasible)
|
|
940
|
+
return false;
|
|
941
|
+
const HighsLp& lp = model_.lp_;
|
|
942
|
+
const double primal_feasibility_tolerance =
|
|
943
|
+
this->options_.primal_feasibility_tolerance;
|
|
944
|
+
std::vector<double> value =
|
|
945
|
+
columns ? this->solution_.col_value : this->solution_.row_value;
|
|
946
|
+
std::vector<double> lower = columns ? lp.col_lower_ : lp.row_lower_;
|
|
947
|
+
std::vector<double> upper = columns ? lp.col_upper_ : lp.row_upper_;
|
|
948
|
+
HighsInt dim = columns ? lp.num_col_ : lp.num_row_;
|
|
949
|
+
for (HighsInt iX = 0; iX < dim; iX++) {
|
|
950
|
+
if (value[iX] < lower[iX] - primal_feasibility_tolerance) return false;
|
|
951
|
+
if (value[iX] > upper[iX] + primal_feasibility_tolerance) return false;
|
|
952
|
+
}
|
|
953
|
+
return true;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
HighsStatus Highs::changeColBoundsInterface(
|
|
957
|
+
HighsIndexCollection& index_collection, const double* col_lower,
|
|
958
|
+
const double* col_upper) {
|
|
959
|
+
HighsInt num_col_bounds = dataSize(index_collection);
|
|
960
|
+
// If a non-positive number of costs (may) need changing nothing needs to be
|
|
961
|
+
// done
|
|
962
|
+
if (num_col_bounds <= 0) return HighsStatus::kOk;
|
|
963
|
+
bool null_data = false;
|
|
964
|
+
null_data = doubleUserDataNotNull(options_.log_options, col_lower,
|
|
965
|
+
"column lower bounds") ||
|
|
966
|
+
null_data;
|
|
967
|
+
null_data = doubleUserDataNotNull(options_.log_options, col_upper,
|
|
968
|
+
"column upper bounds") ||
|
|
969
|
+
null_data;
|
|
970
|
+
if (null_data) return HighsStatus::kError;
|
|
971
|
+
// Take a copy of the cost that can be normalised
|
|
972
|
+
std::vector<double> local_colLower{col_lower, col_lower + num_col_bounds};
|
|
973
|
+
std::vector<double> local_colUpper{col_upper, col_upper + num_col_bounds};
|
|
974
|
+
// If changing the bounds for a set of columns, ensure that the
|
|
975
|
+
// set and data are in ascending order
|
|
976
|
+
if (index_collection.is_set_)
|
|
977
|
+
sortSetData(index_collection.set_num_entries_, index_collection.set_,
|
|
978
|
+
col_lower, col_upper, NULL, local_colLower.data(),
|
|
979
|
+
local_colUpper.data(), NULL);
|
|
980
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
981
|
+
return_status = interpretCallStatus(
|
|
982
|
+
options_.log_options,
|
|
983
|
+
assessBounds(options_, "col", 0, index_collection, local_colLower,
|
|
984
|
+
local_colUpper, options_.infinite_bound),
|
|
985
|
+
return_status, "assessBounds");
|
|
986
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
987
|
+
HighsLp& lp = model_.lp_;
|
|
988
|
+
|
|
989
|
+
changeLpColBounds(lp, index_collection, local_colLower, local_colUpper);
|
|
990
|
+
// Update HiGHS basis status and (any) simplex move status of
|
|
991
|
+
// nonbasic variables whose bounds have changed
|
|
992
|
+
setNonbasicStatusInterface(index_collection, true);
|
|
993
|
+
// Deduce the consequences of new col bounds
|
|
994
|
+
if (!this->basis_.useful && feasibleWrtBounds()) {
|
|
995
|
+
// Retain the solution if there's no basis, and the solution is
|
|
996
|
+
// feasible
|
|
997
|
+
invalidateModelStatusAndInfo();
|
|
998
|
+
} else {
|
|
999
|
+
// Invalidate the solution
|
|
1000
|
+
invalidateModelStatusSolutionAndInfo();
|
|
1001
|
+
}
|
|
1002
|
+
// Determine any implications for simplex data
|
|
1003
|
+
ekk_instance_.updateStatus(LpAction::kNewBounds);
|
|
1004
|
+
return HighsStatus::kOk;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
HighsStatus Highs::changeRowBoundsInterface(
|
|
1008
|
+
HighsIndexCollection& index_collection, const double* lower,
|
|
1009
|
+
const double* upper) {
|
|
1010
|
+
HighsInt num_row_bounds = dataSize(index_collection);
|
|
1011
|
+
// If a non-positive number of costs (may) need changing nothing needs to be
|
|
1012
|
+
// done
|
|
1013
|
+
if (num_row_bounds <= 0) return HighsStatus::kOk;
|
|
1014
|
+
bool null_data = false;
|
|
1015
|
+
null_data =
|
|
1016
|
+
doubleUserDataNotNull(options_.log_options, lower, "row lower bounds") ||
|
|
1017
|
+
null_data;
|
|
1018
|
+
null_data =
|
|
1019
|
+
doubleUserDataNotNull(options_.log_options, upper, "row upper bounds") ||
|
|
1020
|
+
null_data;
|
|
1021
|
+
if (null_data) return HighsStatus::kError;
|
|
1022
|
+
// Take a copy of the cost that can be normalised
|
|
1023
|
+
std::vector<double> local_rowLower{lower, lower + num_row_bounds};
|
|
1024
|
+
std::vector<double> local_rowUpper{upper, upper + num_row_bounds};
|
|
1025
|
+
// If changing the bounds for a set of rows, ensure that the
|
|
1026
|
+
// set and data are in ascending order
|
|
1027
|
+
if (index_collection.is_set_)
|
|
1028
|
+
sortSetData(index_collection.set_num_entries_, index_collection.set_, lower,
|
|
1029
|
+
upper, NULL, local_rowLower.data(), local_rowUpper.data(),
|
|
1030
|
+
NULL);
|
|
1031
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
1032
|
+
return_status = interpretCallStatus(
|
|
1033
|
+
options_.log_options,
|
|
1034
|
+
assessBounds(options_, "row", 0, index_collection, local_rowLower,
|
|
1035
|
+
local_rowUpper, options_.infinite_bound),
|
|
1036
|
+
return_status, "assessBounds");
|
|
1037
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
1038
|
+
HighsLp& lp = model_.lp_;
|
|
1039
|
+
|
|
1040
|
+
changeLpRowBounds(lp, index_collection, local_rowLower, local_rowUpper);
|
|
1041
|
+
// Update HiGHS basis status and (any) simplex move status of
|
|
1042
|
+
// nonbasic variables whose bounds have changed
|
|
1043
|
+
setNonbasicStatusInterface(index_collection, false);
|
|
1044
|
+
// Deduce the consequences of new row bounds
|
|
1045
|
+
if (!this->basis_.useful && feasibleWrtBounds(false)) {
|
|
1046
|
+
// Retain the solution if there's no basis, and the solution is
|
|
1047
|
+
// feasible
|
|
1048
|
+
invalidateModelStatusAndInfo();
|
|
1049
|
+
} else {
|
|
1050
|
+
// Invalidate the solution
|
|
1051
|
+
invalidateModelStatusSolutionAndInfo();
|
|
1052
|
+
}
|
|
1053
|
+
// Determine any implications for simplex data
|
|
1054
|
+
ekk_instance_.updateStatus(LpAction::kNewBounds);
|
|
1055
|
+
return HighsStatus::kOk;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
// Change a single coefficient in the matrix
|
|
1059
|
+
void Highs::changeCoefficientInterface(const HighsInt ext_row,
|
|
1060
|
+
const HighsInt ext_col,
|
|
1061
|
+
const double ext_new_value) {
|
|
1062
|
+
HighsLp& lp = model_.lp_;
|
|
1063
|
+
// Ensure that the LP is column-wise
|
|
1064
|
+
lp.ensureColwise();
|
|
1065
|
+
assert(0 <= ext_row && ext_row < lp.num_row_);
|
|
1066
|
+
assert(0 <= ext_col && ext_col < lp.num_col_);
|
|
1067
|
+
const bool zero_new_value =
|
|
1068
|
+
std::fabs(ext_new_value) <= options_.small_matrix_value;
|
|
1069
|
+
changeLpMatrixCoefficient(lp, ext_row, ext_col, ext_new_value,
|
|
1070
|
+
zero_new_value);
|
|
1071
|
+
// Deduce the consequences of a changed element
|
|
1072
|
+
//
|
|
1073
|
+
// ToDo: Can do something more intelligent if element is in nonbasic
|
|
1074
|
+
// column
|
|
1075
|
+
//
|
|
1076
|
+
const bool basic_column =
|
|
1077
|
+
this->basis_.col_status[ext_col] == HighsBasisStatus::kBasic;
|
|
1078
|
+
//
|
|
1079
|
+
// For now, treat it as if it's a new row
|
|
1080
|
+
invalidateModelStatusSolutionAndInfo();
|
|
1081
|
+
|
|
1082
|
+
if (basic_column) {
|
|
1083
|
+
// Basis is retained, but is has to be viewed as alien, since the
|
|
1084
|
+
// basis matrix has changed
|
|
1085
|
+
this->basis_.was_alien = true;
|
|
1086
|
+
this->basis_.alien = true;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
// Determine any implications for simplex data
|
|
1090
|
+
ekk_instance_.updateStatus(LpAction::kNewRows);
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
HighsStatus Highs::scaleColInterface(const HighsInt col,
|
|
1094
|
+
const double scale_value) {
|
|
1095
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
1096
|
+
HighsLp& lp = model_.lp_;
|
|
1097
|
+
HighsBasis& basis = basis_;
|
|
1098
|
+
HighsSimplexStatus& simplex_status = ekk_instance_.status_;
|
|
1099
|
+
|
|
1100
|
+
// Ensure that the LP is column-wise
|
|
1101
|
+
lp.ensureColwise();
|
|
1102
|
+
if (col < 0) return HighsStatus::kError;
|
|
1103
|
+
if (col >= lp.num_col_) return HighsStatus::kError;
|
|
1104
|
+
if (!scale_value) return HighsStatus::kError;
|
|
1105
|
+
|
|
1106
|
+
return_status = interpretCallStatus(options_.log_options,
|
|
1107
|
+
applyScalingToLpCol(lp, col, scale_value),
|
|
1108
|
+
return_status, "applyScalingToLpCol");
|
|
1109
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
1110
|
+
|
|
1111
|
+
if (scale_value < 0 && basis.valid) {
|
|
1112
|
+
// Negative, so flip any nonbasic status
|
|
1113
|
+
if (basis.col_status[col] == HighsBasisStatus::kLower) {
|
|
1114
|
+
basis.col_status[col] = HighsBasisStatus::kUpper;
|
|
1115
|
+
} else if (basis.col_status[col] == HighsBasisStatus::kUpper) {
|
|
1116
|
+
basis.col_status[col] = HighsBasisStatus::kLower;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
if (simplex_status.initialised_for_solve) {
|
|
1120
|
+
SimplexBasis& simplex_basis = ekk_instance_.basis_;
|
|
1121
|
+
if (scale_value < 0 && simplex_status.has_basis) {
|
|
1122
|
+
// Negative, so flip any nonbasic status
|
|
1123
|
+
if (simplex_basis.nonbasicMove_[col] == kNonbasicMoveUp) {
|
|
1124
|
+
simplex_basis.nonbasicMove_[col] = kNonbasicMoveDn;
|
|
1125
|
+
} else if (simplex_basis.nonbasicMove_[col] == kNonbasicMoveDn) {
|
|
1126
|
+
simplex_basis.nonbasicMove_[col] = kNonbasicMoveUp;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
// Deduce the consequences of a scaled column
|
|
1131
|
+
invalidateModelStatusSolutionAndInfo();
|
|
1132
|
+
|
|
1133
|
+
// Determine any implications for simplex data
|
|
1134
|
+
ekk_instance_.updateStatus(LpAction::kScaledCol);
|
|
1135
|
+
return HighsStatus::kOk;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
HighsStatus Highs::scaleRowInterface(const HighsInt row,
|
|
1139
|
+
const double scale_value) {
|
|
1140
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
1141
|
+
HighsLp& lp = model_.lp_;
|
|
1142
|
+
HighsBasis& basis = basis_;
|
|
1143
|
+
HighsSimplexStatus& simplex_status = ekk_instance_.status_;
|
|
1144
|
+
|
|
1145
|
+
// Ensure that the LP is column-wise
|
|
1146
|
+
lp.ensureColwise();
|
|
1147
|
+
|
|
1148
|
+
if (row < 0) return HighsStatus::kError;
|
|
1149
|
+
if (row >= lp.num_row_) return HighsStatus::kError;
|
|
1150
|
+
if (!scale_value) return HighsStatus::kError;
|
|
1151
|
+
|
|
1152
|
+
return_status = interpretCallStatus(options_.log_options,
|
|
1153
|
+
applyScalingToLpRow(lp, row, scale_value),
|
|
1154
|
+
return_status, "applyScalingToLpRow");
|
|
1155
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
1156
|
+
|
|
1157
|
+
if (scale_value < 0 && basis.valid) {
|
|
1158
|
+
// Negative, so flip any nonbasic status
|
|
1159
|
+
if (basis.row_status[row] == HighsBasisStatus::kLower) {
|
|
1160
|
+
basis.row_status[row] = HighsBasisStatus::kUpper;
|
|
1161
|
+
} else if (basis.row_status[row] == HighsBasisStatus::kUpper) {
|
|
1162
|
+
basis.row_status[row] = HighsBasisStatus::kLower;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
if (simplex_status.initialised_for_solve) {
|
|
1166
|
+
SimplexBasis& simplex_basis = ekk_instance_.basis_;
|
|
1167
|
+
if (scale_value < 0 && simplex_status.has_basis) {
|
|
1168
|
+
// Negative, so flip any nonbasic status
|
|
1169
|
+
const HighsInt var = lp.num_col_ + row;
|
|
1170
|
+
if (simplex_basis.nonbasicMove_[var] == kNonbasicMoveUp) {
|
|
1171
|
+
simplex_basis.nonbasicMove_[var] = kNonbasicMoveDn;
|
|
1172
|
+
} else if (simplex_basis.nonbasicMove_[var] == kNonbasicMoveDn) {
|
|
1173
|
+
simplex_basis.nonbasicMove_[var] = kNonbasicMoveUp;
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
// Deduce the consequences of a scaled row
|
|
1178
|
+
invalidateModelStatusSolutionAndInfo();
|
|
1179
|
+
|
|
1180
|
+
// Determine any implications for simplex data
|
|
1181
|
+
ekk_instance_.updateStatus(LpAction::kScaledRow);
|
|
1182
|
+
return HighsStatus::kOk;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
void Highs::setNonbasicStatusInterface(
|
|
1186
|
+
const HighsIndexCollection& index_collection, const bool columns) {
|
|
1187
|
+
HighsBasis& highs_basis = basis_;
|
|
1188
|
+
if (!highs_basis.valid) return;
|
|
1189
|
+
const bool has_simplex_basis = ekk_instance_.status_.has_basis;
|
|
1190
|
+
SimplexBasis& simplex_basis = ekk_instance_.basis_;
|
|
1191
|
+
HighsLp& lp = model_.lp_;
|
|
1192
|
+
|
|
1193
|
+
assert(ok(index_collection));
|
|
1194
|
+
HighsInt from_k;
|
|
1195
|
+
HighsInt to_k;
|
|
1196
|
+
limits(index_collection, from_k, to_k);
|
|
1197
|
+
HighsInt ix_dim;
|
|
1198
|
+
if (columns) {
|
|
1199
|
+
ix_dim = lp.num_col_;
|
|
1200
|
+
} else {
|
|
1201
|
+
ix_dim = lp.num_row_;
|
|
1202
|
+
}
|
|
1203
|
+
// Surely this is checked elsewhere
|
|
1204
|
+
assert(0 <= from_k && to_k < ix_dim);
|
|
1205
|
+
assert(from_k <= to_k);
|
|
1206
|
+
HighsInt set_from_ix;
|
|
1207
|
+
HighsInt set_to_ix;
|
|
1208
|
+
HighsInt ignore_from_ix;
|
|
1209
|
+
HighsInt ignore_to_ix = -1;
|
|
1210
|
+
HighsInt current_set_entry = 0;
|
|
1211
|
+
// Given a basic-nonbasic partition, all status settings are defined
|
|
1212
|
+
// by the bounds unless boxed, in which case any definitive (ie not
|
|
1213
|
+
// just kNonbasic) existing status is retained. Otherwise, set to
|
|
1214
|
+
// bound nearer to zero
|
|
1215
|
+
for (HighsInt k = from_k; k <= to_k; k++) {
|
|
1216
|
+
updateOutInIndex(index_collection, set_from_ix, set_to_ix, ignore_from_ix,
|
|
1217
|
+
ignore_to_ix, current_set_entry);
|
|
1218
|
+
assert(set_to_ix < ix_dim);
|
|
1219
|
+
assert(ignore_to_ix < ix_dim);
|
|
1220
|
+
if (columns) {
|
|
1221
|
+
for (HighsInt iCol = set_from_ix; iCol <= set_to_ix; iCol++) {
|
|
1222
|
+
if (highs_basis.col_status[iCol] == HighsBasisStatus::kBasic) continue;
|
|
1223
|
+
// Nonbasic column
|
|
1224
|
+
double lower = lp.col_lower_[iCol];
|
|
1225
|
+
double upper = lp.col_upper_[iCol];
|
|
1226
|
+
HighsBasisStatus status = highs_basis.col_status[iCol];
|
|
1227
|
+
int8_t move = kIllegalMoveValue;
|
|
1228
|
+
if (lower == upper) {
|
|
1229
|
+
if (status == HighsBasisStatus::kNonbasic)
|
|
1230
|
+
status = HighsBasisStatus::kLower;
|
|
1231
|
+
move = kNonbasicMoveZe;
|
|
1232
|
+
} else if (!highs_isInfinity(-lower)) {
|
|
1233
|
+
// Finite lower bound so boxed or lower
|
|
1234
|
+
if (!highs_isInfinity(upper)) {
|
|
1235
|
+
// Finite upper bound so boxed
|
|
1236
|
+
if (status == HighsBasisStatus::kNonbasic) {
|
|
1237
|
+
// No definitive status, so set to bound nearer to zero
|
|
1238
|
+
if (fabs(lower) < fabs(upper)) {
|
|
1239
|
+
status = HighsBasisStatus::kLower;
|
|
1240
|
+
move = kNonbasicMoveUp;
|
|
1241
|
+
} else {
|
|
1242
|
+
status = HighsBasisStatus::kUpper;
|
|
1243
|
+
move = kNonbasicMoveDn;
|
|
1244
|
+
}
|
|
1245
|
+
} else if (status == HighsBasisStatus::kLower) {
|
|
1246
|
+
move = kNonbasicMoveUp;
|
|
1247
|
+
} else {
|
|
1248
|
+
move = kNonbasicMoveDn;
|
|
1249
|
+
}
|
|
1250
|
+
} else {
|
|
1251
|
+
// Lower (since upper bound is infinite)
|
|
1252
|
+
status = HighsBasisStatus::kLower;
|
|
1253
|
+
move = kNonbasicMoveUp;
|
|
1254
|
+
}
|
|
1255
|
+
} else if (!highs_isInfinity(upper)) {
|
|
1256
|
+
// Upper
|
|
1257
|
+
status = HighsBasisStatus::kUpper;
|
|
1258
|
+
move = kNonbasicMoveDn;
|
|
1259
|
+
} else {
|
|
1260
|
+
// FREE
|
|
1261
|
+
status = HighsBasisStatus::kZero;
|
|
1262
|
+
move = kNonbasicMoveZe;
|
|
1263
|
+
}
|
|
1264
|
+
highs_basis.col_status[iCol] = status;
|
|
1265
|
+
if (has_simplex_basis) {
|
|
1266
|
+
assert(move != kIllegalMoveValue);
|
|
1267
|
+
simplex_basis.nonbasicFlag_[iCol] = kNonbasicFlagTrue;
|
|
1268
|
+
simplex_basis.nonbasicMove_[iCol] = move;
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
} else {
|
|
1272
|
+
for (HighsInt iRow = set_from_ix; iRow <= set_to_ix; iRow++) {
|
|
1273
|
+
if (highs_basis.row_status[iRow] == HighsBasisStatus::kBasic) continue;
|
|
1274
|
+
// Nonbasic column
|
|
1275
|
+
double lower = lp.row_lower_[iRow];
|
|
1276
|
+
double upper = lp.row_upper_[iRow];
|
|
1277
|
+
HighsBasisStatus status = highs_basis.row_status[iRow];
|
|
1278
|
+
int8_t move = kIllegalMoveValue;
|
|
1279
|
+
if (lower == upper) {
|
|
1280
|
+
if (status == HighsBasisStatus::kNonbasic)
|
|
1281
|
+
status = HighsBasisStatus::kLower;
|
|
1282
|
+
move = kNonbasicMoveZe;
|
|
1283
|
+
} else if (!highs_isInfinity(-lower)) {
|
|
1284
|
+
// Finite lower bound so boxed or lower
|
|
1285
|
+
if (!highs_isInfinity(upper)) {
|
|
1286
|
+
// Finite upper bound so boxed
|
|
1287
|
+
if (status == HighsBasisStatus::kNonbasic) {
|
|
1288
|
+
// No definitive status, so set to bound nearer to zero
|
|
1289
|
+
if (fabs(lower) < fabs(upper)) {
|
|
1290
|
+
status = HighsBasisStatus::kLower;
|
|
1291
|
+
move = kNonbasicMoveDn;
|
|
1292
|
+
} else {
|
|
1293
|
+
status = HighsBasisStatus::kUpper;
|
|
1294
|
+
move = kNonbasicMoveUp;
|
|
1295
|
+
}
|
|
1296
|
+
} else if (status == HighsBasisStatus::kLower) {
|
|
1297
|
+
move = kNonbasicMoveDn;
|
|
1298
|
+
} else {
|
|
1299
|
+
move = kNonbasicMoveUp;
|
|
1300
|
+
}
|
|
1301
|
+
} else {
|
|
1302
|
+
// Lower (since upper bound is infinite)
|
|
1303
|
+
status = HighsBasisStatus::kLower;
|
|
1304
|
+
move = kNonbasicMoveDn;
|
|
1305
|
+
}
|
|
1306
|
+
} else if (!highs_isInfinity(upper)) {
|
|
1307
|
+
// Upper
|
|
1308
|
+
status = HighsBasisStatus::kUpper;
|
|
1309
|
+
move = kNonbasicMoveUp;
|
|
1310
|
+
} else {
|
|
1311
|
+
// FREE
|
|
1312
|
+
status = HighsBasisStatus::kZero;
|
|
1313
|
+
move = kNonbasicMoveZe;
|
|
1314
|
+
}
|
|
1315
|
+
highs_basis.row_status[iRow] = status;
|
|
1316
|
+
if (has_simplex_basis) {
|
|
1317
|
+
assert(move != kIllegalMoveValue);
|
|
1318
|
+
simplex_basis.nonbasicFlag_[lp.num_col_ + iRow] = kNonbasicFlagTrue;
|
|
1319
|
+
simplex_basis.nonbasicMove_[lp.num_col_ + iRow] = move;
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
if (ignore_to_ix >= ix_dim - 1) break;
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
void Highs::appendNonbasicColsToBasisInterface(const HighsInt ext_num_new_col) {
|
|
1328
|
+
if (ext_num_new_col == 0) return;
|
|
1329
|
+
HighsBasis& highs_basis = basis_;
|
|
1330
|
+
if (!highs_basis.useful) return;
|
|
1331
|
+
const bool has_simplex_basis = ekk_instance_.status_.has_basis;
|
|
1332
|
+
SimplexBasis& simplex_basis = ekk_instance_.basis_;
|
|
1333
|
+
HighsLp& lp = model_.lp_;
|
|
1334
|
+
|
|
1335
|
+
assert(highs_basis.col_status.size() == static_cast<size_t>(lp.num_col_));
|
|
1336
|
+
assert(highs_basis.row_status.size() == static_cast<size_t>(lp.num_row_));
|
|
1337
|
+
|
|
1338
|
+
// Add nonbasic structurals
|
|
1339
|
+
HighsInt newNumCol = lp.num_col_ + ext_num_new_col;
|
|
1340
|
+
HighsInt newNumTot = newNumCol + lp.num_row_;
|
|
1341
|
+
highs_basis.col_status.resize(newNumCol);
|
|
1342
|
+
if (has_simplex_basis) {
|
|
1343
|
+
simplex_basis.nonbasicFlag_.resize(newNumTot);
|
|
1344
|
+
simplex_basis.nonbasicMove_.resize(newNumTot);
|
|
1345
|
+
// Shift the row data in basicIndex, nonbasicFlag and nonbasicMove if
|
|
1346
|
+
// necessary
|
|
1347
|
+
for (HighsInt iRow = lp.num_row_ - 1; iRow >= 0; iRow--) {
|
|
1348
|
+
HighsInt iCol = simplex_basis.basicIndex_[iRow];
|
|
1349
|
+
if (iCol >= lp.num_col_) {
|
|
1350
|
+
// This basic variable is a row, so shift its index
|
|
1351
|
+
simplex_basis.basicIndex_[iRow] += ext_num_new_col;
|
|
1352
|
+
}
|
|
1353
|
+
simplex_basis.nonbasicFlag_[newNumCol + iRow] =
|
|
1354
|
+
simplex_basis.nonbasicFlag_[lp.num_col_ + iRow];
|
|
1355
|
+
simplex_basis.nonbasicMove_[newNumCol + iRow] =
|
|
1356
|
+
simplex_basis.nonbasicMove_[lp.num_col_ + iRow];
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
// Make any new columns nonbasic
|
|
1360
|
+
for (HighsInt iCol = lp.num_col_; iCol < newNumCol; iCol++) {
|
|
1361
|
+
double lower = lp.col_lower_[iCol];
|
|
1362
|
+
double upper = lp.col_upper_[iCol];
|
|
1363
|
+
HighsBasisStatus status = HighsBasisStatus::kNonbasic;
|
|
1364
|
+
int8_t move = kIllegalMoveValue;
|
|
1365
|
+
if (lower == upper) {
|
|
1366
|
+
// Fixed
|
|
1367
|
+
status = HighsBasisStatus::kLower;
|
|
1368
|
+
move = kNonbasicMoveZe;
|
|
1369
|
+
} else if (!highs_isInfinity(-lower)) {
|
|
1370
|
+
// Finite lower bound so boxed or lower
|
|
1371
|
+
if (!highs_isInfinity(upper)) {
|
|
1372
|
+
// Finite upper bound so boxed
|
|
1373
|
+
if (fabs(lower) < fabs(upper)) {
|
|
1374
|
+
status = HighsBasisStatus::kLower;
|
|
1375
|
+
move = kNonbasicMoveUp;
|
|
1376
|
+
} else {
|
|
1377
|
+
status = HighsBasisStatus::kUpper;
|
|
1378
|
+
move = kNonbasicMoveDn;
|
|
1379
|
+
}
|
|
1380
|
+
} else {
|
|
1381
|
+
// Lower (since upper bound is infinite)
|
|
1382
|
+
status = HighsBasisStatus::kLower;
|
|
1383
|
+
move = kNonbasicMoveUp;
|
|
1384
|
+
}
|
|
1385
|
+
} else if (!highs_isInfinity(upper)) {
|
|
1386
|
+
// Upper
|
|
1387
|
+
status = HighsBasisStatus::kUpper;
|
|
1388
|
+
move = kNonbasicMoveDn;
|
|
1389
|
+
} else {
|
|
1390
|
+
// FREE
|
|
1391
|
+
status = HighsBasisStatus::kZero;
|
|
1392
|
+
move = kNonbasicMoveZe;
|
|
1393
|
+
}
|
|
1394
|
+
assert(status != HighsBasisStatus::kNonbasic);
|
|
1395
|
+
highs_basis.col_status[iCol] = status;
|
|
1396
|
+
if (has_simplex_basis) {
|
|
1397
|
+
assert(move != kIllegalMoveValue);
|
|
1398
|
+
simplex_basis.nonbasicFlag_[iCol] = kNonbasicFlagTrue;
|
|
1399
|
+
simplex_basis.nonbasicMove_[iCol] = move;
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
void Highs::appendBasicRowsToBasisInterface(const HighsInt ext_num_new_row) {
|
|
1405
|
+
if (ext_num_new_row == 0) return;
|
|
1406
|
+
HighsBasis& highs_basis = basis_;
|
|
1407
|
+
if (!highs_basis.useful) return;
|
|
1408
|
+
const bool has_simplex_basis = ekk_instance_.status_.has_basis;
|
|
1409
|
+
SimplexBasis& simplex_basis = ekk_instance_.basis_;
|
|
1410
|
+
HighsLp& lp = model_.lp_;
|
|
1411
|
+
|
|
1412
|
+
assert(highs_basis.col_status.size() == static_cast<size_t>(lp.num_col_));
|
|
1413
|
+
assert(highs_basis.row_status.size() == static_cast<size_t>(lp.num_row_));
|
|
1414
|
+
|
|
1415
|
+
// Add basic logicals
|
|
1416
|
+
// Add the new rows to the Highs basis
|
|
1417
|
+
HighsInt newNumRow = lp.num_row_ + ext_num_new_row;
|
|
1418
|
+
highs_basis.row_status.resize(newNumRow);
|
|
1419
|
+
for (HighsInt iRow = lp.num_row_; iRow < newNumRow; iRow++)
|
|
1420
|
+
highs_basis.row_status[iRow] = HighsBasisStatus::kBasic;
|
|
1421
|
+
if (has_simplex_basis) {
|
|
1422
|
+
// Add the new rows to the simplex basis
|
|
1423
|
+
HighsInt newNumTot = lp.num_col_ + newNumRow;
|
|
1424
|
+
simplex_basis.nonbasicFlag_.resize(newNumTot);
|
|
1425
|
+
simplex_basis.nonbasicMove_.resize(newNumTot);
|
|
1426
|
+
simplex_basis.basicIndex_.resize(newNumRow);
|
|
1427
|
+
for (HighsInt iRow = lp.num_row_; iRow < newNumRow; iRow++) {
|
|
1428
|
+
simplex_basis.nonbasicFlag_[lp.num_col_ + iRow] = kNonbasicFlagFalse;
|
|
1429
|
+
simplex_basis.nonbasicMove_[lp.num_col_ + iRow] = 0;
|
|
1430
|
+
simplex_basis.basicIndex_[iRow] = lp.num_col_ + iRow;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
// Get the basic variables, performing INVERT if necessary
|
|
1436
|
+
HighsStatus Highs::getBasicVariablesInterface(HighsInt* basic_variables) {
|
|
1437
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
1438
|
+
HighsLp& lp = model_.lp_;
|
|
1439
|
+
HighsInt num_row = lp.num_row_;
|
|
1440
|
+
HighsInt num_col = lp.num_col_;
|
|
1441
|
+
HighsSimplexStatus& ekk_status = ekk_instance_.status_;
|
|
1442
|
+
// For an LP with no rows the solution is vacuous
|
|
1443
|
+
if (num_row == 0) return return_status;
|
|
1444
|
+
if (!basis_.valid) {
|
|
1445
|
+
highsLogUser(options_.log_options, HighsLogType::kError,
|
|
1446
|
+
"getBasicVariables called without a HiGHS basis\n");
|
|
1447
|
+
return HighsStatus::kError;
|
|
1448
|
+
}
|
|
1449
|
+
if (!ekk_status.has_invert) {
|
|
1450
|
+
// The LP has no invert to use, so have to set one up, but only
|
|
1451
|
+
// for the current basis, so return_value is the rank deficiency.
|
|
1452
|
+
HighsLpSolverObject solver_object(lp, basis_, solution_, info_,
|
|
1453
|
+
ekk_instance_, callback_, options_,
|
|
1454
|
+
timer_, sub_solver_call_time_);
|
|
1455
|
+
const bool only_from_known_basis = true;
|
|
1456
|
+
return_status = interpretCallStatus(
|
|
1457
|
+
options_.log_options,
|
|
1458
|
+
formSimplexLpBasisAndFactor(solver_object, only_from_known_basis),
|
|
1459
|
+
return_status, "formSimplexLpBasisAndFactor");
|
|
1460
|
+
if (return_status != HighsStatus::kOk) return return_status;
|
|
1461
|
+
}
|
|
1462
|
+
assert(ekk_status.has_invert);
|
|
1463
|
+
|
|
1464
|
+
for (HighsInt row = 0; row < num_row; row++) {
|
|
1465
|
+
HighsInt var = ekk_instance_.basis_.basicIndex_[row];
|
|
1466
|
+
if (var < num_col) {
|
|
1467
|
+
basic_variables[row] = var;
|
|
1468
|
+
} else {
|
|
1469
|
+
basic_variables[row] = -(1 + var - num_col);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
return return_status;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
// Solve (transposed) system involving the basis matrix
|
|
1476
|
+
|
|
1477
|
+
HighsStatus Highs::basisSolveInterface(const vector<double>& rhs,
|
|
1478
|
+
double* solution_vector,
|
|
1479
|
+
HighsInt* solution_num_nz,
|
|
1480
|
+
HighsInt* solution_indices,
|
|
1481
|
+
bool transpose) {
|
|
1482
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
1483
|
+
HighsLp& lp = model_.lp_;
|
|
1484
|
+
HighsInt num_row = lp.num_row_;
|
|
1485
|
+
// For an LP with no rows the solution is vacuous
|
|
1486
|
+
if (num_row == 0) return return_status;
|
|
1487
|
+
// EKK must have an INVERT, but simplex NLA may need the pointer to
|
|
1488
|
+
// its LP to be refreshed so that it can use its scale factors
|
|
1489
|
+
assert(ekk_instance_.status_.has_invert);
|
|
1490
|
+
// Reset the simplex NLA LP and scale pointers for the unscaled LP
|
|
1491
|
+
ekk_instance_.setNlaPointersForLpAndScale(lp);
|
|
1492
|
+
assert(!lp.is_moved_);
|
|
1493
|
+
// Set up solve vector with suitably scaled RHS
|
|
1494
|
+
HVector solve_vector;
|
|
1495
|
+
solve_vector.setup(num_row);
|
|
1496
|
+
solve_vector.clear();
|
|
1497
|
+
HighsInt rhs_num_nz = 0;
|
|
1498
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
1499
|
+
if (rhs[iRow]) {
|
|
1500
|
+
solve_vector.index[rhs_num_nz++] = iRow;
|
|
1501
|
+
solve_vector.array[iRow] = rhs[iRow];
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
solve_vector.count = rhs_num_nz;
|
|
1505
|
+
//
|
|
1506
|
+
// Note that solve_vector.count is just used to determine whether
|
|
1507
|
+
// hyper-sparse solves should be used. The indices of the nonzeros
|
|
1508
|
+
// in the solution are always accumulated. There's no switch (such
|
|
1509
|
+
// as setting solve_vector.count = num_row+1) to not do this.
|
|
1510
|
+
//
|
|
1511
|
+
// Get expected_density from analysis during simplex solve.
|
|
1512
|
+
const double expected_density = 1;
|
|
1513
|
+
if (transpose) {
|
|
1514
|
+
ekk_instance_.btran(solve_vector, expected_density);
|
|
1515
|
+
} else {
|
|
1516
|
+
ekk_instance_.ftran(solve_vector, expected_density);
|
|
1517
|
+
}
|
|
1518
|
+
// Extract the solution
|
|
1519
|
+
if (solution_indices == NULL) {
|
|
1520
|
+
// Nonzeros in the solution not required
|
|
1521
|
+
if (solve_vector.count > num_row) {
|
|
1522
|
+
// Solution nonzeros not known
|
|
1523
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
1524
|
+
solution_vector[iRow] = solve_vector.array[iRow];
|
|
1525
|
+
}
|
|
1526
|
+
} else {
|
|
1527
|
+
// Solution nonzeros are known
|
|
1528
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) solution_vector[iRow] = 0;
|
|
1529
|
+
for (HighsInt iX = 0; iX < solve_vector.count; iX++) {
|
|
1530
|
+
HighsInt iRow = solve_vector.index[iX];
|
|
1531
|
+
solution_vector[iRow] = solve_vector.array[iRow];
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
} else {
|
|
1535
|
+
// Nonzeros in the solution are required
|
|
1536
|
+
if (solve_vector.count > num_row) {
|
|
1537
|
+
// Solution nonzeros not known
|
|
1538
|
+
solution_num_nz = 0;
|
|
1539
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
1540
|
+
solution_vector[iRow] = 0;
|
|
1541
|
+
if (solve_vector.array[iRow]) {
|
|
1542
|
+
solution_vector[iRow] = solve_vector.array[iRow];
|
|
1543
|
+
solution_indices[*solution_num_nz++] = iRow;
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
} else {
|
|
1547
|
+
// Solution nonzeros are known
|
|
1548
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) solution_vector[iRow] = 0;
|
|
1549
|
+
for (HighsInt iX = 0; iX < solve_vector.count; iX++) {
|
|
1550
|
+
HighsInt iRow = solve_vector.index[iX];
|
|
1551
|
+
solution_vector[iRow] = solve_vector.array[iRow];
|
|
1552
|
+
solution_indices[iX] = iRow;
|
|
1553
|
+
}
|
|
1554
|
+
*solution_num_nz = solve_vector.count;
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
return HighsStatus::kOk;
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
void Highs::zeroIterationCounts() {
|
|
1561
|
+
info_.simplex_iteration_count = 0;
|
|
1562
|
+
info_.ipm_iteration_count = 0;
|
|
1563
|
+
info_.crossover_iteration_count = 0;
|
|
1564
|
+
info_.pdlp_iteration_count = 0;
|
|
1565
|
+
info_.qp_iteration_count = 0;
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
HighsStatus Highs::getDualRayInterface(bool& has_dual_ray,
|
|
1569
|
+
double* dual_ray_value) {
|
|
1570
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
1571
|
+
HighsLp& lp = model_.lp_;
|
|
1572
|
+
HighsInt num_row = lp.num_row_;
|
|
1573
|
+
// For an LP with no rows the dual ray is vacuous
|
|
1574
|
+
if (num_row == 0) return return_status;
|
|
1575
|
+
bool has_invert = ekk_instance_.status_.has_invert;
|
|
1576
|
+
assert(!lp.is_moved_);
|
|
1577
|
+
has_dual_ray = ekk_instance_.dual_ray_record_.index != kNoRayIndex;
|
|
1578
|
+
|
|
1579
|
+
// Declare identifiers to save column costs, integrality, any
|
|
1580
|
+
// Hessian and the presolve setting, and a flag to know when they
|
|
1581
|
+
// should be recovered
|
|
1582
|
+
std::vector<double> col_cost;
|
|
1583
|
+
HighsHessian hessian;
|
|
1584
|
+
bool solve_relaxation;
|
|
1585
|
+
std::string presolve;
|
|
1586
|
+
bool solve_feasibility_problem = false;
|
|
1587
|
+
const bool is_qp = model_.isQp();
|
|
1588
|
+
|
|
1589
|
+
if (dual_ray_value != NULL) {
|
|
1590
|
+
// User wants a dual ray whatever
|
|
1591
|
+
if (!has_dual_ray || !has_invert) {
|
|
1592
|
+
// No dual ray is known, or no INVERT to compute it
|
|
1593
|
+
//
|
|
1594
|
+
// No point in trying to get a dual ray if the model status is
|
|
1595
|
+
// optimal
|
|
1596
|
+
if (this->model_status_ == HighsModelStatus::kOptimal) {
|
|
1597
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
1598
|
+
"Model status is optimal, so no dual ray is available\n");
|
|
1599
|
+
return return_status;
|
|
1600
|
+
}
|
|
1601
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
1602
|
+
"Solving LP to try to compute dual ray\n");
|
|
1603
|
+
// Save the column costs, integrality, any Hessian and the
|
|
1604
|
+
// presolve setting
|
|
1605
|
+
col_cost = lp.col_cost_;
|
|
1606
|
+
if (is_qp) hessian = model_.hessian_;
|
|
1607
|
+
this->getOptionValue("presolve", presolve);
|
|
1608
|
+
this->getOptionValue("solve_relaxation", solve_relaxation);
|
|
1609
|
+
solve_feasibility_problem = true;
|
|
1610
|
+
// Zero the costs, integrality and Hessian
|
|
1611
|
+
std::vector<double> zero_costs;
|
|
1612
|
+
zero_costs.assign(lp.num_col_, 0);
|
|
1613
|
+
// Take a copy of the primal ray record, since this will be
|
|
1614
|
+
// cleared by calling changeColsCost
|
|
1615
|
+
HighsRayRecord primal_ray_record =
|
|
1616
|
+
this->ekk_instance_.primal_ray_record_.getRayRecord();
|
|
1617
|
+
HighsStatus status =
|
|
1618
|
+
this->changeColsCost(0, lp.num_col_ - 1, zero_costs.data());
|
|
1619
|
+
assert(status == HighsStatus::kOk);
|
|
1620
|
+
// Reinstate the primal ray record
|
|
1621
|
+
this->ekk_instance_.primal_ray_record_.setRayRecord(primal_ray_record);
|
|
1622
|
+
if (is_qp) {
|
|
1623
|
+
HighsHessian zero_hessian;
|
|
1624
|
+
this->passHessian(zero_hessian);
|
|
1625
|
+
}
|
|
1626
|
+
this->setOptionValue("presolve", kHighsOffString);
|
|
1627
|
+
this->setOptionValue("solve_relaxation", true);
|
|
1628
|
+
HighsStatus call_status = this->run();
|
|
1629
|
+
if (call_status != HighsStatus::kOk) return_status = call_status;
|
|
1630
|
+
has_dual_ray = ekk_instance_.dual_ray_record_.index != kNoRayIndex;
|
|
1631
|
+
has_invert = ekk_instance_.status_.has_invert;
|
|
1632
|
+
assert(has_invert);
|
|
1633
|
+
}
|
|
1634
|
+
if (has_dual_ray) {
|
|
1635
|
+
if (ekk_instance_.dual_ray_record_.value.size()) {
|
|
1636
|
+
// Dual ray is already computed
|
|
1637
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
1638
|
+
"Copying known dual ray\n");
|
|
1639
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++)
|
|
1640
|
+
dual_ray_value[iRow] = ekk_instance_.dual_ray_record_.value[iRow];
|
|
1641
|
+
} else if (has_invert) {
|
|
1642
|
+
// Dual ray is known and can be calculated
|
|
1643
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
1644
|
+
"Solving linear system to compute dual ray\n");
|
|
1645
|
+
vector<double> rhs;
|
|
1646
|
+
HighsInt iRow = ekk_instance_.dual_ray_record_.index;
|
|
1647
|
+
rhs.assign(num_row, 0);
|
|
1648
|
+
rhs[iRow] = ekk_instance_.dual_ray_record_.sign;
|
|
1649
|
+
HighsInt* dual_ray_num_nz = 0;
|
|
1650
|
+
basisSolveInterface(rhs, dual_ray_value, dual_ray_num_nz, NULL, true);
|
|
1651
|
+
// Now save the dual ray itself
|
|
1652
|
+
ekk_instance_.dual_ray_record_.value.resize(num_row);
|
|
1653
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++)
|
|
1654
|
+
ekk_instance_.dual_ray_record_.value[iRow] = dual_ray_value[iRow];
|
|
1655
|
+
} else {
|
|
1656
|
+
assert(!has_invert);
|
|
1657
|
+
// Dual ray is known but cannot be calculated
|
|
1658
|
+
highsLogUser(options_.log_options, HighsLogType::kError,
|
|
1659
|
+
"No LP invertible representation to compute dual ray\n");
|
|
1660
|
+
return_status = HighsStatus::kError;
|
|
1661
|
+
}
|
|
1662
|
+
} else {
|
|
1663
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
1664
|
+
"No dual ray found\n");
|
|
1665
|
+
return_status = HighsStatus::kOk;
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
if (solve_feasibility_problem) {
|
|
1669
|
+
// Feasibility problem has been solved, so any objective-related
|
|
1670
|
+
// information has been lost. Reverting the objective function via
|
|
1671
|
+
// Highs calls clears info_, so better to just copy the data
|
|
1672
|
+
// directly and set the info_ entries that are no longer valid
|
|
1673
|
+
lp.col_cost_ = col_cost;
|
|
1674
|
+
if (is_qp) model_.hessian_ = hessian;
|
|
1675
|
+
this->setOptionValue("presolve", presolve);
|
|
1676
|
+
this->setOptionValue("solve_relaxation", solve_relaxation);
|
|
1677
|
+
// The relaxation for an infeasible MIP may be feasible - so no
|
|
1678
|
+
// ray is generated - so make sure (#2415) that the primal
|
|
1679
|
+
// solution status is reset
|
|
1680
|
+
this->info_.primal_solution_status = SolutionStatus::kSolutionStatusNone;
|
|
1681
|
+
// Modify the objective-related information
|
|
1682
|
+
this->info_.dual_solution_status = SolutionStatus::kSolutionStatusNone;
|
|
1683
|
+
this->info_.objective_function_value = 0;
|
|
1684
|
+
this->info_.invalidateDualKkt();
|
|
1685
|
+
if (has_dual_ray) {
|
|
1686
|
+
assert(this->info_.num_primal_infeasibilities > 0);
|
|
1687
|
+
assert(this->model_status_ == HighsModelStatus::kInfeasible);
|
|
1688
|
+
} else {
|
|
1689
|
+
// If someone has tried to get a dual ray for a feasible problem
|
|
1690
|
+
// - or if the relaxation is feasible - then any model and
|
|
1691
|
+
// primal KKT status of the original model has been lost
|
|
1692
|
+
this->info_.invalidatePrimalKkt();
|
|
1693
|
+
this->model_status_ = HighsModelStatus::kNotset;
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
return return_status;
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
HighsStatus Highs::getPrimalRayInterface(bool& has_primal_ray,
|
|
1700
|
+
double* primal_ray_value) {
|
|
1701
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
1702
|
+
HighsLp& lp = model_.lp_;
|
|
1703
|
+
HighsInt num_row = lp.num_row_;
|
|
1704
|
+
HighsInt num_col = lp.num_col_;
|
|
1705
|
+
// For an LP with no rows the primal ray is vacuous
|
|
1706
|
+
if (num_row == 0) return return_status;
|
|
1707
|
+
if (model_.isQp()) {
|
|
1708
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
1709
|
+
"Cannot find primal ray for unbounded QP\n");
|
|
1710
|
+
return HighsStatus::kError;
|
|
1711
|
+
}
|
|
1712
|
+
bool has_invert = ekk_instance_.status_.has_invert;
|
|
1713
|
+
assert(!lp.is_moved_);
|
|
1714
|
+
has_primal_ray = ekk_instance_.primal_ray_record_.index != kNoRayIndex;
|
|
1715
|
+
|
|
1716
|
+
std::string presolve;
|
|
1717
|
+
bool solve_relaxation;
|
|
1718
|
+
bool allow_unbounded_or_infeasible;
|
|
1719
|
+
bool solve_unboundedness_problem = false;
|
|
1720
|
+
|
|
1721
|
+
if (primal_ray_value != NULL) {
|
|
1722
|
+
// User wants a primal ray whatever
|
|
1723
|
+
if (!has_primal_ray || !has_invert) {
|
|
1724
|
+
// No primal ray is known, or no INVERT to compute it
|
|
1725
|
+
//
|
|
1726
|
+
// No point in trying to get a primal ray if the model status is
|
|
1727
|
+
// optimal
|
|
1728
|
+
if (this->model_status_ == HighsModelStatus::kOptimal) {
|
|
1729
|
+
highsLogUser(
|
|
1730
|
+
options_.log_options, HighsLogType::kInfo,
|
|
1731
|
+
"Model status is optimal, so no primal ray is available\n");
|
|
1732
|
+
return return_status;
|
|
1733
|
+
}
|
|
1734
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
1735
|
+
"Solving LP to try to compute primal ray\n");
|
|
1736
|
+
this->getOptionValue("presolve", presolve);
|
|
1737
|
+
this->getOptionValue("solve_relaxation", solve_relaxation);
|
|
1738
|
+
this->getOptionValue("allow_unbounded_or_infeasible",
|
|
1739
|
+
allow_unbounded_or_infeasible);
|
|
1740
|
+
solve_unboundedness_problem = true;
|
|
1741
|
+
this->setOptionValue("presolve", kHighsOffString);
|
|
1742
|
+
this->setOptionValue("solve_relaxation", true);
|
|
1743
|
+
this->setOptionValue("allow_unbounded_or_infeasible", false);
|
|
1744
|
+
HighsStatus call_status = this->run();
|
|
1745
|
+
if (call_status != HighsStatus::kOk) return_status = call_status;
|
|
1746
|
+
has_primal_ray = ekk_instance_.primal_ray_record_.index != kNoRayIndex;
|
|
1747
|
+
has_invert = ekk_instance_.status_.has_invert;
|
|
1748
|
+
assert(has_invert);
|
|
1749
|
+
}
|
|
1750
|
+
if (has_primal_ray) {
|
|
1751
|
+
if (ekk_instance_.primal_ray_record_.value.size()) {
|
|
1752
|
+
// Primal ray is already computed
|
|
1753
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
1754
|
+
"Copying known primal ray\n");
|
|
1755
|
+
for (HighsInt iCol = 0; iCol < num_col; iCol++)
|
|
1756
|
+
primal_ray_value[iCol] = ekk_instance_.primal_ray_record_.value[iCol];
|
|
1757
|
+
return return_status;
|
|
1758
|
+
} else if (has_invert) {
|
|
1759
|
+
// Primal ray is known and can be calculated
|
|
1760
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
1761
|
+
"Solving linear system to compute primal ray\n");
|
|
1762
|
+
HighsInt col = ekk_instance_.primal_ray_record_.index;
|
|
1763
|
+
assert(ekk_instance_.basis_.nonbasicFlag_[col] == kNonbasicFlagTrue);
|
|
1764
|
+
// Get this pivotal column
|
|
1765
|
+
vector<double> rhs;
|
|
1766
|
+
vector<double> column;
|
|
1767
|
+
column.assign(num_row, 0);
|
|
1768
|
+
rhs.assign(num_row, 0);
|
|
1769
|
+
lp.ensureColwise();
|
|
1770
|
+
HighsInt primal_ray_sign = ekk_instance_.primal_ray_record_.sign;
|
|
1771
|
+
if (col < num_col) {
|
|
1772
|
+
for (HighsInt iEl = lp.a_matrix_.start_[col];
|
|
1773
|
+
iEl < lp.a_matrix_.start_[col + 1]; iEl++)
|
|
1774
|
+
rhs[lp.a_matrix_.index_[iEl]] =
|
|
1775
|
+
primal_ray_sign * lp.a_matrix_.value_[iEl];
|
|
1776
|
+
} else {
|
|
1777
|
+
rhs[col - num_col] = primal_ray_sign;
|
|
1778
|
+
}
|
|
1779
|
+
HighsInt* column_num_nz = 0;
|
|
1780
|
+
basisSolveInterface(rhs, column.data(), column_num_nz, NULL, false);
|
|
1781
|
+
// Now zero primal_ray_value and scatter the column according to
|
|
1782
|
+
// the basic variables.
|
|
1783
|
+
for (HighsInt iCol = 0; iCol < num_col; iCol++)
|
|
1784
|
+
primal_ray_value[iCol] = 0;
|
|
1785
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
1786
|
+
HighsInt iCol = ekk_instance_.basis_.basicIndex_[iRow];
|
|
1787
|
+
if (iCol < num_col) primal_ray_value[iCol] = column[iRow];
|
|
1788
|
+
}
|
|
1789
|
+
if (col < num_col) primal_ray_value[col] = -primal_ray_sign;
|
|
1790
|
+
// Now save the primal ray itself
|
|
1791
|
+
ekk_instance_.primal_ray_record_.value.resize(num_col);
|
|
1792
|
+
for (HighsInt iCol = 0; iCol < num_col; iCol++)
|
|
1793
|
+
ekk_instance_.primal_ray_record_.value[iCol] = primal_ray_value[iCol];
|
|
1794
|
+
}
|
|
1795
|
+
} else {
|
|
1796
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
1797
|
+
"No primal ray found\n");
|
|
1798
|
+
return_status = HighsStatus::kOk;
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
const bool is_mip = this->model_.isMip();
|
|
1802
|
+
if (solve_unboundedness_problem) {
|
|
1803
|
+
if (is_mip) {
|
|
1804
|
+
// Unboundedness LP has been solved, but that will give dual
|
|
1805
|
+
// solution status kInfeasible which, for a MIP is not correct
|
|
1806
|
+
this->info_.dual_solution_status = SolutionStatus::kSolutionStatusNone;
|
|
1807
|
+
this->info_.invalidateDualKkt();
|
|
1808
|
+
}
|
|
1809
|
+
// Restore the option values
|
|
1810
|
+
this->setOptionValue("presolve", presolve);
|
|
1811
|
+
this->setOptionValue("solve_relaxation", solve_relaxation);
|
|
1812
|
+
this->setOptionValue("allow_unbounded_or_infeasible",
|
|
1813
|
+
allow_unbounded_or_infeasible);
|
|
1814
|
+
if (has_primal_ray) {
|
|
1815
|
+
assert(is_mip || this->info_.num_dual_infeasibilities > 0);
|
|
1816
|
+
assert(this->model_status_ == HighsModelStatus::kUnbounded);
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
return return_status;
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
HighsStatus Highs::getRangingInterface() {
|
|
1823
|
+
HighsLpSolverObject solver_object(model_.lp_, basis_, solution_, info_,
|
|
1824
|
+
ekk_instance_, callback_, options_, timer_,
|
|
1825
|
+
sub_solver_call_time_);
|
|
1826
|
+
solver_object.model_status_ = model_status_;
|
|
1827
|
+
return getRangingData(this->ranging_, solver_object);
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
HighsStatus Highs::getIisInterfaceReturn(
|
|
1831
|
+
const HighsStatus return_status, const HighsOptions& original_options,
|
|
1832
|
+
const std::vector<bool>& original_callback_active) {
|
|
1833
|
+
// Restore options and callbacks
|
|
1834
|
+
this->options_ = original_options;
|
|
1835
|
+
for (int i = kCallbackMin; i <= kCallbackMax; i++) {
|
|
1836
|
+
if (original_callback_active[i]) this->startCallback(i);
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
// Exit early if there was an error
|
|
1840
|
+
if (return_status == HighsStatus::kError) {
|
|
1841
|
+
// Report final results
|
|
1842
|
+
this->iis_.reportFinal(original_options);
|
|
1843
|
+
return return_status;
|
|
1844
|
+
}
|
|
1845
|
+
assert(this->iis_.valid_);
|
|
1846
|
+
|
|
1847
|
+
// A valid HighsIis instance is one for which the information is
|
|
1848
|
+
// known to be correct
|
|
1849
|
+
//
|
|
1850
|
+
// In the case of a system that's feasible this will give empty
|
|
1851
|
+
// HighsIis::col_index_ and HighsIis::row_index_
|
|
1852
|
+
//
|
|
1853
|
+
// If the system is infeasible, then it's possible that only an IS
|
|
1854
|
+
// (not an IIS) has been formed. This will be identified by the
|
|
1855
|
+
// HighsIis::col_bound_ and HighsIis::row_bound_ of the columns and
|
|
1856
|
+
// rows in HighsIis::col_index_ and HighsIis::row_index_ being
|
|
1857
|
+
// kIisStatusMaybeInConflict, rather than kIisStatusInConflict
|
|
1858
|
+
//
|
|
1859
|
+
// The columns and rows not in HighsIis::col_index_ and
|
|
1860
|
+
// HighsIis::row_index_ have HighsIis::col_bound_ and
|
|
1861
|
+
// HighsIis::row_bound_ values set to kIisStatusNotInConflict
|
|
1862
|
+
|
|
1863
|
+
// If the IIS process has identified infeasibility, then set
|
|
1864
|
+
if (this->iis_.status_ >= kIisModelStatusTimeLimit)
|
|
1865
|
+
this->model_status_ = HighsModelStatus::kInfeasible;
|
|
1866
|
+
|
|
1867
|
+
HighsLp& lp = this->model_.lp_;
|
|
1868
|
+
HighsLp& iis_lp = this->iis_.model_.lp_;
|
|
1869
|
+
const bool has_is =
|
|
1870
|
+
this->iis_.col_index_.size() || this->iis_.row_index_.size();
|
|
1871
|
+
const bool has_iis = this->iis_.status_ == kIisModelStatusIrreducible;
|
|
1872
|
+
|
|
1873
|
+
HighsOptions opts = this->options_;
|
|
1874
|
+
opts.time_limit = kHighsInf;
|
|
1875
|
+
opts.simplex_iteration_limit = kHighsIInf;
|
|
1876
|
+
opts.objective_bound = kHighsInf;
|
|
1877
|
+
|
|
1878
|
+
if (has_iis) assert(has_is);
|
|
1879
|
+
if (has_is) {
|
|
1880
|
+
// Construct the HighsIis LP
|
|
1881
|
+
this->iis_.setLp(lp);
|
|
1882
|
+
// Check that the LP data are OK (correspond to original model
|
|
1883
|
+
// reduced to HighsIis col/row and bound data).
|
|
1884
|
+
bool lp_data_ok = this->iis_.lpDataOk(lp, opts);
|
|
1885
|
+
assert(lp_data_ok);
|
|
1886
|
+
if (!lp_data_ok) {
|
|
1887
|
+
// Report final results
|
|
1888
|
+
this->iis_.reportFinal(original_options);
|
|
1889
|
+
return HighsStatus::kError;
|
|
1890
|
+
}
|
|
1891
|
+
// Check that the HighsIis LP has the property of being infeasible
|
|
1892
|
+
// and, if a true IIS is claimed, optimal/unbounded if any bound
|
|
1893
|
+
// is relaxed
|
|
1894
|
+
bool lp_ok = this->iis_.lpOk(opts);
|
|
1895
|
+
if (!lp_ok) {
|
|
1896
|
+
// If we fail to prove infeasibility mark candidate set as invalid and
|
|
1897
|
+
// return with a warning
|
|
1898
|
+
this->iis_.valid_ = false;
|
|
1899
|
+
if (this->iis_.status_ != kIisModelStatusTimeLimit)
|
|
1900
|
+
this->iis_.status_ = kIisModelStatusUnknown;
|
|
1901
|
+
// Report final results
|
|
1902
|
+
this->iis_.reportFinal(original_options);
|
|
1903
|
+
return HighsStatus::kWarning;
|
|
1904
|
+
}
|
|
1905
|
+
} else {
|
|
1906
|
+
assert(this->iis_.status_ <= kIisModelStatusReducible);
|
|
1907
|
+
assert(!this->iis_.col_bound_.size());
|
|
1908
|
+
assert(!this->iis_.row_bound_.size());
|
|
1909
|
+
}
|
|
1910
|
+
// Construct the ISS status vectors for cols and rows of original
|
|
1911
|
+
// model
|
|
1912
|
+
this->iis_.setStatus(lp);
|
|
1913
|
+
// Check consistency of the col/row_index_ and col/row_status_
|
|
1914
|
+
bool index_status_ok = this->iis_.indexStatusOk(lp);
|
|
1915
|
+
assert(index_status_ok);
|
|
1916
|
+
if (!index_status_ok) {
|
|
1917
|
+
this->iis_.reportFinal(original_options);
|
|
1918
|
+
return HighsStatus::kError;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
// Report final results
|
|
1922
|
+
this->iis_.reportFinal(original_options);
|
|
1923
|
+
return return_status;
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
HighsStatus Highs::getIisInterface() {
|
|
1927
|
+
if (this->model_status_ == HighsModelStatus::kOptimal ||
|
|
1928
|
+
this->model_status_ == HighsModelStatus::kUnbounded) {
|
|
1929
|
+
// Strange to call getIis for a model that's known to be feasible
|
|
1930
|
+
highsLogUser(
|
|
1931
|
+
options_.log_options, HighsLogType::kInfo,
|
|
1932
|
+
"Calling Highs::getIis for a model that is known to be feasible\n");
|
|
1933
|
+
this->iis_.clear();
|
|
1934
|
+
// No IIS exists, so validate the empty HighsIis instance
|
|
1935
|
+
this->iis_.valid_ = true;
|
|
1936
|
+
this->iis_.status_ = kIisModelStatusFeasible;
|
|
1937
|
+
return this->getIisInterfaceReturn(HighsStatus::kOk, options_,
|
|
1938
|
+
callback_.active);
|
|
1939
|
+
}
|
|
1940
|
+
// Early exit for existing valid IIS
|
|
1941
|
+
if (this->iis_.valid_)
|
|
1942
|
+
return this->getIisInterfaceReturn(HighsStatus::kOk, options_,
|
|
1943
|
+
callback_.active);
|
|
1944
|
+
// Clear IIS
|
|
1945
|
+
this->iis_.clear();
|
|
1946
|
+
// Check for trivial IIS: empty infeasible row or inconsistent bounds
|
|
1947
|
+
const HighsLp& lp = model_.lp_;
|
|
1948
|
+
if (this->iis_.trivial(lp, options_))
|
|
1949
|
+
return this->getIisInterfaceReturn(HighsStatus::kOk, options_,
|
|
1950
|
+
callback_.active);
|
|
1951
|
+
HighsInt num_row = lp.num_row_;
|
|
1952
|
+
if (num_row == 0) {
|
|
1953
|
+
// For an LP with no rows, the only scope for infeasibility is
|
|
1954
|
+
// inconsistent columns bounds - which has already been assessed,
|
|
1955
|
+
// so validate the empty HighsIis instance
|
|
1956
|
+
this->iis_.valid_ = true;
|
|
1957
|
+
return this->getIisInterfaceReturn(HighsStatus::kOk, options_,
|
|
1958
|
+
callback_.active);
|
|
1959
|
+
}
|
|
1960
|
+
// Look for infeasible rows based on row value bounds
|
|
1961
|
+
if (this->iis_.rowValueBounds(lp, options_))
|
|
1962
|
+
return this->getIisInterfaceReturn(HighsStatus::kOk, options_,
|
|
1963
|
+
callback_.active);
|
|
1964
|
+
// Don't continue with more expensive techniques if using the IIS
|
|
1965
|
+
// light strategy
|
|
1966
|
+
if (options_.iis_strategy == kIisStrategyLight)
|
|
1967
|
+
return this->getIisInterfaceReturn(HighsStatus::kOk, options_,
|
|
1968
|
+
callback_.active);
|
|
1969
|
+
// Clear IIS
|
|
1970
|
+
this->iis_.clear();
|
|
1971
|
+
// Save original options
|
|
1972
|
+
HighsOptions original_options = this->options_;
|
|
1973
|
+
// Save original active callbacks and disable all except for
|
|
1974
|
+
// kCallbackLogging and kCallbackSimplexInterrupt
|
|
1975
|
+
std::vector<bool> original_callback_active = callback_.active;
|
|
1976
|
+
for (int i = kCallbackMin; i <= kCallbackMax; i++) {
|
|
1977
|
+
if (i != kCallbackLogging && i != kCallbackSimplexInterrupt &&
|
|
1978
|
+
callback_.active[i])
|
|
1979
|
+
this->stopCallback(i);
|
|
1980
|
+
}
|
|
1981
|
+
// Zero out all clocks and set time_limit to iis_time_limit
|
|
1982
|
+
this->zeroAllClocks();
|
|
1983
|
+
this->setOptionValue("time_limit", options_.iis_time_limit);
|
|
1984
|
+
// Disallow kIterationLimit and kObjectiveBound model statuses
|
|
1985
|
+
this->setOptionValue("simplex_iteration_limit", kHighsIInf);
|
|
1986
|
+
this->setOptionValue("objective_bound", kHighsInf);
|
|
1987
|
+
// Disallow kUnboundedOrInfeasible model status
|
|
1988
|
+
this->setOptionValue("allow_unbounded_or_infeasible", false);
|
|
1989
|
+
// Run model with new options if needed
|
|
1990
|
+
if (this->model_status_ == HighsModelStatus::kNotset ||
|
|
1991
|
+
this->model_status_ == HighsModelStatus::kIterationLimit ||
|
|
1992
|
+
this->model_status_ == HighsModelStatus::kObjectiveBound ||
|
|
1993
|
+
this->model_status_ == HighsModelStatus::kInterrupt ||
|
|
1994
|
+
this->model_status_ == HighsModelStatus::kTimeLimit ||
|
|
1995
|
+
this->model_status_ == HighsModelStatus::kUnboundedOrInfeasible) {
|
|
1996
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
1997
|
+
"Model status is %s. Resolving to establish infeasibility "
|
|
1998
|
+
"before computing IIS\n\n",
|
|
1999
|
+
this->modelStatusToString(this->model_status_).c_str());
|
|
2000
|
+
double simplex_time = -this->getRunTime();
|
|
2001
|
+
HighsInt simplex_iterations = -info_.simplex_iteration_count;
|
|
2002
|
+
HighsStatus run_status = this->optimizeModel();
|
|
2003
|
+
simplex_time += this->getRunTime();
|
|
2004
|
+
simplex_iterations += info_.simplex_iteration_count;
|
|
2005
|
+
this->iis_.info_.update(simplex_time, simplex_iterations);
|
|
2006
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo, "\n");
|
|
2007
|
+
}
|
|
2008
|
+
if (this->model_status_ == HighsModelStatus::kOptimal ||
|
|
2009
|
+
this->model_status_ == HighsModelStatus::kUnbounded) {
|
|
2010
|
+
// Model became feasible
|
|
2011
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
2012
|
+
"Model became feasible\n");
|
|
2013
|
+
// No IIS exists, so validate the empty HighsIis instance
|
|
2014
|
+
this->iis_.valid_ = true;
|
|
2015
|
+
this->iis_.status_ = kIisModelStatusFeasible;
|
|
2016
|
+
this->iis_.strategy_ = options_.iis_strategy;
|
|
2017
|
+
return this->getIisInterfaceReturn(HighsStatus::kOk, original_options,
|
|
2018
|
+
original_callback_active);
|
|
2019
|
+
} else if (this->model_status_ == HighsModelStatus::kTimeLimit) {
|
|
2020
|
+
// Time limit reached
|
|
2021
|
+
highsLogUser(options_.log_options, HighsLogType::kError,
|
|
2022
|
+
"Time limit reached prior to establishing infeasibility\n");
|
|
2023
|
+
this->iis_.status_ = kIisModelStatusTimeLimit;
|
|
2024
|
+
this->iis_.strategy_ = options_.iis_strategy;
|
|
2025
|
+
return this->getIisInterfaceReturn(HighsStatus::kError, original_options,
|
|
2026
|
+
original_callback_active);
|
|
2027
|
+
} else if (this->model_status_ != HighsModelStatus::kInfeasible) {
|
|
2028
|
+
// kModelEmpty, kModelError, kSolveError, kMemoryLimit, kUnknown model
|
|
2029
|
+
// status
|
|
2030
|
+
highsLogUser(options_.log_options, HighsLogType::kError,
|
|
2031
|
+
"Can not compute IIS for a model with status %s\n",
|
|
2032
|
+
this->modelStatusToString(this->model_status_).c_str());
|
|
2033
|
+
this->iis_.strategy_ = options_.iis_strategy;
|
|
2034
|
+
return this->getIisInterfaceReturn(HighsStatus::kError, original_options,
|
|
2035
|
+
original_callback_active);
|
|
2036
|
+
}
|
|
2037
|
+
assert(this->model_status_ == HighsModelStatus::kInfeasible);
|
|
2038
|
+
|
|
2039
|
+
// Construct an IS from ray or lp
|
|
2040
|
+
bool ray_option =
|
|
2041
|
+
// kIisStrategyFromRay & options_.iis_strategy;
|
|
2042
|
+
false;
|
|
2043
|
+
const bool lp_option = kIisStrategyFromLp & options_.iis_strategy;
|
|
2044
|
+
if (ray_option && !ekk_instance_.status_.has_invert) {
|
|
2045
|
+
// Model is known to be infeasible, and a dual ray option is
|
|
2046
|
+
// chosen, but it has no INVERT, presumably because infeasibility
|
|
2047
|
+
// detected in presolve, so solve without presolve
|
|
2048
|
+
std::string presolve = options_.presolve;
|
|
2049
|
+
options_.presolve = kHighsOffString;
|
|
2050
|
+
|
|
2051
|
+
double simplex_time = -this->getRunTime();
|
|
2052
|
+
HighsInt simplex_iterations = -info_.simplex_iteration_count;
|
|
2053
|
+
HighsStatus run_status = this->optimizeModel();
|
|
2054
|
+
options_.presolve = presolve;
|
|
2055
|
+
simplex_time += this->getRunTime();
|
|
2056
|
+
simplex_iterations += info_.simplex_iteration_count;
|
|
2057
|
+
this->iis_.info_.update(simplex_time, simplex_iterations);
|
|
2058
|
+
|
|
2059
|
+
// Model should remain infeasible!
|
|
2060
|
+
if (this->model_status_ == HighsModelStatus::kTimeLimit) {
|
|
2061
|
+
// Time limit reached
|
|
2062
|
+
this->iis_.status_ = kIisModelStatusTimeLimit;
|
|
2063
|
+
return this->getIisInterfaceReturn(HighsStatus::kError, original_options,
|
|
2064
|
+
original_callback_active);
|
|
2065
|
+
} else if (this->model_status_ != HighsModelStatus::kInfeasible) {
|
|
2066
|
+
highsLogUser(
|
|
2067
|
+
options_.log_options, HighsLogType::kError,
|
|
2068
|
+
"Model status has switched from %s to %s when solving without "
|
|
2069
|
+
"presolve\n",
|
|
2070
|
+
this->modelStatusToString(HighsModelStatus::kInfeasible).c_str(),
|
|
2071
|
+
this->modelStatusToString(this->model_status_).c_str());
|
|
2072
|
+
return this->getIisInterfaceReturn(HighsStatus::kError, original_options,
|
|
2073
|
+
original_callback_active);
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
const bool has_dual_ray = ekk_instance_.dual_ray_record_.index != kNoRayIndex;
|
|
2077
|
+
if (ray_option && !has_dual_ray)
|
|
2078
|
+
highsLogUser(options_.log_options, HighsLogType::kWarning,
|
|
2079
|
+
"No known dual ray from which to compute IIS\n");
|
|
2080
|
+
ray_option = ray_option && has_dual_ray;
|
|
2081
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
2082
|
+
if (ray_option) {
|
|
2083
|
+
assert(has_dual_ray);
|
|
2084
|
+
// Compute the dual ray to identify an infeasible subset of rows
|
|
2085
|
+
assert(ekk_instance_.status_.has_invert);
|
|
2086
|
+
assert(!lp.is_moved_);
|
|
2087
|
+
std::vector<double> rhs;
|
|
2088
|
+
HighsInt iRow = ekk_instance_.dual_ray_record_.index;
|
|
2089
|
+
rhs.assign(num_row, 0);
|
|
2090
|
+
rhs[iRow] = 1;
|
|
2091
|
+
std::vector<double> dual_ray_value(num_row);
|
|
2092
|
+
HighsInt* dual_ray_num_nz = 0;
|
|
2093
|
+
basisSolveInterface(rhs, dual_ray_value.data(), dual_ray_num_nz, NULL,
|
|
2094
|
+
true);
|
|
2095
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++)
|
|
2096
|
+
if (dual_ray_value[iRow]) this->iis_.row_index_.push_back(iRow);
|
|
2097
|
+
} else if (lp_option) {
|
|
2098
|
+
// Full LP option chosen or no dual ray to use
|
|
2099
|
+
// Apply the elasticity filter to the whole model in order to
|
|
2100
|
+
// determine an infeasible subset of rows
|
|
2101
|
+
return_status = this->elasticityFilter(-1.0, -1.0, 1.0, nullptr, nullptr,
|
|
2102
|
+
nullptr, true);
|
|
2103
|
+
}
|
|
2104
|
+
// Do not continue if not using kIisStrategyIrreducible or if time limit is
|
|
2105
|
+
// reached
|
|
2106
|
+
if (!(kIisStrategyIrreducible & this->options_.iis_strategy) ||
|
|
2107
|
+
(this->iis_.status_ == kIisModelStatusTimeLimit))
|
|
2108
|
+
return this->getIisInterfaceReturn(return_status, original_options,
|
|
2109
|
+
original_callback_active);
|
|
2110
|
+
|
|
2111
|
+
// If neither ray and lp options were requested or if they fail to produce a
|
|
2112
|
+
// valid IS, make one consisting of all constraints
|
|
2113
|
+
if (!this->iis_.valid_) {
|
|
2114
|
+
this->iis_.valid_ = true;
|
|
2115
|
+
this->iis_.status_ = kIisModelStatusReducible;
|
|
2116
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++)
|
|
2117
|
+
this->iis_.row_index_.push_back(iRow);
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
assert(this->iis_.row_index_.size());
|
|
2121
|
+
// A subset of infeasible rows, so at least have a reducible
|
|
2122
|
+
// infeasibility set
|
|
2123
|
+
|
|
2124
|
+
// Attempt to compute a true IIS
|
|
2125
|
+
//
|
|
2126
|
+
// To do this the matrix must be column-wise
|
|
2127
|
+
model_.lp_.a_matrix_.ensureColwise();
|
|
2128
|
+
return_status = this->iis_.deduce(lp, options_, callback_, basis_);
|
|
2129
|
+
|
|
2130
|
+
// Analyse the LP solution data
|
|
2131
|
+
const HighsInt num_lp_solved = this->iis_.info_.num_lp_solved;
|
|
2132
|
+
const double min_time = this->iis_.info_.min_simplex_time;
|
|
2133
|
+
const double sum_time = this->iis_.info_.sum_simplex_times;
|
|
2134
|
+
const double max_time = this->iis_.info_.max_simplex_time;
|
|
2135
|
+
const HighsInt min_iterations = this->iis_.info_.min_simplex_iteration_count;
|
|
2136
|
+
const HighsInt sum_iterations = this->iis_.info_.sum_simplex_iteration_counts;
|
|
2137
|
+
const HighsInt max_iterations = this->iis_.info_.max_simplex_iteration_count;
|
|
2138
|
+
|
|
2139
|
+
if (kIisDevReport) {
|
|
2140
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
2141
|
+
" %d cols, %d rows, %d LPs solved"
|
|
2142
|
+
" (min / average / max) iteration count (%6d / %6.2g / % 6d)"
|
|
2143
|
+
" and time (%6.2f / %6.2f / % 6.2f) \n",
|
|
2144
|
+
int(this->iis_.col_index_.size()),
|
|
2145
|
+
int(this->iis_.row_index_.size()), int(num_lp_solved),
|
|
2146
|
+
int(min_iterations),
|
|
2147
|
+
num_lp_solved > 0 ? (1.0 * sum_iterations) / num_lp_solved : 0,
|
|
2148
|
+
int(max_iterations), min_time,
|
|
2149
|
+
num_lp_solved > 0 ? sum_time / num_lp_solved : 0, max_time);
|
|
2150
|
+
}
|
|
2151
|
+
return this->getIisInterfaceReturn(return_status, original_options,
|
|
2152
|
+
original_callback_active);
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
HighsStatus Highs::elasticityFilterReturn(
|
|
2156
|
+
const HighsStatus return_status, const std::string& original_model_name,
|
|
2157
|
+
const HighsModelStatus original_model_status,
|
|
2158
|
+
const HighsInt original_num_col, const HighsInt original_num_row,
|
|
2159
|
+
const std::vector<double>& original_col_cost,
|
|
2160
|
+
const std::vector<double>& original_col_lower,
|
|
2161
|
+
const std::vector<double>& original_col_upper,
|
|
2162
|
+
const std::vector<HighsVarType>& original_integrality) {
|
|
2163
|
+
const HighsLp& lp = this->model_.lp_;
|
|
2164
|
+
// The IIS is cleared by restoring the original LP, so save it
|
|
2165
|
+
HighsIis iis = this->iis_;
|
|
2166
|
+
double objective_function_value = info_.objective_function_value;
|
|
2167
|
+
// Delete any additional rows and columns, and restore the original
|
|
2168
|
+
// column costs and bounds
|
|
2169
|
+
HighsStatus run_status;
|
|
2170
|
+
run_status = this->deleteRows(original_num_row, lp.num_row_ - 1);
|
|
2171
|
+
assert(run_status == HighsStatus::kOk);
|
|
2172
|
+
|
|
2173
|
+
run_status = this->deleteCols(original_num_col, lp.num_col_ - 1);
|
|
2174
|
+
assert(run_status == HighsStatus::kOk);
|
|
2175
|
+
//
|
|
2176
|
+
// Now that deleteRows and deleteCols may yield a valid basis, the
|
|
2177
|
+
// lack of dual values triggers an assert in
|
|
2178
|
+
// getKktFailures. Ultimately (#2081) the dual values will be
|
|
2179
|
+
// available but, for now, make the basis invalid.
|
|
2180
|
+
basis_.valid = false;
|
|
2181
|
+
|
|
2182
|
+
run_status =
|
|
2183
|
+
this->changeColsCost(0, original_num_col - 1, original_col_cost.data());
|
|
2184
|
+
assert(run_status == HighsStatus::kOk);
|
|
2185
|
+
|
|
2186
|
+
run_status =
|
|
2187
|
+
this->changeColsBounds(0, original_num_col - 1, original_col_lower.data(),
|
|
2188
|
+
original_col_upper.data());
|
|
2189
|
+
assert(run_status == HighsStatus::kOk);
|
|
2190
|
+
|
|
2191
|
+
if (kIisStrategyRelaxation & this->options_.iis_strategy &&
|
|
2192
|
+
original_integrality.size()) {
|
|
2193
|
+
this->changeColsIntegrality(0, original_num_col - 1,
|
|
2194
|
+
original_integrality.data());
|
|
2195
|
+
assert(run_status == HighsStatus::kOk);
|
|
2196
|
+
}
|
|
2197
|
+
// Revert the model name
|
|
2198
|
+
this->passModelName(original_model_name);
|
|
2199
|
+
assert(lp.num_col_ == original_num_col);
|
|
2200
|
+
assert(lp.num_row_ == original_num_row);
|
|
2201
|
+
|
|
2202
|
+
// Clear solver data
|
|
2203
|
+
this->invalidateSolverData();
|
|
2204
|
+
|
|
2205
|
+
if (return_status == HighsStatus::kOk) {
|
|
2206
|
+
// Solution is invalidated by deleting rows and columns, but
|
|
2207
|
+
// primal values are correct. Have to recompute row activities,
|
|
2208
|
+
// though
|
|
2209
|
+
this->model_.lp_.a_matrix_.productQuad(this->solution_.row_value,
|
|
2210
|
+
this->solution_.col_value);
|
|
2211
|
+
this->solution_.value_valid = true;
|
|
2212
|
+
// Set the feasibility objective and any KKT failures
|
|
2213
|
+
info_.objective_function_value = objective_function_value;
|
|
2214
|
+
getKktFailures(options_, model_, solution_, basis_, info_);
|
|
2215
|
+
info_.valid = true;
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
// Revert model status
|
|
2219
|
+
this->model_status_ = original_model_status;
|
|
2220
|
+
|
|
2221
|
+
// Restore IIS
|
|
2222
|
+
this->iis_ = iis;
|
|
2223
|
+
|
|
2224
|
+
return return_status;
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
HighsStatus Highs::elasticityFilter(const double global_lower_penalty,
|
|
2228
|
+
const double global_upper_penalty,
|
|
2229
|
+
const double global_rhs_penalty,
|
|
2230
|
+
const double* local_lower_penalty,
|
|
2231
|
+
const double* local_upper_penalty,
|
|
2232
|
+
const double* local_rhs_penalty,
|
|
2233
|
+
const bool get_iis) {
|
|
2234
|
+
// this->writeModel("infeasible.mps");
|
|
2235
|
+
//
|
|
2236
|
+
// Solve the feasibility relaxation problem for the given penalties,
|
|
2237
|
+
// continuing to act as the elasticity filter if get_iis
|
|
2238
|
+
// is true, resulting in an infeasibility subset for further
|
|
2239
|
+
// refinement as an IIS
|
|
2240
|
+
//
|
|
2241
|
+
// Construct the e-LP:
|
|
2242
|
+
//
|
|
2243
|
+
// Constraints L <= Ax <= U; l <= x <= u
|
|
2244
|
+
//
|
|
2245
|
+
// Transformed to
|
|
2246
|
+
//
|
|
2247
|
+
// L <= Ax + e_L - e_U <= U,
|
|
2248
|
+
//
|
|
2249
|
+
// l <= x + e_l - e_u <= u,
|
|
2250
|
+
//
|
|
2251
|
+
// where the elastic variables are not used if the corresponding
|
|
2252
|
+
// bound is infinite or the local/global penalty is negative.
|
|
2253
|
+
//
|
|
2254
|
+
// x is free, and the objective is the linear function of the
|
|
2255
|
+
// elastic variables given by the local/global penalties
|
|
2256
|
+
//
|
|
2257
|
+
// col_of_ecol lists the column indices corresponding to the entries in
|
|
2258
|
+
// bound_of_col_of_ecol_is_lower so that the results can be interpreted
|
|
2259
|
+
//
|
|
2260
|
+
// row_of_ecol lists the row indices corresponding to the entries in
|
|
2261
|
+
// bound_of_row_of_ecol_is_lower so that the results can be interpreted
|
|
2262
|
+
std::vector<HighsInt> col_of_ecol;
|
|
2263
|
+
std::vector<HighsInt> row_of_ecol;
|
|
2264
|
+
std::vector<bool> bound_of_row_of_ecol_is_lower;
|
|
2265
|
+
std::vector<bool> bound_of_col_of_ecol_is_lower;
|
|
2266
|
+
std::vector<double> erow_lower;
|
|
2267
|
+
std::vector<double> erow_upper;
|
|
2268
|
+
std::vector<HighsInt> erow_start;
|
|
2269
|
+
std::vector<HighsInt> erow_index;
|
|
2270
|
+
std::vector<double> erow_value;
|
|
2271
|
+
// Accumulate names for ecols and erows, re-using ecol_name for the
|
|
2272
|
+
// names of row ecols after defining the names of col ecols
|
|
2273
|
+
std::vector<std::string> ecol_name;
|
|
2274
|
+
std::vector<std::string> erow_name;
|
|
2275
|
+
std::vector<double> ecol_cost;
|
|
2276
|
+
std::vector<double> ecol_lower;
|
|
2277
|
+
std::vector<double> ecol_upper;
|
|
2278
|
+
const HighsLp& lp = this->model_.lp_;
|
|
2279
|
+
HighsInt evar_ix = lp.num_col_;
|
|
2280
|
+
HighsStatus run_status;
|
|
2281
|
+
const bool write_model = false;
|
|
2282
|
+
// Take copies of the original model name, dimensions and column
|
|
2283
|
+
// data vectors, as they will be modified in forming the e-LP
|
|
2284
|
+
const std::string original_model_name = lp.model_name_;
|
|
2285
|
+
const HighsModelStatus original_model_status = this->getModelStatus();
|
|
2286
|
+
const HighsInt original_num_col = lp.num_col_;
|
|
2287
|
+
const HighsInt original_num_row = lp.num_row_;
|
|
2288
|
+
const std::vector<double> original_col_cost = lp.col_cost_;
|
|
2289
|
+
const std::vector<double> original_col_lower = lp.col_lower_;
|
|
2290
|
+
const std::vector<double> original_col_upper = lp.col_upper_;
|
|
2291
|
+
const std::vector<HighsVarType> original_integrality = lp.integrality_;
|
|
2292
|
+
HighsIis iis = this->iis_;
|
|
2293
|
+
// Clear solver data
|
|
2294
|
+
this->invalidateSolverData();
|
|
2295
|
+
// Give the model a new name to avoid confusing logging when the
|
|
2296
|
+
// elastic LP is solved
|
|
2297
|
+
this->passModelName(original_model_name + "_elastic");
|
|
2298
|
+
// Zero the column costs
|
|
2299
|
+
std::vector<double> zero_costs;
|
|
2300
|
+
zero_costs.assign(original_num_col, 0);
|
|
2301
|
+
run_status = this->changeColsCost(0, lp.num_col_ - 1, zero_costs.data());
|
|
2302
|
+
assert(run_status == HighsStatus::kOk);
|
|
2303
|
+
|
|
2304
|
+
const bool mip_relaxation_iis =
|
|
2305
|
+
get_iis && lp.isMip() &&
|
|
2306
|
+
kIisStrategyRelaxation & this->options_.iis_strategy;
|
|
2307
|
+
if (mip_relaxation_iis) {
|
|
2308
|
+
// Set any integrality to continuous
|
|
2309
|
+
std::vector<HighsVarType> all_continuous;
|
|
2310
|
+
all_continuous.assign(original_num_col, HighsVarType::kContinuous);
|
|
2311
|
+
run_status =
|
|
2312
|
+
this->changeColsIntegrality(0, lp.num_col_ - 1, all_continuous.data());
|
|
2313
|
+
assert(run_status == HighsStatus::kOk);
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
// For the columns
|
|
2317
|
+
const bool has_local_lower_penalty = local_lower_penalty;
|
|
2318
|
+
const bool has_global_elastic_lower = global_lower_penalty >= 0;
|
|
2319
|
+
const bool has_elastic_lower =
|
|
2320
|
+
has_local_lower_penalty || has_global_elastic_lower;
|
|
2321
|
+
const bool has_local_upper_penalty = local_upper_penalty;
|
|
2322
|
+
const bool has_global_elastic_upper = global_upper_penalty >= 0;
|
|
2323
|
+
const bool has_elastic_upper =
|
|
2324
|
+
has_local_upper_penalty || has_global_elastic_upper;
|
|
2325
|
+
const bool has_elastic_columns = has_elastic_lower || has_elastic_upper;
|
|
2326
|
+
// For the rows
|
|
2327
|
+
const bool has_local_rhs_penalty = local_rhs_penalty;
|
|
2328
|
+
const bool has_global_elastic_rhs = global_rhs_penalty >= 0;
|
|
2329
|
+
const bool has_elastic_rows = has_local_rhs_penalty || has_global_elastic_rhs;
|
|
2330
|
+
assert(has_elastic_columns || has_elastic_rows);
|
|
2331
|
+
|
|
2332
|
+
const HighsInt col_ecol_offset = lp.num_col_;
|
|
2333
|
+
if (has_elastic_columns) {
|
|
2334
|
+
// Accumulate bounds to be used for columns
|
|
2335
|
+
std::vector<double> col_lower;
|
|
2336
|
+
std::vector<double> col_upper;
|
|
2337
|
+
// When defining names, need to know the column number
|
|
2338
|
+
const bool has_col_names = lp.col_names_.size() > 0;
|
|
2339
|
+
erow_start.push_back(0);
|
|
2340
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
2341
|
+
const double lower = lp.col_lower_[iCol];
|
|
2342
|
+
const double upper = lp.col_upper_[iCol];
|
|
2343
|
+
// Original bounds used unless e-variable introduced
|
|
2344
|
+
col_lower.push_back(lower);
|
|
2345
|
+
col_upper.push_back(upper);
|
|
2346
|
+
// Free columns have no erow
|
|
2347
|
+
if (lower <= -kHighsInf && upper >= kHighsInf) continue;
|
|
2348
|
+
|
|
2349
|
+
// Get the penalty for violating the lower bounds on this column
|
|
2350
|
+
const double lower_penalty = has_local_lower_penalty
|
|
2351
|
+
? local_lower_penalty[iCol]
|
|
2352
|
+
: global_lower_penalty;
|
|
2353
|
+
// Negative lower penalty and infinite upper bound implies that the
|
|
2354
|
+
// bounds cannot be violated
|
|
2355
|
+
if (lower_penalty < 0 && upper >= kHighsInf) continue;
|
|
2356
|
+
|
|
2357
|
+
// Get the penalty for violating the upper bounds on this column
|
|
2358
|
+
const double upper_penalty = has_local_upper_penalty
|
|
2359
|
+
? local_upper_penalty[iCol]
|
|
2360
|
+
: global_upper_penalty;
|
|
2361
|
+
// Infinite upper bound and negative lower penalty implies that the
|
|
2362
|
+
// bounds cannot be violated
|
|
2363
|
+
if (lower <= -kHighsInf && upper_penalty < 0) continue;
|
|
2364
|
+
erow_lower.push_back(lower);
|
|
2365
|
+
erow_upper.push_back(upper);
|
|
2366
|
+
if (has_col_names)
|
|
2367
|
+
erow_name.push_back("row_" + std::to_string(iCol) + "_" +
|
|
2368
|
+
lp.col_names_[iCol] + "_erow");
|
|
2369
|
+
// Define the entry for x[iCol]
|
|
2370
|
+
erow_index.push_back(iCol);
|
|
2371
|
+
erow_value.push_back(1);
|
|
2372
|
+
if (lower > -kHighsInf && lower_penalty >= 0) {
|
|
2373
|
+
// New e_l variable
|
|
2374
|
+
col_of_ecol.push_back(iCol);
|
|
2375
|
+
if (has_col_names)
|
|
2376
|
+
ecol_name.push_back("col_" + std::to_string(iCol) + "_" +
|
|
2377
|
+
lp.col_names_[iCol] + "_lower");
|
|
2378
|
+
// Save the original lower bound on this column and free its
|
|
2379
|
+
// lower bound
|
|
2380
|
+
bound_of_col_of_ecol_is_lower.push_back(true);
|
|
2381
|
+
col_lower[iCol] = -kHighsInf;
|
|
2382
|
+
erow_index.push_back(evar_ix);
|
|
2383
|
+
erow_value.push_back(1);
|
|
2384
|
+
ecol_cost.push_back(lower_penalty);
|
|
2385
|
+
evar_ix++;
|
|
2386
|
+
}
|
|
2387
|
+
if (upper < kHighsInf && upper_penalty >= 0) {
|
|
2388
|
+
// New e_u variable
|
|
2389
|
+
col_of_ecol.push_back(iCol);
|
|
2390
|
+
if (has_col_names)
|
|
2391
|
+
ecol_name.push_back("col_" + std::to_string(iCol) + "_" +
|
|
2392
|
+
lp.col_names_[iCol] + "_upper");
|
|
2393
|
+
// Save the original upper bound on this column and free its
|
|
2394
|
+
// upper bound
|
|
2395
|
+
bound_of_col_of_ecol_is_lower.push_back(false);
|
|
2396
|
+
col_upper[iCol] = kHighsInf;
|
|
2397
|
+
erow_index.push_back(evar_ix);
|
|
2398
|
+
erow_value.push_back(-1);
|
|
2399
|
+
ecol_cost.push_back(upper_penalty);
|
|
2400
|
+
evar_ix++;
|
|
2401
|
+
}
|
|
2402
|
+
erow_start.push_back(erow_index.size());
|
|
2403
|
+
HighsInt row_nz =
|
|
2404
|
+
erow_start[erow_start.size() - 1] - erow_start[erow_start.size() - 2];
|
|
2405
|
+
// printf("eRow for column %d has %d nonzeros\n", int(iCol),
|
|
2406
|
+
// int(row_nz));
|
|
2407
|
+
assert(row_nz == 2 || row_nz == 3);
|
|
2408
|
+
}
|
|
2409
|
+
HighsInt num_new_col = col_of_ecol.size();
|
|
2410
|
+
HighsInt num_new_row = erow_start.size() - 1;
|
|
2411
|
+
HighsInt num_new_nz = erow_start[num_new_row];
|
|
2412
|
+
if (kIisDevReport)
|
|
2413
|
+
printf(
|
|
2414
|
+
"Elasticity filter: For columns there are %d variables and %d "
|
|
2415
|
+
"constraints\n",
|
|
2416
|
+
int(num_new_col), int(num_new_row));
|
|
2417
|
+
// Apply the original column bound changes
|
|
2418
|
+
assert(col_lower.size() == static_cast<size_t>(lp.num_col_));
|
|
2419
|
+
assert(col_upper.size() == static_cast<size_t>(lp.num_col_));
|
|
2420
|
+
run_status = this->changeColsBounds(0, lp.num_col_ - 1, col_lower.data(),
|
|
2421
|
+
col_upper.data());
|
|
2422
|
+
assert(run_status == HighsStatus::kOk);
|
|
2423
|
+
// Add the new columns
|
|
2424
|
+
ecol_lower.assign(num_new_col, 0);
|
|
2425
|
+
ecol_upper.assign(num_new_col, kHighsInf);
|
|
2426
|
+
run_status = this->addCols(num_new_col, ecol_cost.data(), ecol_lower.data(),
|
|
2427
|
+
ecol_upper.data(), 0, nullptr, nullptr, nullptr);
|
|
2428
|
+
assert(run_status == HighsStatus::kOk);
|
|
2429
|
+
// Add the new rows
|
|
2430
|
+
assert(erow_start.size() == static_cast<size_t>(num_new_row + 1));
|
|
2431
|
+
assert(erow_index.size() == static_cast<size_t>(num_new_nz));
|
|
2432
|
+
assert(erow_value.size() == static_cast<size_t>(num_new_nz));
|
|
2433
|
+
run_status = this->addRows(num_new_row, erow_lower.data(),
|
|
2434
|
+
erow_upper.data(), num_new_nz, erow_start.data(),
|
|
2435
|
+
erow_index.data(), erow_value.data());
|
|
2436
|
+
assert(run_status == HighsStatus::kOk);
|
|
2437
|
+
if (has_col_names) {
|
|
2438
|
+
for (HighsInt iCol = 0; iCol < num_new_col; iCol++)
|
|
2439
|
+
this->passColName(col_ecol_offset + iCol, ecol_name[iCol]);
|
|
2440
|
+
for (HighsInt iRow = 0; iRow < num_new_row; iRow++)
|
|
2441
|
+
this->passRowName(original_num_row + iRow, erow_name[iRow]);
|
|
2442
|
+
}
|
|
2443
|
+
assert(ecol_cost.size() == static_cast<size_t>(num_new_col));
|
|
2444
|
+
assert(ecol_lower.size() == static_cast<size_t>(num_new_col));
|
|
2445
|
+
assert(ecol_upper.size() == static_cast<size_t>(num_new_col));
|
|
2446
|
+
if (write_model) {
|
|
2447
|
+
printf("\nAfter adding %d e-rows\n=============\n", int(num_new_col));
|
|
2448
|
+
bool output_flag;
|
|
2449
|
+
run_status = this->getOptionValue("output_flag", output_flag);
|
|
2450
|
+
this->setOptionValue("output_flag", true);
|
|
2451
|
+
this->writeModel("");
|
|
2452
|
+
this->setOptionValue("output_flag", output_flag);
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
const HighsInt row_ecol_offset = lp.num_col_;
|
|
2456
|
+
if (has_elastic_rows) {
|
|
2457
|
+
// Add the columns corresponding to the e_L and e_U variables for
|
|
2458
|
+
// the constraints
|
|
2459
|
+
ecol_name.clear();
|
|
2460
|
+
ecol_cost.clear();
|
|
2461
|
+
std::vector<HighsInt> ecol_start;
|
|
2462
|
+
std::vector<HighsInt> ecol_index;
|
|
2463
|
+
std::vector<double> ecol_value;
|
|
2464
|
+
ecol_start.push_back(0);
|
|
2465
|
+
const bool has_row_names = lp.row_names_.size() > 0;
|
|
2466
|
+
for (HighsInt iRow = 0; iRow < original_num_row; iRow++) {
|
|
2467
|
+
// Get the penalty for violating the bounds on this row
|
|
2468
|
+
const double penalty =
|
|
2469
|
+
has_local_rhs_penalty ? local_rhs_penalty[iRow] : global_rhs_penalty;
|
|
2470
|
+
// Negative penalty implies that the bounds cannot be violated
|
|
2471
|
+
if (penalty < 0) continue;
|
|
2472
|
+
const double lower = lp.row_lower_[iRow];
|
|
2473
|
+
const double upper = lp.row_upper_[iRow];
|
|
2474
|
+
if (lower > -kHighsInf) {
|
|
2475
|
+
// Create an e-var for the row lower bound
|
|
2476
|
+
row_of_ecol.push_back(iRow);
|
|
2477
|
+
if (has_row_names)
|
|
2478
|
+
ecol_name.push_back("row_" + std::to_string(iRow) + "_" +
|
|
2479
|
+
lp.row_names_[iRow] + "_lower");
|
|
2480
|
+
bound_of_row_of_ecol_is_lower.push_back(true);
|
|
2481
|
+
// Define the sub-matrix column
|
|
2482
|
+
ecol_index.push_back(iRow);
|
|
2483
|
+
ecol_value.push_back(1);
|
|
2484
|
+
ecol_start.push_back(ecol_index.size());
|
|
2485
|
+
ecol_cost.push_back(penalty);
|
|
2486
|
+
evar_ix++;
|
|
2487
|
+
}
|
|
2488
|
+
if (upper < kHighsInf) {
|
|
2489
|
+
// Create an e-var for the row upper bound
|
|
2490
|
+
row_of_ecol.push_back(iRow);
|
|
2491
|
+
if (has_row_names)
|
|
2492
|
+
ecol_name.push_back("row_" + std::to_string(iRow) + "_" +
|
|
2493
|
+
lp.row_names_[iRow] + "_upper");
|
|
2494
|
+
bound_of_row_of_ecol_is_lower.push_back(false);
|
|
2495
|
+
// Define the sub-matrix column
|
|
2496
|
+
ecol_index.push_back(iRow);
|
|
2497
|
+
ecol_value.push_back(-1);
|
|
2498
|
+
ecol_start.push_back(ecol_index.size());
|
|
2499
|
+
ecol_cost.push_back(penalty);
|
|
2500
|
+
evar_ix++;
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
HighsInt num_new_col = ecol_start.size() - 1;
|
|
2504
|
+
HighsInt num_new_nz = ecol_start[num_new_col];
|
|
2505
|
+
ecol_lower.assign(num_new_col, 0);
|
|
2506
|
+
ecol_upper.assign(num_new_col, kHighsInf);
|
|
2507
|
+
assert(ecol_cost.size() == static_cast<size_t>(num_new_col));
|
|
2508
|
+
assert(ecol_lower.size() == static_cast<size_t>(num_new_col));
|
|
2509
|
+
assert(ecol_upper.size() == static_cast<size_t>(num_new_col));
|
|
2510
|
+
assert(ecol_start.size() == static_cast<size_t>(num_new_col + 1));
|
|
2511
|
+
assert(ecol_index.size() == static_cast<size_t>(num_new_nz));
|
|
2512
|
+
assert(ecol_value.size() == static_cast<size_t>(num_new_nz));
|
|
2513
|
+
run_status = this->addCols(num_new_col, ecol_cost.data(), ecol_lower.data(),
|
|
2514
|
+
ecol_upper.data(), num_new_nz, ecol_start.data(),
|
|
2515
|
+
ecol_index.data(), ecol_value.data());
|
|
2516
|
+
assert(run_status == HighsStatus::kOk);
|
|
2517
|
+
if (has_row_names) {
|
|
2518
|
+
for (HighsInt iCol = 0; iCol < num_new_col; iCol++)
|
|
2519
|
+
this->passColName(row_ecol_offset + iCol, ecol_name[iCol]);
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
if (write_model) {
|
|
2523
|
+
bool output_flag;
|
|
2524
|
+
printf("\nAfter adding %d e-cols\n=============\n", int(num_new_col));
|
|
2525
|
+
run_status = this->getOptionValue("output_flag", output_flag);
|
|
2526
|
+
this->setOptionValue("output_flag", true);
|
|
2527
|
+
this->writeModel("");
|
|
2528
|
+
this->setOptionValue("output_flag", output_flag);
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
|
|
2532
|
+
if (write_model) this->writeModel("elastic.mps");
|
|
2533
|
+
// Initial logging
|
|
2534
|
+
if (get_iis)
|
|
2535
|
+
highsLogUser(
|
|
2536
|
+
options_.log_options, HighsLogType::kInfo,
|
|
2537
|
+
"Running elasticity filter to identify an infeasible subset of rows\n");
|
|
2538
|
+
|
|
2539
|
+
// Working with a copy of the IIS so clear this->iis_
|
|
2540
|
+
this->iis_.clear();
|
|
2541
|
+
// Lambda for gathering data when solving an LP
|
|
2542
|
+
auto solveLp = [&]() -> HighsStatus {
|
|
2543
|
+
bool output_flag = options_.output_flag;
|
|
2544
|
+
options_.output_flag = false;
|
|
2545
|
+
double simplex_time = -this->getRunTime();
|
|
2546
|
+
HighsInt simplex_iterations = -info_.simplex_iteration_count;
|
|
2547
|
+
run_status = this->optimizeModel();
|
|
2548
|
+
simplex_time += this->getRunTime();
|
|
2549
|
+
simplex_iterations += info_.simplex_iteration_count;
|
|
2550
|
+
iis.info_.update(simplex_time, simplex_iterations);
|
|
2551
|
+
options_.output_flag = output_flag;
|
|
2552
|
+
return run_status;
|
|
2553
|
+
};
|
|
2554
|
+
|
|
2555
|
+
// Solve the elastic LP
|
|
2556
|
+
run_status = solveLp();
|
|
2557
|
+
if (run_status != HighsStatus::kOk) {
|
|
2558
|
+
// Failed to establish feasibility or infeasibility due to unknown error
|
|
2559
|
+
// or hitting a time limit
|
|
2560
|
+
if (this->model_status_ == HighsModelStatus::kTimeLimit) {
|
|
2561
|
+
iis.status_ = kIisModelStatusTimeLimit;
|
|
2562
|
+
if (get_iis)
|
|
2563
|
+
highsLogUser(
|
|
2564
|
+
options_.log_options, HighsLogType::kError,
|
|
2565
|
+
"Elasticity filter failed because time limit was reached\n");
|
|
2566
|
+
} else {
|
|
2567
|
+
iis.status_ = kIisModelStatusUnknown;
|
|
2568
|
+
if (get_iis)
|
|
2569
|
+
highsLogUser(options_.log_options, HighsLogType::kError,
|
|
2570
|
+
"Elasticity filter failed because it encountered an "
|
|
2571
|
+
"unknown model status\n");
|
|
2572
|
+
}
|
|
2573
|
+
iis.valid_ = false;
|
|
2574
|
+
this->iis_ = iis;
|
|
2575
|
+
return elasticityFilterReturn(
|
|
2576
|
+
HighsStatus::kError, original_model_name, original_model_status,
|
|
2577
|
+
original_num_col, original_num_row, original_col_cost,
|
|
2578
|
+
original_col_lower, original_col_upper, original_integrality);
|
|
2579
|
+
}
|
|
2580
|
+
if (kIisDevReport) this->writeSolution("", kSolutionStylePretty);
|
|
2581
|
+
// Model status should be optimal, unless model is unbounded
|
|
2582
|
+
assert(this->model_status_ == HighsModelStatus::kOptimal ||
|
|
2583
|
+
this->model_status_ == HighsModelStatus::kUnbounded);
|
|
2584
|
+
iis.valid_ = true;
|
|
2585
|
+
iis.status_ = this->info_.objective_function_value > 0
|
|
2586
|
+
? kIisModelStatusReducible
|
|
2587
|
+
: kIisModelStatusFeasible;
|
|
2588
|
+
if (!get_iis) {
|
|
2589
|
+
this->iis_ = iis;
|
|
2590
|
+
return elasticityFilterReturn(
|
|
2591
|
+
HighsStatus::kOk, original_model_name, original_model_status,
|
|
2592
|
+
original_num_col, original_num_row, original_col_cost,
|
|
2593
|
+
original_col_lower, original_col_upper, original_integrality);
|
|
2594
|
+
}
|
|
2595
|
+
// If getting an (I)IS, assume no elastic columns, so no additional rows
|
|
2596
|
+
assert(!has_elastic_columns);
|
|
2597
|
+
assert(has_elastic_rows);
|
|
2598
|
+
assert(original_num_row == lp.num_row_);
|
|
2599
|
+
|
|
2600
|
+
// Get solution
|
|
2601
|
+
const HighsSolution& solution = this->getSolution();
|
|
2602
|
+
// Now fix e-variables that are positive and re-solve until e-LP is
|
|
2603
|
+
// infeasible
|
|
2604
|
+
HighsInt loop_k = 0;
|
|
2605
|
+
std::unordered_set<HighsInt> row_set;
|
|
2606
|
+
|
|
2607
|
+
for (;;) {
|
|
2608
|
+
if (kIisDevReport)
|
|
2609
|
+
printf("\nElasticity filter pass %d\n==============\n", int(loop_k));
|
|
2610
|
+
HighsInt num_fixed = 0;
|
|
2611
|
+
if (has_elastic_columns) {
|
|
2612
|
+
for (size_t eCol = 0; eCol < col_of_ecol.size(); eCol++) {
|
|
2613
|
+
HighsInt iCol = col_of_ecol[eCol];
|
|
2614
|
+
if (solution.col_value[col_ecol_offset + eCol] >
|
|
2615
|
+
this->options_.primal_feasibility_tolerance) {
|
|
2616
|
+
if (kIisDevReport)
|
|
2617
|
+
printf(
|
|
2618
|
+
"E-col %2d (column %2d) corresponds to column %2d with %s "
|
|
2619
|
+
"bound "
|
|
2620
|
+
"%11.4g "
|
|
2621
|
+
"and has solution value %11.4g\n",
|
|
2622
|
+
int(eCol), int(col_ecol_offset + eCol), int(iCol),
|
|
2623
|
+
bound_of_col_of_ecol_is_lower[eCol] ? "lower" : "upper",
|
|
2624
|
+
bound_of_col_of_ecol_is_lower[eCol] ? lp.col_lower_[iCol]
|
|
2625
|
+
: lp.col_upper_[iCol],
|
|
2626
|
+
solution.col_value[col_ecol_offset + eCol]);
|
|
2627
|
+
this->changeColBounds(col_ecol_offset + eCol, 0, 0);
|
|
2628
|
+
num_fixed++;
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
if (has_elastic_rows) {
|
|
2633
|
+
for (size_t eCol = 0; eCol < row_of_ecol.size(); eCol++) {
|
|
2634
|
+
HighsInt iRow = row_of_ecol[eCol];
|
|
2635
|
+
if (solution.col_value[row_ecol_offset + eCol] >
|
|
2636
|
+
this->options_.primal_feasibility_tolerance) {
|
|
2637
|
+
if (kIisDevReport)
|
|
2638
|
+
printf(
|
|
2639
|
+
"E-row %2d (column %2d) corresponds to row %2d with %s "
|
|
2640
|
+
"bound "
|
|
2641
|
+
"%11.4g "
|
|
2642
|
+
"and has solution value %11.4g\n",
|
|
2643
|
+
int(eCol), int(row_ecol_offset + eCol), int(iRow),
|
|
2644
|
+
bound_of_row_of_ecol_is_lower[eCol] ? "lower" : "upper",
|
|
2645
|
+
bound_of_row_of_ecol_is_lower[eCol] ? lp.row_lower_[iRow]
|
|
2646
|
+
: lp.row_upper_[iRow],
|
|
2647
|
+
solution.col_value[row_ecol_offset + eCol]);
|
|
2648
|
+
this->changeColBounds(row_ecol_offset + eCol, 0, 0);
|
|
2649
|
+
num_fixed++;
|
|
2650
|
+
row_set.insert(iRow);
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
// Report on iteration
|
|
2655
|
+
bool force = loop_k == 0;
|
|
2656
|
+
iis.reportIteration(options_, loop_k + 1, HighsInt(row_set.size()), force);
|
|
2657
|
+
|
|
2658
|
+
if (num_fixed == 0) {
|
|
2659
|
+
// No elastic variables were positive, so problem is feasible
|
|
2660
|
+
iis.status_ = kIisModelStatusFeasible;
|
|
2661
|
+
break;
|
|
2662
|
+
}
|
|
2663
|
+
HighsStatus run_status = solveLp();
|
|
2664
|
+
if (run_status != HighsStatus::kOk) {
|
|
2665
|
+
// Solve failed
|
|
2666
|
+
if (this->model_status_ == HighsModelStatus::kTimeLimit) {
|
|
2667
|
+
iis.status_ = kIisModelStatusTimeLimit;
|
|
2668
|
+
|
|
2669
|
+
highsLogUser(
|
|
2670
|
+
options_.log_options, HighsLogType::kError,
|
|
2671
|
+
"Elasticity filter failed because time limit was reached\n");
|
|
2672
|
+
} else {
|
|
2673
|
+
iis.status_ = kIisModelStatusUnknown;
|
|
2674
|
+
|
|
2675
|
+
highsLogUser(options_.log_options, HighsLogType::kError,
|
|
2676
|
+
"Elasticity filter failed because it encountered an "
|
|
2677
|
+
"unknown model status\n");
|
|
2678
|
+
}
|
|
2679
|
+
iis.valid_ = false;
|
|
2680
|
+
this->iis_ = iis;
|
|
2681
|
+
return elasticityFilterReturn(
|
|
2682
|
+
HighsStatus::kError, original_model_name, original_model_status,
|
|
2683
|
+
original_num_col, original_num_row, original_col_cost,
|
|
2684
|
+
original_col_lower, original_col_upper, original_integrality);
|
|
2685
|
+
}
|
|
2686
|
+
if (kIisDevReport) this->writeSolution("", kSolutionStylePretty);
|
|
2687
|
+
HighsModelStatus model_status = this->getModelStatus();
|
|
2688
|
+
if (model_status == HighsModelStatus::kInfeasible) break;
|
|
2689
|
+
loop_k++;
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2692
|
+
// Final report
|
|
2693
|
+
iis.reportIteration(options_, loop_k + 1, HighsInt(row_set.size()), true);
|
|
2694
|
+
|
|
2695
|
+
HighsInt num_enforced_col_ecol = 0;
|
|
2696
|
+
HighsInt num_enforced_row_ecol = 0;
|
|
2697
|
+
if (has_elastic_columns) {
|
|
2698
|
+
for (size_t eCol = 0; eCol < col_of_ecol.size(); eCol++) {
|
|
2699
|
+
HighsInt iCol = col_of_ecol[eCol];
|
|
2700
|
+
if (lp.col_upper_[col_ecol_offset + eCol] == 0) {
|
|
2701
|
+
num_enforced_col_ecol++;
|
|
2702
|
+
if (kIisDevReport)
|
|
2703
|
+
printf(
|
|
2704
|
+
"Col e-col %2d (column %2d) corresponds to column %2d with %s "
|
|
2705
|
+
"bound "
|
|
2706
|
+
"%11.4g "
|
|
2707
|
+
"and is enforced\n",
|
|
2708
|
+
int(eCol), int(col_ecol_offset + eCol), int(iCol),
|
|
2709
|
+
bound_of_col_of_ecol_is_lower[eCol] ? "lower" : "upper",
|
|
2710
|
+
bound_of_col_of_ecol_is_lower[eCol] ? lp.col_lower_[iCol]
|
|
2711
|
+
: lp.col_upper_[iCol]);
|
|
2712
|
+
}
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
if (has_elastic_rows) {
|
|
2716
|
+
for (size_t eCol = 0; eCol < row_of_ecol.size(); eCol++) {
|
|
2717
|
+
HighsInt iRow = row_of_ecol[eCol];
|
|
2718
|
+
if (lp.col_upper_[row_ecol_offset + eCol] == 0) {
|
|
2719
|
+
num_enforced_row_ecol++;
|
|
2720
|
+
if (iis.row_index_.empty() || iis.row_index_.back() != iRow)
|
|
2721
|
+
iis.row_index_.push_back(iRow);
|
|
2722
|
+
|
|
2723
|
+
/*
|
|
2724
|
+
iis.row_bound_.push_back(erow_value[eRow] > 0 ?
|
|
2725
|
+
kIisBoundStatusUpper :
|
|
2726
|
+
kIisBoundStatusLower);
|
|
2727
|
+
*/
|
|
2728
|
+
if (kIisDevReport)
|
|
2729
|
+
printf(
|
|
2730
|
+
"Row e-col %2d (column %2d) corresponds to row %2d with %s "
|
|
2731
|
+
"bound "
|
|
2732
|
+
"%11.4g and is enforced\n",
|
|
2733
|
+
int(eCol), int(row_ecol_offset + eCol), int(iRow),
|
|
2734
|
+
bound_of_row_of_ecol_is_lower[eCol] ? "lower" : "upper",
|
|
2735
|
+
bound_of_row_of_ecol_is_lower[eCol] ? lp.row_lower_[iRow]
|
|
2736
|
+
: lp.row_upper_[iRow]);
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
HighsInt num_iis_row = iis.row_index_.size();
|
|
2741
|
+
if (iis.status_ == kIisModelStatusFeasible) {
|
|
2742
|
+
assert(num_enforced_col_ecol == 0 && num_enforced_row_ecol == 0);
|
|
2743
|
+
assert(num_iis_row == 0);
|
|
2744
|
+
}
|
|
2745
|
+
|
|
2746
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
2747
|
+
"Elasticity filter after %d passes found an infeasible subset "
|
|
2748
|
+
"of %d rows\n",
|
|
2749
|
+
int(loop_k + 1), row_set.size());
|
|
2750
|
+
|
|
2751
|
+
iis.valid_ = true;
|
|
2752
|
+
iis.strategy_ = this->options_.iis_strategy;
|
|
2753
|
+
if (iis.status_ == kIisModelStatusFeasible) {
|
|
2754
|
+
this->iis_ = iis;
|
|
2755
|
+
return elasticityFilterReturn(
|
|
2756
|
+
HighsStatus::kOk, original_model_name, original_model_status,
|
|
2757
|
+
original_num_col, original_num_row, original_col_cost,
|
|
2758
|
+
original_col_lower, original_col_upper, original_integrality);
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2761
|
+
// Model is infeasible because there are (at least) a positive
|
|
2762
|
+
// number of rows in the infeasibility set. Hence the IIS status is
|
|
2763
|
+
// reducible
|
|
2764
|
+
assert(iis.status_ == kIisModelStatusReducible);
|
|
2765
|
+
assert(num_iis_row > 0);
|
|
2766
|
+
|
|
2767
|
+
// Have to be able to map from original row indices to position in
|
|
2768
|
+
// iis.row_index_
|
|
2769
|
+
std::vector<HighsInt> in_row_index(original_num_row, -1);
|
|
2770
|
+
for (HighsInt iX = 0; iX < num_iis_row; iX++)
|
|
2771
|
+
in_row_index[iis.row_index_[iX]] = iX;
|
|
2772
|
+
|
|
2773
|
+
// Determine the columns with nonzeros in the row subset
|
|
2774
|
+
std::vector<bool> nonzero_in_row_index(original_num_col, false);
|
|
2775
|
+
if (lp.a_matrix_.isColwise()) {
|
|
2776
|
+
for (HighsInt iCol = 0; iCol < original_num_col; iCol++) {
|
|
2777
|
+
for (HighsInt iEl = lp.a_matrix_.start_[iCol];
|
|
2778
|
+
iEl < lp.a_matrix_.start_[iCol + 1]; iEl++)
|
|
2779
|
+
if (in_row_index[lp.a_matrix_.index_[iEl]] >= 0)
|
|
2780
|
+
nonzero_in_row_index[iCol] = true;
|
|
2781
|
+
}
|
|
2782
|
+
} else {
|
|
2783
|
+
for (HighsInt iX = 0; iX < num_iis_row; iX++) {
|
|
2784
|
+
HighsInt iRow = iis.row_index_[iX];
|
|
2785
|
+
for (HighsInt iEl = lp.a_matrix_.start_[iRow];
|
|
2786
|
+
iEl < lp.a_matrix_.start_[iRow + 1]; iEl++)
|
|
2787
|
+
nonzero_in_row_index[lp.a_matrix_.index_[iEl]] = true;
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
// Now form iis.col_index_ and iis.col_bound_
|
|
2791
|
+
assert(iis.col_index_.size() == 0);
|
|
2792
|
+
for (HighsInt iCol = 0; iCol < original_num_col; iCol++) {
|
|
2793
|
+
if (nonzero_in_row_index[iCol]) {
|
|
2794
|
+
iis.col_index_.push_back(iCol);
|
|
2795
|
+
if (lp.col_lower_[iCol] > -kHighsInf) {
|
|
2796
|
+
if (lp.col_upper_[iCol] < kHighsInf) {
|
|
2797
|
+
// Boxed
|
|
2798
|
+
iis.col_bound_.push_back(kIisBoundStatusBoxed);
|
|
2799
|
+
} else {
|
|
2800
|
+
// LB
|
|
2801
|
+
iis.col_bound_.push_back(kIisBoundStatusLower);
|
|
2802
|
+
}
|
|
2803
|
+
} else {
|
|
2804
|
+
if (lp.col_upper_[iCol] < kHighsInf) {
|
|
2805
|
+
// UB
|
|
2806
|
+
iis.col_bound_.push_back(kIisBoundStatusUpper);
|
|
2807
|
+
} else {
|
|
2808
|
+
// Free
|
|
2809
|
+
iis.col_bound_.push_back(kIisBoundStatusFree);
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
// Now, go through the elastic columns for the rows, identifying the bound
|
|
2815
|
+
// that is required
|
|
2816
|
+
iis.row_bound_.assign(num_iis_row, -1);
|
|
2817
|
+
for (size_t eCol = 0; eCol < row_of_ecol.size(); eCol++) {
|
|
2818
|
+
HighsInt iRow = row_of_ecol[eCol];
|
|
2819
|
+
if (lp.col_upper_[row_ecol_offset + eCol] == 0) {
|
|
2820
|
+
HighsInt iX = in_row_index[iRow];
|
|
2821
|
+
if (iis.row_bound_[iX] == -1) {
|
|
2822
|
+
// Unassigned
|
|
2823
|
+
iis.row_bound_[iX] = bound_of_row_of_ecol_is_lower[eCol]
|
|
2824
|
+
? kIisBoundStatusLower
|
|
2825
|
+
: kIisBoundStatusUpper;
|
|
2826
|
+
} else {
|
|
2827
|
+
// Mark row as boxed when encountered twice, indicating both elastic
|
|
2828
|
+
// variables were enforced
|
|
2829
|
+
iis.row_bound_[iX] = kIisBoundStatusBoxed;
|
|
2830
|
+
}
|
|
2831
|
+
}
|
|
2832
|
+
}
|
|
2833
|
+
assert(iis.row_bound_.size() == iis.row_index_.size());
|
|
2834
|
+
for (HighsInt iX = 0; iX < num_iis_row; iX++) assert(iis.row_bound_[iX] >= 0);
|
|
2835
|
+
this->iis_ = iis;
|
|
2836
|
+
return elasticityFilterReturn(
|
|
2837
|
+
HighsStatus::kOk, original_model_name, original_model_status,
|
|
2838
|
+
original_num_col, original_num_row, original_col_cost, original_col_lower,
|
|
2839
|
+
original_col_upper, original_integrality);
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2842
|
+
HighsStatus Highs::extractIis(HighsInt& num_iis_col, HighsInt& num_iis_row,
|
|
2843
|
+
HighsInt* iis_col_index, HighsInt* iis_row_index,
|
|
2844
|
+
HighsInt* iis_col_bound,
|
|
2845
|
+
HighsInt* iis_row_bound) {
|
|
2846
|
+
assert(this->iis_.valid_);
|
|
2847
|
+
num_iis_col = this->iis_.col_index_.size();
|
|
2848
|
+
num_iis_row = this->iis_.row_index_.size();
|
|
2849
|
+
if (iis_col_index || iis_col_bound) {
|
|
2850
|
+
for (HighsInt iCol = 0; iCol < num_iis_col; iCol++) {
|
|
2851
|
+
if (iis_col_index) iis_col_index[iCol] = this->iis_.col_index_[iCol];
|
|
2852
|
+
if (iis_col_bound) iis_col_bound[iCol] = this->iis_.col_bound_[iCol];
|
|
2853
|
+
}
|
|
2854
|
+
}
|
|
2855
|
+
if (iis_row_index || iis_row_bound) {
|
|
2856
|
+
for (HighsInt iRow = 0; iRow < num_iis_row; iRow++) {
|
|
2857
|
+
if (iis_row_index) iis_row_index[iRow] = this->iis_.row_index_[iRow];
|
|
2858
|
+
if (iis_row_bound) iis_row_bound[iRow] = this->iis_.row_bound_[iRow];
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
return HighsStatus::kOk;
|
|
2862
|
+
}
|
|
2863
|
+
|
|
2864
|
+
bool Highs::aFormatOk(const HighsInt num_nz, const HighsInt format) {
|
|
2865
|
+
if (!num_nz) return true;
|
|
2866
|
+
const bool ok_format = format == (HighsInt)MatrixFormat::kColwise ||
|
|
2867
|
+
format == (HighsInt)MatrixFormat::kRowwise;
|
|
2868
|
+
assert(ok_format);
|
|
2869
|
+
if (!ok_format)
|
|
2870
|
+
highsLogUser(
|
|
2871
|
+
options_.log_options, HighsLogType::kError,
|
|
2872
|
+
"Non-empty Constraint matrix has illegal format = %" HIGHSINT_FORMAT
|
|
2873
|
+
"\n",
|
|
2874
|
+
format);
|
|
2875
|
+
return ok_format;
|
|
2876
|
+
}
|
|
2877
|
+
|
|
2878
|
+
bool Highs::qFormatOk(const HighsInt num_nz, const HighsInt format) {
|
|
2879
|
+
if (!num_nz) return true;
|
|
2880
|
+
const bool ok_format = format == (HighsInt)HessianFormat::kTriangular;
|
|
2881
|
+
assert(ok_format);
|
|
2882
|
+
if (!ok_format)
|
|
2883
|
+
highsLogUser(
|
|
2884
|
+
options_.log_options, HighsLogType::kError,
|
|
2885
|
+
"Non-empty Hessian matrix has illegal format = %" HIGHSINT_FORMAT "\n",
|
|
2886
|
+
format);
|
|
2887
|
+
return ok_format;
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2890
|
+
void Highs::clearZeroHessian() {
|
|
2891
|
+
HighsHessian& hessian = model_.hessian_;
|
|
2892
|
+
if (hessian.dim_) {
|
|
2893
|
+
// Clear any zero Hessian
|
|
2894
|
+
if (hessian.numNz() == 0) {
|
|
2895
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
2896
|
+
"Hessian has dimension %" HIGHSINT_FORMAT
|
|
2897
|
+
" but no nonzeros, so is ignored\n",
|
|
2898
|
+
hessian.dim_);
|
|
2899
|
+
hessian.clear();
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
|
|
2904
|
+
HighsStatus Highs::checkOptimality(const std::string& solver_type) {
|
|
2905
|
+
// Check for infeasibility measures incompatible with optimality
|
|
2906
|
+
assert(model_status_ == HighsModelStatus::kOptimal);
|
|
2907
|
+
// Cannot expect to have no dual_infeasibilities since the QP solver
|
|
2908
|
+
// (and, of course, the MIP solver) give no dual information
|
|
2909
|
+
if (info_.num_primal_infeasibilities == 0 &&
|
|
2910
|
+
info_.num_dual_infeasibilities <= 0)
|
|
2911
|
+
return HighsStatus::kOk;
|
|
2912
|
+
model_status_ = HighsModelStatus::kSolveError;
|
|
2913
|
+
std::stringstream ss;
|
|
2914
|
+
ss.str(std::string());
|
|
2915
|
+
ss << highsFormatToString(
|
|
2916
|
+
"%s solver claims optimality, but with num/max/sum "
|
|
2917
|
+
"primal(%d/%g/%g)",
|
|
2918
|
+
solver_type.c_str(), int(info_.num_primal_infeasibilities),
|
|
2919
|
+
info_.max_primal_infeasibility, info_.sum_primal_infeasibilities);
|
|
2920
|
+
if (info_.num_dual_infeasibilities > 0)
|
|
2921
|
+
ss << highsFormatToString(
|
|
2922
|
+
"and dual(%d/%g/%g)", int(info_.num_dual_infeasibilities),
|
|
2923
|
+
info_.max_dual_infeasibility, info_.sum_dual_infeasibilities);
|
|
2924
|
+
ss << " infeasibilities\n";
|
|
2925
|
+
const std::string report_string = ss.str();
|
|
2926
|
+
highsLogUser(options_.log_options, HighsLogType::kError, "%s",
|
|
2927
|
+
report_string.c_str());
|
|
2928
|
+
highsLogUser(options_.log_options, HighsLogType::kError,
|
|
2929
|
+
"Setting model status to %s\n",
|
|
2930
|
+
modelStatusToString(model_status_).c_str());
|
|
2931
|
+
return HighsStatus::kError;
|
|
2932
|
+
}
|
|
2933
|
+
|
|
2934
|
+
void Highs::callLpKktCheck(const HighsLp& lp, const std::string& message) {
|
|
2935
|
+
lpKktCheck(this->model_status_, this->info_, lp, this->solution_,
|
|
2936
|
+
this->basis_, this->options_, message);
|
|
2937
|
+
}
|
|
2938
|
+
|
|
2939
|
+
HighsStatus Highs::invertRequirementError(std::string method_name) const {
|
|
2940
|
+
assert(!ekk_instance_.status_.has_invert);
|
|
2941
|
+
highsLogUser(options_.log_options, HighsLogType::kError,
|
|
2942
|
+
"No invertible representation for %s\n", method_name.c_str());
|
|
2943
|
+
return HighsStatus::kError;
|
|
2944
|
+
}
|
|
2945
|
+
|
|
2946
|
+
HighsStatus Highs::handleInfCost() {
|
|
2947
|
+
HighsLp& lp = this->model_.lp_;
|
|
2948
|
+
if (!lp.has_infinite_cost_) return HighsStatus::kOk;
|
|
2949
|
+
HighsLpMods& mods = lp.mods_;
|
|
2950
|
+
double inf_cost = this->options_.infinite_cost;
|
|
2951
|
+
for (HighsInt k = 0; k < 2; k++) {
|
|
2952
|
+
// Pass twice: first checking that infinite costs can be handled,
|
|
2953
|
+
// then handling them, so that model is unmodified if infinite
|
|
2954
|
+
// costs cannot be handled
|
|
2955
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
2956
|
+
double cost = lp.col_cost_[iCol];
|
|
2957
|
+
if (cost > -inf_cost && cost < inf_cost) continue;
|
|
2958
|
+
double lower = lp.col_lower_[iCol];
|
|
2959
|
+
double upper = lp.col_upper_[iCol];
|
|
2960
|
+
if (lp.isMip()) {
|
|
2961
|
+
if (lp.integrality_[iCol] == HighsVarType::kInteger) {
|
|
2962
|
+
lower = std::ceil(lower);
|
|
2963
|
+
upper = std::floor(upper);
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
if (cost <= -inf_cost) {
|
|
2967
|
+
if (lp.sense_ == ObjSense::kMinimize) {
|
|
2968
|
+
// Minimizing with -inf cost so try to fix at upper bound
|
|
2969
|
+
if (upper < kHighsInf) {
|
|
2970
|
+
if (k) lp.col_lower_[iCol] = upper;
|
|
2971
|
+
} else {
|
|
2972
|
+
highsLogUser(options_.log_options, HighsLogType::kError,
|
|
2973
|
+
"Cannot minimize with a cost on variable %d of %g and "
|
|
2974
|
+
"upper bound of %g\n",
|
|
2975
|
+
int(iCol), cost, upper);
|
|
2976
|
+
return HighsStatus::kError;
|
|
2977
|
+
}
|
|
2978
|
+
} else {
|
|
2979
|
+
// Maximizing with -inf cost so try to fix at lower bound
|
|
2980
|
+
if (lower > -kHighsInf) {
|
|
2981
|
+
if (k) lp.col_upper_[iCol] = lower;
|
|
2982
|
+
} else {
|
|
2983
|
+
highsLogUser(options_.log_options, HighsLogType::kError,
|
|
2984
|
+
"Cannot maximize with a cost on variable %d of %g and "
|
|
2985
|
+
"lower bound of %g\n",
|
|
2986
|
+
int(iCol), cost, lower);
|
|
2987
|
+
return HighsStatus::kError;
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
} else {
|
|
2991
|
+
if (lp.sense_ == ObjSense::kMinimize) {
|
|
2992
|
+
// Minimizing with inf cost so try to fix at lower bound
|
|
2993
|
+
if (lower > -kHighsInf) {
|
|
2994
|
+
if (k) lp.col_upper_[iCol] = lower;
|
|
2995
|
+
} else {
|
|
2996
|
+
highsLogUser(options_.log_options, HighsLogType::kError,
|
|
2997
|
+
"Cannot minimize with a cost on variable %d of %g and "
|
|
2998
|
+
"lower bound of %g\n",
|
|
2999
|
+
int(iCol), cost, lower);
|
|
3000
|
+
return HighsStatus::kError;
|
|
3001
|
+
}
|
|
3002
|
+
} else {
|
|
3003
|
+
// Maximizing with inf cost so try to fix at upper bound
|
|
3004
|
+
if (upper < kHighsInf) {
|
|
3005
|
+
if (k) lp.col_lower_[iCol] = upper;
|
|
3006
|
+
} else {
|
|
3007
|
+
highsLogUser(options_.log_options, HighsLogType::kError,
|
|
3008
|
+
"Cannot maximize with a cost on variable %d of %g and "
|
|
3009
|
+
"upper bound of %g\n",
|
|
3010
|
+
int(iCol), cost, upper);
|
|
3011
|
+
return HighsStatus::kError;
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
if (k) {
|
|
3016
|
+
mods.save_inf_cost_variable_index.push_back(iCol);
|
|
3017
|
+
mods.save_inf_cost_variable_cost.push_back(cost);
|
|
3018
|
+
mods.save_inf_cost_variable_lower.push_back(lower);
|
|
3019
|
+
mods.save_inf_cost_variable_upper.push_back(upper);
|
|
3020
|
+
lp.col_cost_[iCol] = 0;
|
|
3021
|
+
}
|
|
3022
|
+
}
|
|
3023
|
+
}
|
|
3024
|
+
// Infinite costs have been removed, but their presence in the
|
|
3025
|
+
// original model is known from mods.save_inf_cost_variable_*, so
|
|
3026
|
+
// set lp.has_infinite_cost_ to be false to avoid assert when run()
|
|
3027
|
+
// is called using copy of model in MIP solver (See #1446)
|
|
3028
|
+
lp.has_infinite_cost_ = false;
|
|
3029
|
+
|
|
3030
|
+
return HighsStatus::kOk;
|
|
3031
|
+
}
|
|
3032
|
+
|
|
3033
|
+
HighsStatus Highs::optionChangeAction() {
|
|
3034
|
+
if (this->iis_.valid_ && options_.iis_strategy != this->iis_.strategy_)
|
|
3035
|
+
this->iis_.clear();
|
|
3036
|
+
return HighsStatus::kOk;
|
|
3037
|
+
}
|
|
3038
|
+
|
|
3039
|
+
void Highs::restoreInfCost(HighsStatus& return_status) {
|
|
3040
|
+
HighsLp& lp = this->model_.lp_;
|
|
3041
|
+
HighsBasis& basis = this->basis_;
|
|
3042
|
+
HighsLpMods& mods = lp.mods_;
|
|
3043
|
+
HighsInt num_inf_cost = mods.save_inf_cost_variable_index.size();
|
|
3044
|
+
if (num_inf_cost <= 0) return;
|
|
3045
|
+
assert(num_inf_cost);
|
|
3046
|
+
for (HighsInt ix = 0; ix < num_inf_cost; ix++) {
|
|
3047
|
+
HighsInt iCol = mods.save_inf_cost_variable_index[ix];
|
|
3048
|
+
double cost = mods.save_inf_cost_variable_cost[ix];
|
|
3049
|
+
double lower = mods.save_inf_cost_variable_lower[ix];
|
|
3050
|
+
double upper = mods.save_inf_cost_variable_upper[ix];
|
|
3051
|
+
double value = solution_.value_valid ? solution_.col_value[iCol] : 0;
|
|
3052
|
+
if (basis.valid) {
|
|
3053
|
+
assert(basis.col_status[iCol] != HighsBasisStatus::kBasic);
|
|
3054
|
+
if (lp.col_lower_[iCol] == lower) {
|
|
3055
|
+
basis.col_status[iCol] = HighsBasisStatus::kLower;
|
|
3056
|
+
} else {
|
|
3057
|
+
basis.col_status[iCol] = HighsBasisStatus::kUpper;
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
assert(lp.col_cost_[iCol] == 0);
|
|
3061
|
+
if (value) this->info_.objective_function_value += value * cost;
|
|
3062
|
+
lp.col_cost_[iCol] = cost;
|
|
3063
|
+
lp.col_lower_[iCol] = lower;
|
|
3064
|
+
lp.col_upper_[iCol] = upper;
|
|
3065
|
+
}
|
|
3066
|
+
// Infinite costs have been reintroduced, so reset to true the flag
|
|
3067
|
+
// that was set false in Highs::handleInfCost() (See #1446)
|
|
3068
|
+
lp.has_infinite_cost_ = true;
|
|
3069
|
+
|
|
3070
|
+
if (this->model_status_ == HighsModelStatus::kInfeasible) {
|
|
3071
|
+
// Model is infeasible with the infinite cost variables fixed at
|
|
3072
|
+
// appropriate values, so model status cannot be determined
|
|
3073
|
+
this->model_status_ = HighsModelStatus::kUnknown;
|
|
3074
|
+
setHighsModelStatusAndClearSolutionAndBasis(this->model_status_);
|
|
3075
|
+
return_status = highsStatusFromHighsModelStatus(model_status_);
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
HighsStatus Highs::userScale(HighsUserScaleData& data) {
|
|
3080
|
+
if (!options_.user_objective_scale && !options_.user_bound_scale)
|
|
3081
|
+
return HighsStatus::kOk;
|
|
3082
|
+
// User objective and bound scaling data are accumulated in the
|
|
3083
|
+
// HighsUserScaleData struct, in particular, there is a local copy
|
|
3084
|
+
// of the user objective and bound scaling options values, and
|
|
3085
|
+
// records of resulting extreme data values that prevent the user
|
|
3086
|
+
// objective and bound scaling from being applied.
|
|
3087
|
+
initialiseUserScaleData(this->options_, data);
|
|
3088
|
+
// Determine whether user scaling yields excessively large cost,
|
|
3089
|
+
// Hessian values, column/row bounds or matrix values. If not,
|
|
3090
|
+
// then apply the user scaling to the model...
|
|
3091
|
+
if (this->userScaleModel(data) == HighsStatus::kError)
|
|
3092
|
+
return HighsStatus::kError;
|
|
3093
|
+
// ... and the solution
|
|
3094
|
+
this->userScaleSolution(data);
|
|
3095
|
+
// Indicate that the scaling has been applied
|
|
3096
|
+
data.applied = true;
|
|
3097
|
+
return HighsStatus::kOk;
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
HighsStatus Highs::userUnscale(HighsUserScaleData& data) {
|
|
3101
|
+
if (!data.applied) return HighsStatus::kOk;
|
|
3102
|
+
// Unscale the incumbent model and solution
|
|
3103
|
+
HighsStatus status = HighsStatus::kOk;
|
|
3104
|
+
// Flip the scaling sign
|
|
3105
|
+
data.user_objective_scale *= -1;
|
|
3106
|
+
data.user_bound_scale *= -1;
|
|
3107
|
+
HighsStatus unscale_status = this->userScaleModel(data);
|
|
3108
|
+
if (unscale_status == HighsStatus::kError) {
|
|
3109
|
+
highsLogUser(
|
|
3110
|
+
this->options_.log_options, HighsLogType::kError,
|
|
3111
|
+
"Unexpected error removing user scaling from the incumbent model\n");
|
|
3112
|
+
assert(unscale_status != HighsStatus::kError);
|
|
3113
|
+
}
|
|
3114
|
+
const bool update_kkt = true;
|
|
3115
|
+
unscale_status = this->userScaleSolution(data, update_kkt);
|
|
3116
|
+
highsLogUser(this->options_.log_options, HighsLogType::kInfo,
|
|
3117
|
+
"After solving the user-scaled model, the unscaled solution "
|
|
3118
|
+
"has objective value %.12g\n",
|
|
3119
|
+
this->info_.objective_function_value);
|
|
3120
|
+
if (model_status_ == HighsModelStatus::kOptimal &&
|
|
3121
|
+
unscale_status != HighsStatus::kOk) {
|
|
3122
|
+
// KKT errors in the unscaled optimal solution, so log a warning and
|
|
3123
|
+
// return
|
|
3124
|
+
highsLogUser(
|
|
3125
|
+
this->options_.log_options, HighsLogType::kWarning,
|
|
3126
|
+
"User scaled problem solved to optimality, but unscaled solution "
|
|
3127
|
+
"does not satisfy feasibility and optimality tolerances\n");
|
|
3128
|
+
status = HighsStatus::kWarning;
|
|
3129
|
+
}
|
|
3130
|
+
return status;
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3133
|
+
HighsStatus Highs::userScaleModel(HighsUserScaleData& data) {
|
|
3134
|
+
// Consider applying user objective and bound scaling to the model
|
|
3135
|
+
// by first identifying whether it causes any errors due to creating
|
|
3136
|
+
// extreme data values...
|
|
3137
|
+
userScaleLp(this->model_.lp_, data, false);
|
|
3138
|
+
userScaleHessian(this->model_.hessian_, data, false);
|
|
3139
|
+
HighsStatus return_status = userScaleStatus(this->options_.log_options, data);
|
|
3140
|
+
if (return_status == HighsStatus::kError) return HighsStatus::kError;
|
|
3141
|
+
// ... and, if not, actually apply the scaling
|
|
3142
|
+
userScaleLp(this->model_.lp_, data);
|
|
3143
|
+
userScaleHessian(this->model_.hessian_, data);
|
|
3144
|
+
return return_status;
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
HighsStatus Highs::userScaleSolution(HighsUserScaleData& data,
|
|
3148
|
+
bool update_kkt) {
|
|
3149
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
3150
|
+
if (!data.user_objective_scale && !data.user_bound_scale)
|
|
3151
|
+
return HighsStatus::kOk;
|
|
3152
|
+
double objective_scale_value = std::pow(2, data.user_objective_scale);
|
|
3153
|
+
double bound_scale_value = std::pow(2, data.user_bound_scale);
|
|
3154
|
+
const HighsLp& lp = this->model_.lp_;
|
|
3155
|
+
const bool has_integrality = lp.integrality_.size();
|
|
3156
|
+
if (info_.primal_solution_status != kSolutionStatusNone) {
|
|
3157
|
+
if (data.user_bound_scale) {
|
|
3158
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
3159
|
+
if (has_integrality &&
|
|
3160
|
+
lp.integrality_[iCol] != HighsVarType::kContinuous)
|
|
3161
|
+
continue;
|
|
3162
|
+
this->solution_.col_value[iCol] *= bound_scale_value;
|
|
3163
|
+
}
|
|
3164
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++)
|
|
3165
|
+
this->solution_.row_value[iRow] *= bound_scale_value;
|
|
3166
|
+
}
|
|
3167
|
+
}
|
|
3168
|
+
if (info_.dual_solution_status != kSolutionStatusNone) {
|
|
3169
|
+
if (data.user_objective_scale) {
|
|
3170
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
|
|
3171
|
+
this->solution_.col_dual[iCol] *= objective_scale_value;
|
|
3172
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++)
|
|
3173
|
+
this->solution_.row_dual[iRow] *= objective_scale_value;
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
if (!update_kkt) return return_status;
|
|
3177
|
+
// In scaling the objective function value, have to consider the offset
|
|
3178
|
+
double objective_function_value =
|
|
3179
|
+
info_.objective_function_value - model_.lp_.offset_;
|
|
3180
|
+
objective_function_value *= (bound_scale_value * objective_scale_value);
|
|
3181
|
+
objective_function_value += model_.lp_.offset_;
|
|
3182
|
+
info_.objective_function_value = objective_function_value;
|
|
3183
|
+
getKktFailures(options_, model_, solution_, basis_, info_);
|
|
3184
|
+
return reportKktFailures(model_.lp_, options_, info_,
|
|
3185
|
+
"After removing user scaling")
|
|
3186
|
+
? HighsStatus::kWarning
|
|
3187
|
+
: return_status;
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
void HighsIllConditioning::clear() { this->record.clear(); }
|
|
3191
|
+
|
|
3192
|
+
HighsStatus Highs::computeIllConditioning(
|
|
3193
|
+
HighsIllConditioning& ill_conditioning, const bool constraint,
|
|
3194
|
+
const HighsInt method, const double ill_conditioning_bound) {
|
|
3195
|
+
const double kZeroMultiplier = 1e-6;
|
|
3196
|
+
ill_conditioning.clear();
|
|
3197
|
+
HighsLp& incumbent_lp = this->model_.lp_;
|
|
3198
|
+
Highs conditioning;
|
|
3199
|
+
const bool dev_conditioning = false;
|
|
3200
|
+
conditioning.setOptionValue("output_flag", false); // dev_conditioning);
|
|
3201
|
+
std::vector<HighsInt> basic_var;
|
|
3202
|
+
HighsLp& ill_conditioning_lp = conditioning.model_.lp_;
|
|
3203
|
+
// Form the ill-conditioning LP according to method
|
|
3204
|
+
if (method == 0) {
|
|
3205
|
+
formIllConditioningLp0(ill_conditioning_lp, basic_var, constraint);
|
|
3206
|
+
} else {
|
|
3207
|
+
formIllConditioningLp1(ill_conditioning_lp, basic_var, constraint,
|
|
3208
|
+
ill_conditioning_bound);
|
|
3209
|
+
// conditioning.writeModel("");
|
|
3210
|
+
}
|
|
3211
|
+
|
|
3212
|
+
// if (dev_conditioning) conditioning.writeModel("");
|
|
3213
|
+
|
|
3214
|
+
assert(assessLp(ill_conditioning_lp, this->options_) == HighsStatus::kOk);
|
|
3215
|
+
// Solve the ill-conditioning analysis LP
|
|
3216
|
+
HighsStatus return_status = conditioning.run();
|
|
3217
|
+
HighsModelStatus model_status = conditioning.getModelStatus();
|
|
3218
|
+
const std::string type = constraint ? "Constraint" : "Column";
|
|
3219
|
+
const bool failed =
|
|
3220
|
+
return_status != HighsStatus::kOk ||
|
|
3221
|
+
(method == 0 && model_status != HighsModelStatus::kOptimal) ||
|
|
3222
|
+
(method == 1 && (model_status != HighsModelStatus::kOptimal &&
|
|
3223
|
+
model_status != HighsModelStatus::kInfeasible));
|
|
3224
|
+
if (failed) {
|
|
3225
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
3226
|
+
"\n%s view ill-conditioning analysis has failed\n",
|
|
3227
|
+
type.c_str());
|
|
3228
|
+
return HighsStatus::kError;
|
|
3229
|
+
}
|
|
3230
|
+
if (method == 1 && model_status == HighsModelStatus::kInfeasible) {
|
|
3231
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
3232
|
+
"\n%s view ill-conditioning bound of %g is insufficient for "
|
|
3233
|
+
"analysis: try %g\n",
|
|
3234
|
+
type.c_str(), ill_conditioning_bound,
|
|
3235
|
+
1e1 * ill_conditioning_bound);
|
|
3236
|
+
return HighsStatus::kOk;
|
|
3237
|
+
}
|
|
3238
|
+
if (dev_conditioning) conditioning.writeSolution("", 1);
|
|
3239
|
+
// Extract and normalise the multipliers
|
|
3240
|
+
HighsSolution& solution = conditioning.solution_;
|
|
3241
|
+
double multiplier_norm = 0;
|
|
3242
|
+
for (HighsInt iRow = 0; iRow < incumbent_lp.num_row_; iRow++)
|
|
3243
|
+
multiplier_norm += std::fabs(solution.col_value[iRow]);
|
|
3244
|
+
assert(multiplier_norm > 0);
|
|
3245
|
+
const double ill_conditioning_measure =
|
|
3246
|
+
(method == 0 ? conditioning.getInfo().objective_function_value
|
|
3247
|
+
: solution.row_value[conditioning.getNumRow() - 1]) /
|
|
3248
|
+
multiplier_norm;
|
|
3249
|
+
highsLogUser(
|
|
3250
|
+
options_.log_options, HighsLogType::kInfo,
|
|
3251
|
+
"\n%s view ill-conditioning analysis: 1-norm distance of basis matrix "
|
|
3252
|
+
"from singularity is estimated to be %g\n",
|
|
3253
|
+
type.c_str(), ill_conditioning_measure);
|
|
3254
|
+
std::vector<std::pair<double, HighsInt>> abs_list;
|
|
3255
|
+
for (HighsInt iRow = 0; iRow < incumbent_lp.num_row_; iRow++) {
|
|
3256
|
+
double abs_multiplier =
|
|
3257
|
+
std::fabs(solution.col_value[iRow]) / multiplier_norm;
|
|
3258
|
+
if (abs_multiplier <= kZeroMultiplier) continue;
|
|
3259
|
+
abs_list.push_back(std::make_pair(abs_multiplier, iRow));
|
|
3260
|
+
}
|
|
3261
|
+
std::sort(abs_list.begin(), abs_list.end());
|
|
3262
|
+
// Report on ill-conditioning multipliers
|
|
3263
|
+
std::stringstream ss;
|
|
3264
|
+
const bool has_row_names =
|
|
3265
|
+
HighsInt(incumbent_lp.row_names_.size()) == incumbent_lp.num_row_;
|
|
3266
|
+
const bool has_col_names =
|
|
3267
|
+
HighsInt(incumbent_lp.col_names_.size()) == incumbent_lp.num_col_;
|
|
3268
|
+
const double coefficient_zero_tolerance = 1e-8;
|
|
3269
|
+
auto printCoefficient = [&](const double multiplier, const bool first) {
|
|
3270
|
+
if (std::fabs(multiplier) < coefficient_zero_tolerance) {
|
|
3271
|
+
ss << "+ 0";
|
|
3272
|
+
} else if (std::fabs(multiplier - 1) < coefficient_zero_tolerance) {
|
|
3273
|
+
std::string str = first ? "" : "+ ";
|
|
3274
|
+
ss << str;
|
|
3275
|
+
} else if (std::fabs(multiplier + 1) < coefficient_zero_tolerance) {
|
|
3276
|
+
std::string str = first ? "-" : "- ";
|
|
3277
|
+
ss << str;
|
|
3278
|
+
} else if (multiplier < 0) {
|
|
3279
|
+
std::string str = first ? "-" : "- ";
|
|
3280
|
+
ss << str << -multiplier << " ";
|
|
3281
|
+
} else {
|
|
3282
|
+
std::string str = first ? "" : "+ ";
|
|
3283
|
+
ss << str << multiplier << " ";
|
|
3284
|
+
}
|
|
3285
|
+
};
|
|
3286
|
+
|
|
3287
|
+
for (HighsInt iX = int(abs_list.size()) - 1; iX >= 0; iX--) {
|
|
3288
|
+
HighsInt iRow = abs_list[iX].second;
|
|
3289
|
+
HighsIllConditioningRecord record;
|
|
3290
|
+
record.index = iRow;
|
|
3291
|
+
record.multiplier = solution.col_value[iRow] / multiplier_norm;
|
|
3292
|
+
ill_conditioning.record.push_back(record);
|
|
3293
|
+
}
|
|
3294
|
+
HighsSparseMatrix& incumbent_matrix = incumbent_lp.a_matrix_;
|
|
3295
|
+
if (constraint) {
|
|
3296
|
+
HighsInt num_nz;
|
|
3297
|
+
std::vector<HighsInt> index(incumbent_lp.num_col_);
|
|
3298
|
+
std::vector<double> value(incumbent_lp.num_col_);
|
|
3299
|
+
HighsInt* p_index = index.data();
|
|
3300
|
+
double* p_value = value.data();
|
|
3301
|
+
for (HighsInt iX = 0; iX < HighsInt(ill_conditioning.record.size()); iX++) {
|
|
3302
|
+
ss.str(std::string());
|
|
3303
|
+
bool newline = false;
|
|
3304
|
+
HighsInt iRow = ill_conditioning.record[iX].index;
|
|
3305
|
+
double multiplier = ill_conditioning.record[iX].multiplier;
|
|
3306
|
+
// Extract the row corresponding to this constraint
|
|
3307
|
+
num_nz = 0;
|
|
3308
|
+
incumbent_matrix.getRow(iRow, num_nz, p_index, p_value);
|
|
3309
|
+
std::string row_name = has_row_names ? incumbent_lp.row_names_[iRow]
|
|
3310
|
+
: "R" + std::to_string(iRow);
|
|
3311
|
+
ss << "(Mu=" << multiplier << ")" << row_name << ": ";
|
|
3312
|
+
const double lower = incumbent_lp.row_lower_[iRow];
|
|
3313
|
+
const double upper = incumbent_lp.row_upper_[iRow];
|
|
3314
|
+
if (lower > -kHighsInf && lower != upper)
|
|
3315
|
+
ss << incumbent_lp.row_lower_[iRow] << " <= ";
|
|
3316
|
+
for (HighsInt iEl = 0; iEl < num_nz; iEl++) {
|
|
3317
|
+
if (newline) {
|
|
3318
|
+
ss << " ";
|
|
3319
|
+
newline = false;
|
|
3320
|
+
}
|
|
3321
|
+
HighsInt iCol = index[iEl];
|
|
3322
|
+
printCoefficient(value[iEl], iEl == 0);
|
|
3323
|
+
std::string col_name = has_col_names ? incumbent_lp.col_names_[iCol]
|
|
3324
|
+
: "C" + std::to_string(iCol);
|
|
3325
|
+
ss << col_name << " ";
|
|
3326
|
+
HighsInt length_ss = ss.str().length();
|
|
3327
|
+
if (length_ss > 72 && iEl < num_nz - 1) {
|
|
3328
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo, "%s\n",
|
|
3329
|
+
ss.str().c_str());
|
|
3330
|
+
ss.str(std::string());
|
|
3331
|
+
newline = true;
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
3334
|
+
if (upper < kHighsInf) {
|
|
3335
|
+
if (lower == upper) {
|
|
3336
|
+
ss << "= " << upper;
|
|
3337
|
+
} else {
|
|
3338
|
+
ss << "<= " << upper;
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
if (ss.str().length())
|
|
3342
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo, "%s\n",
|
|
3343
|
+
ss.str().c_str());
|
|
3344
|
+
}
|
|
3345
|
+
} else {
|
|
3346
|
+
for (const auto& rec : ill_conditioning.record) {
|
|
3347
|
+
ss.str(std::string());
|
|
3348
|
+
bool newline = false;
|
|
3349
|
+
double multiplier = rec.multiplier;
|
|
3350
|
+
HighsInt iCol = basic_var[rec.index];
|
|
3351
|
+
if (iCol < incumbent_lp.num_col_) {
|
|
3352
|
+
std::string col_name = has_col_names ? incumbent_lp.col_names_[iCol]
|
|
3353
|
+
: "C" + std::to_string(iCol);
|
|
3354
|
+
ss << "(Mu=" << multiplier << ")" << col_name << ": ";
|
|
3355
|
+
for (HighsInt iEl = incumbent_matrix.start_[iCol];
|
|
3356
|
+
iEl < incumbent_matrix.start_[iCol + 1]; iEl++) {
|
|
3357
|
+
if (newline) {
|
|
3358
|
+
ss << " ";
|
|
3359
|
+
newline = false;
|
|
3360
|
+
} else {
|
|
3361
|
+
if (iEl > incumbent_matrix.start_[iCol]) ss << " | ";
|
|
3362
|
+
}
|
|
3363
|
+
HighsInt iRow = incumbent_matrix.index_[iEl];
|
|
3364
|
+
printCoefficient(incumbent_matrix.value_[iEl], true);
|
|
3365
|
+
std::string row_name = has_row_names ? incumbent_lp.row_names_[iRow]
|
|
3366
|
+
: "R" + std::to_string(iRow);
|
|
3367
|
+
ss << row_name;
|
|
3368
|
+
HighsInt length_ss = ss.str().length();
|
|
3369
|
+
if (length_ss > 72 && iEl < incumbent_matrix.start_[iCol + 1] - 1) {
|
|
3370
|
+
ss << " | ";
|
|
3371
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo, "%s\n",
|
|
3372
|
+
ss.str().c_str());
|
|
3373
|
+
ss.str(std::string());
|
|
3374
|
+
newline = true;
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3377
|
+
} else {
|
|
3378
|
+
HighsInt iRow = iCol - incumbent_lp.num_col_;
|
|
3379
|
+
std::string col_name = has_row_names
|
|
3380
|
+
? "Slack_" + incumbent_lp.row_names_[iRow]
|
|
3381
|
+
: "Slack_R" + std::to_string(iRow);
|
|
3382
|
+
ss << "(Mu=" << multiplier << ")" << col_name << ": ";
|
|
3383
|
+
}
|
|
3384
|
+
if (ss.str().length())
|
|
3385
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo, "%s\n",
|
|
3386
|
+
ss.str().c_str());
|
|
3387
|
+
}
|
|
3388
|
+
}
|
|
3389
|
+
return HighsStatus::kOk;
|
|
3390
|
+
}
|
|
3391
|
+
|
|
3392
|
+
void Highs::formIllConditioningLp0(HighsLp& ill_conditioning_lp,
|
|
3393
|
+
std::vector<HighsInt>& basic_var,
|
|
3394
|
+
const bool constraint) {
|
|
3395
|
+
HighsLp& incumbent_lp = this->model_.lp_;
|
|
3396
|
+
// Conditioning LP minimizes the infeasibilities of
|
|
3397
|
+
//
|
|
3398
|
+
// [B^T]y = [0]; y free - for constraint view
|
|
3399
|
+
// [e^T] [1]
|
|
3400
|
+
//
|
|
3401
|
+
// [ B ]y = [0]; y free - for column view
|
|
3402
|
+
// [e^T] [1]
|
|
3403
|
+
//
|
|
3404
|
+
ill_conditioning_lp.num_row_ = incumbent_lp.num_row_ + 1;
|
|
3405
|
+
for (HighsInt iRow = 0; iRow < incumbent_lp.num_row_; iRow++) {
|
|
3406
|
+
ill_conditioning_lp.row_lower_.push_back(0);
|
|
3407
|
+
ill_conditioning_lp.row_upper_.push_back(0);
|
|
3408
|
+
}
|
|
3409
|
+
ill_conditioning_lp.row_lower_.push_back(1);
|
|
3410
|
+
ill_conditioning_lp.row_upper_.push_back(1);
|
|
3411
|
+
HighsSparseMatrix& incumbent_matrix = incumbent_lp.a_matrix_;
|
|
3412
|
+
incumbent_matrix.ensureColwise();
|
|
3413
|
+
HighsSparseMatrix& ill_conditioning_matrix = ill_conditioning_lp.a_matrix_;
|
|
3414
|
+
ill_conditioning_matrix.num_row_ = ill_conditioning_lp.num_row_;
|
|
3415
|
+
// Form the basis matrix and
|
|
3416
|
+
//
|
|
3417
|
+
// * For constraint view, add the column e, and transpose the
|
|
3418
|
+
// * resulting matrix
|
|
3419
|
+
//
|
|
3420
|
+
// * For column view, add a unit entry to each column
|
|
3421
|
+
//
|
|
3422
|
+
const HighsInt ill_conditioning_lp_e_row = ill_conditioning_lp.num_row_ - 1;
|
|
3423
|
+
for (HighsInt iCol = 0; iCol < incumbent_lp.num_col_; iCol++) {
|
|
3424
|
+
if (this->basis_.col_status[iCol] != HighsBasisStatus::kBasic) continue;
|
|
3425
|
+
// Basic column goes into conditioning LP, possibly with unit
|
|
3426
|
+
// coefficient for constraint e^Ty=1
|
|
3427
|
+
basic_var.push_back(iCol);
|
|
3428
|
+
ill_conditioning_lp.col_cost_.push_back(0);
|
|
3429
|
+
ill_conditioning_lp.col_lower_.push_back(-kHighsInf);
|
|
3430
|
+
ill_conditioning_lp.col_upper_.push_back(kHighsInf);
|
|
3431
|
+
for (HighsInt iEl = incumbent_matrix.start_[iCol];
|
|
3432
|
+
iEl < incumbent_matrix.start_[iCol + 1]; iEl++) {
|
|
3433
|
+
ill_conditioning_matrix.index_.push_back(incumbent_matrix.index_[iEl]);
|
|
3434
|
+
ill_conditioning_matrix.value_.push_back(incumbent_matrix.value_[iEl]);
|
|
3435
|
+
}
|
|
3436
|
+
if (!constraint) {
|
|
3437
|
+
ill_conditioning_matrix.index_.push_back(ill_conditioning_lp_e_row);
|
|
3438
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3439
|
+
}
|
|
3440
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3441
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3442
|
+
}
|
|
3443
|
+
for (HighsInt iRow = 0; iRow < incumbent_lp.num_row_; iRow++) {
|
|
3444
|
+
if (this->basis_.row_status[iRow] != HighsBasisStatus::kBasic) continue;
|
|
3445
|
+
// Basic slack goes into conditioning LP
|
|
3446
|
+
basic_var.push_back(incumbent_lp.num_col_ + iRow);
|
|
3447
|
+
ill_conditioning_lp.col_cost_.push_back(0);
|
|
3448
|
+
ill_conditioning_lp.col_lower_.push_back(-kHighsInf);
|
|
3449
|
+
ill_conditioning_lp.col_upper_.push_back(kHighsInf);
|
|
3450
|
+
ill_conditioning_matrix.index_.push_back(iRow);
|
|
3451
|
+
ill_conditioning_matrix.value_.push_back(-1.0);
|
|
3452
|
+
if (!constraint) {
|
|
3453
|
+
ill_conditioning_matrix.index_.push_back(ill_conditioning_lp_e_row);
|
|
3454
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3455
|
+
}
|
|
3456
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3457
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3458
|
+
}
|
|
3459
|
+
if (constraint) {
|
|
3460
|
+
// Add the column e, and transpose the resulting matrix
|
|
3461
|
+
for (HighsInt iRow = 0; iRow < incumbent_lp.num_row_; iRow++) {
|
|
3462
|
+
ill_conditioning_matrix.index_.push_back(iRow);
|
|
3463
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3464
|
+
}
|
|
3465
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3466
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3467
|
+
ill_conditioning_matrix.num_row_ = incumbent_lp.num_row_;
|
|
3468
|
+
ill_conditioning_matrix.num_col_ = incumbent_lp.num_row_ + 1;
|
|
3469
|
+
ill_conditioning_matrix.ensureRowwise();
|
|
3470
|
+
ill_conditioning_matrix.format_ = MatrixFormat::kColwise;
|
|
3471
|
+
}
|
|
3472
|
+
// Now add the variables to measure the infeasibilities
|
|
3473
|
+
for (HighsInt iRow = 0; iRow < incumbent_lp.num_row_; iRow++) {
|
|
3474
|
+
// Adding x_+ with cost 1
|
|
3475
|
+
ill_conditioning_lp.col_cost_.push_back(1);
|
|
3476
|
+
ill_conditioning_lp.col_lower_.push_back(0);
|
|
3477
|
+
ill_conditioning_lp.col_upper_.push_back(kHighsInf);
|
|
3478
|
+
ill_conditioning_matrix.index_.push_back(iRow);
|
|
3479
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3480
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3481
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3482
|
+
// Subtracting x_- with cost 1
|
|
3483
|
+
ill_conditioning_lp.col_cost_.push_back(1);
|
|
3484
|
+
ill_conditioning_lp.col_lower_.push_back(0);
|
|
3485
|
+
ill_conditioning_lp.col_upper_.push_back(kHighsInf);
|
|
3486
|
+
ill_conditioning_matrix.index_.push_back(iRow);
|
|
3487
|
+
ill_conditioning_matrix.value_.push_back(-1.0);
|
|
3488
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3489
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3490
|
+
}
|
|
3491
|
+
ill_conditioning_lp.num_col_ = 3 * incumbent_lp.num_row_;
|
|
3492
|
+
ill_conditioning_matrix.num_col_ = ill_conditioning_lp.num_col_;
|
|
3493
|
+
ill_conditioning_matrix.num_row_ = ill_conditioning_lp.num_row_;
|
|
3494
|
+
}
|
|
3495
|
+
|
|
3496
|
+
void Highs::formIllConditioningLp1(HighsLp& ill_conditioning_lp,
|
|
3497
|
+
std::vector<HighsInt>& basic_var,
|
|
3498
|
+
const bool constraint,
|
|
3499
|
+
const double ill_conditioning_bound) {
|
|
3500
|
+
HighsLp& incumbent_lp = this->model_.lp_;
|
|
3501
|
+
const HighsInt incumbent_num_row = incumbent_lp.num_row_;
|
|
3502
|
+
//
|
|
3503
|
+
// Using notation from Klotz14
|
|
3504
|
+
//
|
|
3505
|
+
// For constraint view, conditioning LP minimizes the
|
|
3506
|
+
// infeasibilities of c7
|
|
3507
|
+
//
|
|
3508
|
+
// c4: B^Ty - s + t = 0
|
|
3509
|
+
// c1: y - u + w = 0
|
|
3510
|
+
// c7: u + w = 0
|
|
3511
|
+
// c6: e^Ty = 1
|
|
3512
|
+
// c5: e^Ts + e^Tt <= eps
|
|
3513
|
+
// y free; u, w, s, t >= 0
|
|
3514
|
+
//
|
|
3515
|
+
// Column view uses B rather than B^T
|
|
3516
|
+
//
|
|
3517
|
+
// Set up offsets
|
|
3518
|
+
//
|
|
3519
|
+
const HighsInt c4_offset = 0;
|
|
3520
|
+
const HighsInt c1_offset = incumbent_num_row;
|
|
3521
|
+
const HighsInt c7_offset = 2 * incumbent_num_row;
|
|
3522
|
+
const HighsInt c6_offset = 3 * incumbent_num_row;
|
|
3523
|
+
const HighsInt c5_offset = 3 * incumbent_num_row + 1;
|
|
3524
|
+
for (HighsInt iRow = 0; iRow < c6_offset; iRow++) {
|
|
3525
|
+
ill_conditioning_lp.row_lower_.push_back(0);
|
|
3526
|
+
ill_conditioning_lp.row_upper_.push_back(0);
|
|
3527
|
+
}
|
|
3528
|
+
HighsSparseMatrix& incumbent_matrix = incumbent_lp.a_matrix_;
|
|
3529
|
+
incumbent_matrix.ensureColwise();
|
|
3530
|
+
HighsSparseMatrix& ill_conditioning_matrix = ill_conditioning_lp.a_matrix_;
|
|
3531
|
+
// Form the basis matrix and
|
|
3532
|
+
//
|
|
3533
|
+
// * For constraint view, add the identity matrix and vector of
|
|
3534
|
+
// * ones, and transpose the resulting matrix
|
|
3535
|
+
//
|
|
3536
|
+
// * For column view, add an identity matrix column and unit entry
|
|
3537
|
+
// * below each column
|
|
3538
|
+
//
|
|
3539
|
+
ill_conditioning_lp.num_col_ = 0;
|
|
3540
|
+
for (HighsInt iCol = 0; iCol < incumbent_lp.num_col_; iCol++) {
|
|
3541
|
+
if (this->basis_.col_status[iCol] != HighsBasisStatus::kBasic) continue;
|
|
3542
|
+
// Basic column goes into ill-conditioning LP, possibly with
|
|
3543
|
+
// identity matrix column for constraint y - u + w = 0 and unit
|
|
3544
|
+
// entry for e^Ty = 1
|
|
3545
|
+
basic_var.push_back(iCol);
|
|
3546
|
+
ill_conditioning_lp.col_names_.push_back(
|
|
3547
|
+
"y_" + std::to_string(ill_conditioning_lp.num_col_));
|
|
3548
|
+
ill_conditioning_lp.col_cost_.push_back(0);
|
|
3549
|
+
ill_conditioning_lp.col_lower_.push_back(-kHighsInf);
|
|
3550
|
+
ill_conditioning_lp.col_upper_.push_back(kHighsInf);
|
|
3551
|
+
for (HighsInt iEl = incumbent_matrix.start_[iCol];
|
|
3552
|
+
iEl < incumbent_matrix.start_[iCol + 1]; iEl++) {
|
|
3553
|
+
ill_conditioning_matrix.index_.push_back(incumbent_matrix.index_[iEl]);
|
|
3554
|
+
ill_conditioning_matrix.value_.push_back(incumbent_matrix.value_[iEl]);
|
|
3555
|
+
}
|
|
3556
|
+
if (!constraint) {
|
|
3557
|
+
// Add identity matrix column for constraint y - u + w = 0
|
|
3558
|
+
ill_conditioning_matrix.index_.push_back(c1_offset +
|
|
3559
|
+
ill_conditioning_lp.num_col_);
|
|
3560
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3561
|
+
// Add unit entry for e^Ty = 1
|
|
3562
|
+
ill_conditioning_matrix.index_.push_back(c6_offset);
|
|
3563
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3564
|
+
}
|
|
3565
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3566
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3567
|
+
ill_conditioning_lp.num_col_++;
|
|
3568
|
+
}
|
|
3569
|
+
|
|
3570
|
+
for (HighsInt iRow = 0; iRow < incumbent_num_row; iRow++) {
|
|
3571
|
+
if (this->basis_.row_status[iRow] != HighsBasisStatus::kBasic) continue;
|
|
3572
|
+
// Basic slack goes into conditioning LP
|
|
3573
|
+
basic_var.push_back(incumbent_lp.num_col_ + iRow);
|
|
3574
|
+
ill_conditioning_lp.col_names_.push_back(
|
|
3575
|
+
"y_" + std::to_string(ill_conditioning_lp.num_col_));
|
|
3576
|
+
ill_conditioning_lp.col_cost_.push_back(0);
|
|
3577
|
+
ill_conditioning_lp.col_lower_.push_back(-kHighsInf);
|
|
3578
|
+
ill_conditioning_lp.col_upper_.push_back(kHighsInf);
|
|
3579
|
+
ill_conditioning_matrix.index_.push_back(iRow);
|
|
3580
|
+
ill_conditioning_matrix.value_.push_back(-1.0);
|
|
3581
|
+
if (!constraint) {
|
|
3582
|
+
// Add identity matrix column for constraint y - u + w = 0
|
|
3583
|
+
ill_conditioning_matrix.index_.push_back(c1_offset +
|
|
3584
|
+
ill_conditioning_lp.num_col_);
|
|
3585
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3586
|
+
// Add unit entry for e^Ty = 1
|
|
3587
|
+
ill_conditioning_matrix.index_.push_back(c6_offset);
|
|
3588
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3589
|
+
}
|
|
3590
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3591
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3592
|
+
ill_conditioning_lp.num_col_++;
|
|
3593
|
+
}
|
|
3594
|
+
assert(ill_conditioning_lp.num_col_ == incumbent_num_row);
|
|
3595
|
+
if (constraint) {
|
|
3596
|
+
// Add the identity matrix for constraint y - u + w = 0
|
|
3597
|
+
for (HighsInt iRow = 0; iRow < incumbent_num_row; iRow++) {
|
|
3598
|
+
ill_conditioning_matrix.index_.push_back(iRow);
|
|
3599
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3600
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3601
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3602
|
+
}
|
|
3603
|
+
// Add the square zero matrix of c7
|
|
3604
|
+
for (HighsInt iRow = 0; iRow < incumbent_num_row; iRow++)
|
|
3605
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3606
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3607
|
+
// Add the vector of ones for e^Ty = 1
|
|
3608
|
+
for (HighsInt iRow = 0; iRow < incumbent_num_row; iRow++) {
|
|
3609
|
+
ill_conditioning_matrix.index_.push_back(iRow);
|
|
3610
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3611
|
+
}
|
|
3612
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3613
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3614
|
+
|
|
3615
|
+
// Transpose the resulting matrix
|
|
3616
|
+
ill_conditioning_matrix.num_col_ = c6_offset + 1;
|
|
3617
|
+
ill_conditioning_matrix.num_row_ = incumbent_num_row;
|
|
3618
|
+
ill_conditioning_matrix.ensureRowwise();
|
|
3619
|
+
ill_conditioning_matrix.format_ = MatrixFormat::kColwise;
|
|
3620
|
+
ill_conditioning_matrix.num_col_ = incumbent_num_row;
|
|
3621
|
+
ill_conditioning_matrix.num_row_ = c6_offset + 1;
|
|
3622
|
+
}
|
|
3623
|
+
|
|
3624
|
+
assert(ill_conditioning_lp.num_col_ == incumbent_num_row);
|
|
3625
|
+
ill_conditioning_lp.num_row_ = 3 * incumbent_num_row + 2;
|
|
3626
|
+
|
|
3627
|
+
// Now add the variables u and w
|
|
3628
|
+
for (HighsInt iRow = 0; iRow < incumbent_num_row; iRow++) {
|
|
3629
|
+
// Adding u with cost 0
|
|
3630
|
+
ill_conditioning_lp.col_names_.push_back("u_" + std::to_string(iRow));
|
|
3631
|
+
ill_conditioning_lp.col_cost_.push_back(0);
|
|
3632
|
+
ill_conditioning_lp.col_lower_.push_back(0);
|
|
3633
|
+
ill_conditioning_lp.col_upper_.push_back(kHighsInf);
|
|
3634
|
+
// Contribution to c1: y - u + w = 0
|
|
3635
|
+
ill_conditioning_matrix.index_.push_back(c1_offset + iRow);
|
|
3636
|
+
ill_conditioning_matrix.value_.push_back(-1.0);
|
|
3637
|
+
// Contribution to c7: u + w = 0
|
|
3638
|
+
ill_conditioning_matrix.index_.push_back(c7_offset + iRow);
|
|
3639
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3640
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3641
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3642
|
+
ill_conditioning_lp.num_col_++;
|
|
3643
|
+
// Adding w with cost 0
|
|
3644
|
+
ill_conditioning_lp.col_names_.push_back("w_" + std::to_string(iRow));
|
|
3645
|
+
ill_conditioning_lp.col_cost_.push_back(0);
|
|
3646
|
+
ill_conditioning_lp.col_lower_.push_back(0);
|
|
3647
|
+
ill_conditioning_lp.col_upper_.push_back(kHighsInf);
|
|
3648
|
+
// Contribution to c1: y - u + w = 0
|
|
3649
|
+
ill_conditioning_matrix.index_.push_back(c1_offset + iRow);
|
|
3650
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3651
|
+
// Contribution to c7: u + w = 0
|
|
3652
|
+
ill_conditioning_matrix.index_.push_back(c7_offset + iRow);
|
|
3653
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3654
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3655
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3656
|
+
ill_conditioning_lp.num_col_++;
|
|
3657
|
+
}
|
|
3658
|
+
// Now add the variables s and t
|
|
3659
|
+
for (HighsInt iRow = 0; iRow < incumbent_num_row; iRow++) {
|
|
3660
|
+
// Adding s with cost 0
|
|
3661
|
+
ill_conditioning_lp.col_names_.push_back("s_" + std::to_string(iRow));
|
|
3662
|
+
ill_conditioning_lp.col_cost_.push_back(0);
|
|
3663
|
+
ill_conditioning_lp.col_lower_.push_back(0);
|
|
3664
|
+
ill_conditioning_lp.col_upper_.push_back(kHighsInf);
|
|
3665
|
+
// Contribution to c4: B^Ty - s + t = 0
|
|
3666
|
+
ill_conditioning_matrix.index_.push_back(c4_offset + iRow);
|
|
3667
|
+
ill_conditioning_matrix.value_.push_back(-1.0);
|
|
3668
|
+
// Contribution to c5: e^Ts + e^Tt <= eps
|
|
3669
|
+
ill_conditioning_matrix.index_.push_back(c5_offset);
|
|
3670
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3671
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3672
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3673
|
+
ill_conditioning_lp.num_col_++;
|
|
3674
|
+
// Adding t with cost 0
|
|
3675
|
+
ill_conditioning_lp.col_names_.push_back("t_" + std::to_string(iRow));
|
|
3676
|
+
ill_conditioning_lp.col_cost_.push_back(0);
|
|
3677
|
+
ill_conditioning_lp.col_lower_.push_back(0);
|
|
3678
|
+
ill_conditioning_lp.col_upper_.push_back(kHighsInf);
|
|
3679
|
+
// Contribution to c4: B^Ty - s + t = 0
|
|
3680
|
+
ill_conditioning_matrix.index_.push_back(c4_offset + iRow);
|
|
3681
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3682
|
+
// Contribution to c5: e^Ts + e^Tt <= eps
|
|
3683
|
+
ill_conditioning_matrix.index_.push_back(c5_offset);
|
|
3684
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3685
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3686
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3687
|
+
ill_conditioning_lp.num_col_++;
|
|
3688
|
+
}
|
|
3689
|
+
// Add the bounds for c6: e^Ty = 1
|
|
3690
|
+
ill_conditioning_lp.row_lower_.push_back(1);
|
|
3691
|
+
ill_conditioning_lp.row_upper_.push_back(1);
|
|
3692
|
+
// Add the bounds for c5: e^Ts + e^Tt <= eps
|
|
3693
|
+
assert(ill_conditioning_bound > 0);
|
|
3694
|
+
ill_conditioning_lp.row_lower_.push_back(-kHighsInf);
|
|
3695
|
+
ill_conditioning_lp.row_upper_.push_back(ill_conditioning_bound);
|
|
3696
|
+
assert(HighsInt(ill_conditioning_lp.row_lower_.size()) ==
|
|
3697
|
+
ill_conditioning_lp.num_row_);
|
|
3698
|
+
assert(HighsInt(ill_conditioning_lp.row_upper_.size()) ==
|
|
3699
|
+
ill_conditioning_lp.num_row_);
|
|
3700
|
+
|
|
3701
|
+
// Now add the variables to measure the infeasibilities in
|
|
3702
|
+
//
|
|
3703
|
+
// c7: u + w = r^+ - r^-
|
|
3704
|
+
for (HighsInt iRow = 0; iRow < incumbent_num_row; iRow++) {
|
|
3705
|
+
// Adding r^+ with cost 1
|
|
3706
|
+
ill_conditioning_lp.col_names_.push_back("IfsPlus_" + std::to_string(iRow));
|
|
3707
|
+
ill_conditioning_lp.col_cost_.push_back(1);
|
|
3708
|
+
ill_conditioning_lp.col_lower_.push_back(0);
|
|
3709
|
+
ill_conditioning_lp.col_upper_.push_back(kHighsInf);
|
|
3710
|
+
ill_conditioning_matrix.index_.push_back(c7_offset + iRow);
|
|
3711
|
+
ill_conditioning_matrix.value_.push_back(-1.0);
|
|
3712
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3713
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3714
|
+
ill_conditioning_lp.num_col_++;
|
|
3715
|
+
// Adding r^- with cost 1
|
|
3716
|
+
ill_conditioning_lp.col_names_.push_back("IfsMinus_" +
|
|
3717
|
+
std::to_string(iRow));
|
|
3718
|
+
ill_conditioning_lp.col_cost_.push_back(1);
|
|
3719
|
+
ill_conditioning_lp.col_lower_.push_back(0);
|
|
3720
|
+
ill_conditioning_lp.col_upper_.push_back(kHighsInf);
|
|
3721
|
+
ill_conditioning_matrix.index_.push_back(c7_offset + iRow);
|
|
3722
|
+
ill_conditioning_matrix.value_.push_back(1.0);
|
|
3723
|
+
ill_conditioning_matrix.start_.push_back(
|
|
3724
|
+
HighsInt(ill_conditioning_matrix.index_.size()));
|
|
3725
|
+
ill_conditioning_lp.num_col_++;
|
|
3726
|
+
}
|
|
3727
|
+
assert(ill_conditioning_lp.num_col_ == 7 * incumbent_num_row);
|
|
3728
|
+
assert(ill_conditioning_lp.num_row_ == 3 * incumbent_num_row + 2);
|
|
3729
|
+
ill_conditioning_matrix.num_col_ = ill_conditioning_lp.num_col_;
|
|
3730
|
+
ill_conditioning_matrix.num_row_ = ill_conditioning_lp.num_row_;
|
|
3731
|
+
}
|
|
3732
|
+
|
|
3733
|
+
bool Highs::infeasibleBoundsOk() {
|
|
3734
|
+
const HighsLogOptions& log_options = this->options_.log_options;
|
|
3735
|
+
HighsLp& lp = this->model_.lp_;
|
|
3736
|
+
|
|
3737
|
+
HighsInt num_true_infeasible_bound = 0;
|
|
3738
|
+
HighsInt num_ok_infeasible_bound = 0;
|
|
3739
|
+
const bool has_integrality = lp.integrality_.size() > 0;
|
|
3740
|
+
bool performed_inward_integer_rounding = false;
|
|
3741
|
+
// Lambda for assessing infeasible bounds
|
|
3742
|
+
auto infeasibleBoundOk = [&](const std::string& type, const HighsInt iX,
|
|
3743
|
+
double& lower, double& upper) {
|
|
3744
|
+
double range = upper - lower;
|
|
3745
|
+
// Should only be called if lower > upper, so range < 0
|
|
3746
|
+
assert(range < 0);
|
|
3747
|
+
if (range >= 0) return true;
|
|
3748
|
+
if (range > -this->options_.primal_feasibility_tolerance) {
|
|
3749
|
+
// Infeasibility is less than feasibility tolerance, so fix
|
|
3750
|
+
// bounds at lower (upper) if lower (upper) is an integer - and
|
|
3751
|
+
// both can't be integer, otherwise the range <= -1 - otherwise
|
|
3752
|
+
// fix at 0.5 * (lower + upper)
|
|
3753
|
+
num_ok_infeasible_bound++;
|
|
3754
|
+
bool report = num_ok_infeasible_bound <= 10;
|
|
3755
|
+
bool integer_lower = lower == std::floor(lower + 0.5);
|
|
3756
|
+
bool integer_upper = upper == std::floor(upper + 0.5);
|
|
3757
|
+
assert(!integer_lower || !integer_upper);
|
|
3758
|
+
if (integer_lower) {
|
|
3759
|
+
if (report)
|
|
3760
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
3761
|
+
"%s %d bounds [%g, %g] have infeasibility = %g so set "
|
|
3762
|
+
"upper bound to %g\n",
|
|
3763
|
+
type.c_str(), int(iX), lower, upper, range, lower);
|
|
3764
|
+
upper = lower;
|
|
3765
|
+
} else if (integer_upper) {
|
|
3766
|
+
if (report)
|
|
3767
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
3768
|
+
"%s %d bounds [%g, %g] have infeasibility = %g so set "
|
|
3769
|
+
"lower bound to %g\n",
|
|
3770
|
+
type.c_str(), int(iX), lower, upper, range, upper);
|
|
3771
|
+
lower = upper;
|
|
3772
|
+
} else {
|
|
3773
|
+
double mid = 0.5 * (lower + upper);
|
|
3774
|
+
if (report)
|
|
3775
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
3776
|
+
"%s %d bounds [%g, %g] have infeasibility = %g so set "
|
|
3777
|
+
"both bounds to %g\n",
|
|
3778
|
+
type.c_str(), int(iX), lower, upper, range, mid);
|
|
3779
|
+
lower = mid;
|
|
3780
|
+
upper = mid;
|
|
3781
|
+
}
|
|
3782
|
+
return true;
|
|
3783
|
+
}
|
|
3784
|
+
// Infeasibility is greater than feasibility tolerance, so report
|
|
3785
|
+
// this (up to 10 times)
|
|
3786
|
+
num_true_infeasible_bound++;
|
|
3787
|
+
if (num_true_infeasible_bound <= 10)
|
|
3788
|
+
highsLogUser(
|
|
3789
|
+
log_options, HighsLogType::kInfo,
|
|
3790
|
+
"%s %d bounds [%g, %g] have excessive infeasibility = %g%s\n",
|
|
3791
|
+
type.c_str(), int(iX), lower, upper, range,
|
|
3792
|
+
performed_inward_integer_rounding ? " due to inward integer rounding"
|
|
3793
|
+
: "");
|
|
3794
|
+
return false;
|
|
3795
|
+
};
|
|
3796
|
+
|
|
3797
|
+
const bool perform_inward_integer_rounding = !this->options_.solve_relaxation;
|
|
3798
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
3799
|
+
performed_inward_integer_rounding = false;
|
|
3800
|
+
double lower = lp.col_lower_[iCol];
|
|
3801
|
+
double upper = lp.col_upper_[iCol];
|
|
3802
|
+
if (has_integrality) {
|
|
3803
|
+
// Semi-variables cannot have inconsistent bounds
|
|
3804
|
+
if (lp.integrality_[iCol] == HighsVarType::kSemiContinuous ||
|
|
3805
|
+
lp.integrality_[iCol] == HighsVarType::kSemiInteger)
|
|
3806
|
+
continue;
|
|
3807
|
+
if (perform_inward_integer_rounding &&
|
|
3808
|
+
lp.integrality_[iCol] == HighsVarType::kInteger) {
|
|
3809
|
+
// Assess bounds after inward integer rounding
|
|
3810
|
+
double feastol = this->options_.mip_feasibility_tolerance;
|
|
3811
|
+
double integer_lower = std::ceil(lower - feastol);
|
|
3812
|
+
double integer_upper = std::floor(upper + feastol);
|
|
3813
|
+
assert(integer_lower >= lower);
|
|
3814
|
+
assert(integer_upper <= upper);
|
|
3815
|
+
performed_inward_integer_rounding =
|
|
3816
|
+
integer_lower > lower || integer_upper < upper;
|
|
3817
|
+
lower = integer_lower;
|
|
3818
|
+
upper = integer_upper;
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
//
|
|
3822
|
+
if (lower > upper) {
|
|
3823
|
+
if (infeasibleBoundOk("Column", iCol, lower, upper)) {
|
|
3824
|
+
// Bound infeasibility is OK (less than the tolerance), so can
|
|
3825
|
+
// change the model data
|
|
3826
|
+
lp.col_lower_[iCol] = lower;
|
|
3827
|
+
lp.col_upper_[iCol] = upper;
|
|
3828
|
+
}
|
|
3829
|
+
}
|
|
3830
|
+
// Note that any inward integer rounding can't be used to change
|
|
3831
|
+
// the model data, since it may be a significant change and make
|
|
3832
|
+
// the relaxation infeasible when previously it was feasible. In
|
|
3833
|
+
// particular, when inward integer rounding leads to inconsistent
|
|
3834
|
+
// bounds being propagated to the relaxation, this can prevent a
|
|
3835
|
+
// dual ray from being constructed
|
|
3836
|
+
}
|
|
3837
|
+
performed_inward_integer_rounding = false;
|
|
3838
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
3839
|
+
if (lp.row_lower_[iRow] > lp.row_upper_[iRow])
|
|
3840
|
+
infeasibleBoundOk("Row", iRow, lp.row_lower_[iRow], lp.row_upper_[iRow]);
|
|
3841
|
+
}
|
|
3842
|
+
if (num_ok_infeasible_bound > 0)
|
|
3843
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
3844
|
+
"Model has %d small inconsistent bound(s): rectified\n",
|
|
3845
|
+
int(num_ok_infeasible_bound));
|
|
3846
|
+
if (num_true_infeasible_bound > 0)
|
|
3847
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
3848
|
+
"Model has %d significant inconsistent bound(s): infeasible\n",
|
|
3849
|
+
int(num_true_infeasible_bound));
|
|
3850
|
+
return num_true_infeasible_bound == 0;
|
|
3851
|
+
}
|
|
3852
|
+
|
|
3853
|
+
bool Highs::validLinearObjective(const HighsLinearObjective& linear_objective,
|
|
3854
|
+
const HighsInt iObj) const {
|
|
3855
|
+
HighsInt linear_objective_coefficients_size =
|
|
3856
|
+
linear_objective.coefficients.size();
|
|
3857
|
+
if (linear_objective_coefficients_size != this->model_.lp_.num_col_) {
|
|
3858
|
+
highsLogUser(
|
|
3859
|
+
options_.log_options, HighsLogType::kError,
|
|
3860
|
+
"Coefficient vector for linear objective %s has size %d != %d = "
|
|
3861
|
+
"lp.num_col_\n",
|
|
3862
|
+
iObj >= 0 ? std::to_string(iObj).c_str() : "",
|
|
3863
|
+
int(linear_objective_coefficients_size),
|
|
3864
|
+
int(this->model_.lp_.num_col_));
|
|
3865
|
+
return false;
|
|
3866
|
+
}
|
|
3867
|
+
if (!options_.blend_multi_objectives &&
|
|
3868
|
+
hasRepeatedLinearObjectivePriorities(&linear_objective)) {
|
|
3869
|
+
highsLogUser(
|
|
3870
|
+
options_.log_options, HighsLogType::kError,
|
|
3871
|
+
"Repeated priorities for lexicographic optimization is illegal\n");
|
|
3872
|
+
return false;
|
|
3873
|
+
}
|
|
3874
|
+
return true;
|
|
3875
|
+
}
|
|
3876
|
+
|
|
3877
|
+
bool Highs::hasRepeatedLinearObjectivePriorities(
|
|
3878
|
+
const HighsLinearObjective* linear_objective) const {
|
|
3879
|
+
// Look for repeated values in the linear objective priorities, also
|
|
3880
|
+
// comparing linear_objective if it's not a null pointer. Cost is
|
|
3881
|
+
// O(n^2), but who will have more than O(1) linear objectives!
|
|
3882
|
+
HighsInt num_linear_objective = this->multi_linear_objective_.size();
|
|
3883
|
+
if (num_linear_objective <= 0 ||
|
|
3884
|
+
(num_linear_objective <= 1 && !linear_objective))
|
|
3885
|
+
return false;
|
|
3886
|
+
for (HighsInt iObj0 = 0; iObj0 < num_linear_objective; iObj0++) {
|
|
3887
|
+
HighsInt priority0 = this->multi_linear_objective_[iObj0].priority;
|
|
3888
|
+
for (HighsInt iObj1 = iObj0 + 1; iObj1 < num_linear_objective; iObj1++) {
|
|
3889
|
+
HighsInt priority1 = this->multi_linear_objective_[iObj1].priority;
|
|
3890
|
+
if (priority1 == priority0) return true;
|
|
3891
|
+
}
|
|
3892
|
+
if (linear_objective) {
|
|
3893
|
+
if (linear_objective->priority == priority0) return true;
|
|
3894
|
+
}
|
|
3895
|
+
}
|
|
3896
|
+
return false;
|
|
3897
|
+
}
|
|
3898
|
+
|
|
3899
|
+
static bool comparison(std::pair<HighsInt, HighsInt> x1,
|
|
3900
|
+
std::pair<HighsInt, HighsInt> x2) {
|
|
3901
|
+
return x1.first > x2.first;
|
|
3902
|
+
}
|
|
3903
|
+
|
|
3904
|
+
HighsStatus Highs::returnFromLexicographicOptimization(
|
|
3905
|
+
HighsStatus return_status, HighsInt original_lp_num_row) {
|
|
3906
|
+
// Save model_status_ and info_ since they are cleared by calling
|
|
3907
|
+
// deleteRows
|
|
3908
|
+
HighsModelStatus model_status = this->model_status_;
|
|
3909
|
+
HighsInfo info = this->info_;
|
|
3910
|
+
HighsInt num_linear_objective = this->multi_linear_objective_.size();
|
|
3911
|
+
if (num_linear_objective > 1) {
|
|
3912
|
+
this->deleteRows(original_lp_num_row, this->model_.lp_.num_row_ - 1);
|
|
3913
|
+
// Recover model_status_ and info_, and then account for lack of basis or
|
|
3914
|
+
// dual solution
|
|
3915
|
+
this->model_status_ = model_status;
|
|
3916
|
+
this->info_ = info;
|
|
3917
|
+
info_.objective_function_value = 0;
|
|
3918
|
+
info_.basis_validity = kBasisValidityInvalid;
|
|
3919
|
+
info_.invalidateDualKkt();
|
|
3920
|
+
this->solution_.value_valid = true;
|
|
3921
|
+
this->model_.lp_.col_cost_.assign(this->model_.lp_.num_col_, 0);
|
|
3922
|
+
}
|
|
3923
|
+
return return_status;
|
|
3924
|
+
}
|
|
3925
|
+
|
|
3926
|
+
HighsStatus Highs::multiobjectiveSolve() {
|
|
3927
|
+
const HighsInt coeff_logging_size_limit = 10;
|
|
3928
|
+
HighsInt num_linear_objective = this->multi_linear_objective_.size();
|
|
3929
|
+
|
|
3930
|
+
assert(num_linear_objective > 0);
|
|
3931
|
+
HighsLp& lp = this->model_.lp_;
|
|
3932
|
+
for (HighsInt iObj = 0; iObj < num_linear_objective; iObj++) {
|
|
3933
|
+
HighsLinearObjective& multi_linear_objective =
|
|
3934
|
+
this->multi_linear_objective_[iObj];
|
|
3935
|
+
if (multi_linear_objective.coefficients.size() !=
|
|
3936
|
+
static_cast<size_t>(lp.num_col_)) {
|
|
3937
|
+
highsLogUser(options_.log_options, HighsLogType::kError,
|
|
3938
|
+
"Multiple linear objective coefficient vector %d has size "
|
|
3939
|
+
"incompatible with model\n",
|
|
3940
|
+
int(iObj));
|
|
3941
|
+
return HighsStatus::kError;
|
|
3942
|
+
}
|
|
3943
|
+
}
|
|
3944
|
+
|
|
3945
|
+
std::unique_ptr<std::stringstream> multi_objective_log;
|
|
3946
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
3947
|
+
"Solving with %d multiple linear objectives, %s\n",
|
|
3948
|
+
int(num_linear_objective),
|
|
3949
|
+
this->options_.blend_multi_objectives
|
|
3950
|
+
? "blending objectives by weight"
|
|
3951
|
+
: "using lexicographic optimization by priority");
|
|
3952
|
+
highsLogUser(
|
|
3953
|
+
options_.log_options, HighsLogType::kInfo,
|
|
3954
|
+
"Ix weight offset abs_tol rel_tol priority%s\n",
|
|
3955
|
+
lp.num_col_ < coeff_logging_size_limit ? " coefficients" : "");
|
|
3956
|
+
for (HighsInt iObj = 0; iObj < num_linear_objective; iObj++) {
|
|
3957
|
+
HighsLinearObjective& linear_objective =
|
|
3958
|
+
this->multi_linear_objective_[iObj];
|
|
3959
|
+
multi_objective_log =
|
|
3960
|
+
std::unique_ptr<std::stringstream>(new std::stringstream());
|
|
3961
|
+
*multi_objective_log << highsFormatToString(
|
|
3962
|
+
"%2d %11.6g %11.6g %11.6g %11.6g %11d ", int(iObj),
|
|
3963
|
+
linear_objective.weight, linear_objective.offset,
|
|
3964
|
+
linear_objective.abs_tolerance, linear_objective.rel_tolerance,
|
|
3965
|
+
int(linear_objective.priority));
|
|
3966
|
+
if (lp.num_col_ < coeff_logging_size_limit) {
|
|
3967
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
|
|
3968
|
+
*multi_objective_log << highsFormatToString(
|
|
3969
|
+
"%s c_{%1d} = %g", iCol == 0 ? "" : ",", int(iCol),
|
|
3970
|
+
linear_objective.coefficients[iCol]);
|
|
3971
|
+
}
|
|
3972
|
+
*multi_objective_log << "\n";
|
|
3973
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo, "%s",
|
|
3974
|
+
multi_objective_log->str().c_str());
|
|
3975
|
+
}
|
|
3976
|
+
// Solving with a different objective, but don't call
|
|
3977
|
+
// this->clearSolver() since this loses the current solution - that
|
|
3978
|
+
// may have been provided by the user (#2419). Just clear the dual
|
|
3979
|
+
// data.
|
|
3980
|
+
//
|
|
3981
|
+
this->clearSolverDualData();
|
|
3982
|
+
if (this->options_.blend_multi_objectives) {
|
|
3983
|
+
// Objectives are blended by weight and minimized
|
|
3984
|
+
lp.offset_ = 0;
|
|
3985
|
+
lp.col_cost_.assign(lp.num_col_, 0);
|
|
3986
|
+
for (HighsInt iObj = 0; iObj < num_linear_objective; iObj++) {
|
|
3987
|
+
HighsLinearObjective& multi_linear_objective =
|
|
3988
|
+
this->multi_linear_objective_[iObj];
|
|
3989
|
+
lp.offset_ +=
|
|
3990
|
+
multi_linear_objective.weight * multi_linear_objective.offset;
|
|
3991
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
|
|
3992
|
+
lp.col_cost_[iCol] += multi_linear_objective.weight *
|
|
3993
|
+
multi_linear_objective.coefficients[iCol];
|
|
3994
|
+
}
|
|
3995
|
+
lp.sense_ = ObjSense::kMinimize;
|
|
3996
|
+
|
|
3997
|
+
multi_objective_log =
|
|
3998
|
+
std::unique_ptr<std::stringstream>(new std::stringstream());
|
|
3999
|
+
*multi_objective_log << highsFormatToString(
|
|
4000
|
+
"Solving with blended objective");
|
|
4001
|
+
if (lp.num_col_ < coeff_logging_size_limit) {
|
|
4002
|
+
*multi_objective_log << highsFormatToString(
|
|
4003
|
+
": %s %g", lp.sense_ == ObjSense::kMinimize ? "min" : "max",
|
|
4004
|
+
lp.offset_);
|
|
4005
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
|
|
4006
|
+
*multi_objective_log << highsFormatToString(
|
|
4007
|
+
" + (%g) x[%d]", lp.col_cost_[iCol], int(iCol));
|
|
4008
|
+
}
|
|
4009
|
+
*multi_objective_log << "\n";
|
|
4010
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo, "%s",
|
|
4011
|
+
multi_objective_log->str().c_str());
|
|
4012
|
+
return this->optimizeModel();
|
|
4013
|
+
}
|
|
4014
|
+
|
|
4015
|
+
// Objectives are applied lexicographically
|
|
4016
|
+
if (model_.isQp() && num_linear_objective > 1) {
|
|
4017
|
+
// Lexicographic optimization with a single linear objective is
|
|
4018
|
+
// trivially standard optimization, so is OK
|
|
4019
|
+
highsLogUser(
|
|
4020
|
+
options_.log_options, HighsLogType::kError,
|
|
4021
|
+
"Cannot perform non-trivial lexicographic optimization for QP\n");
|
|
4022
|
+
return HighsStatus::kError;
|
|
4023
|
+
}
|
|
4024
|
+
// Check whether there are repeated linear objective priorities
|
|
4025
|
+
if (hasRepeatedLinearObjectivePriorities()) {
|
|
4026
|
+
highsLogUser(
|
|
4027
|
+
options_.log_options, HighsLogType::kError,
|
|
4028
|
+
"Repeated priorities for lexicographic optimization is illegal\n");
|
|
4029
|
+
return HighsStatus::kError;
|
|
4030
|
+
}
|
|
4031
|
+
std::vector<std::pair<HighsInt, HighsInt>> priority_objective;
|
|
4032
|
+
|
|
4033
|
+
for (HighsInt iObj = 0; iObj < num_linear_objective; iObj++)
|
|
4034
|
+
priority_objective.push_back(
|
|
4035
|
+
std::make_pair(this->multi_linear_objective_[iObj].priority, iObj));
|
|
4036
|
+
std::sort(priority_objective.begin(), priority_objective.end(), comparison);
|
|
4037
|
+
// Clear LP objective
|
|
4038
|
+
lp.offset_ = 0;
|
|
4039
|
+
lp.col_cost_.assign(lp.num_col_, 0);
|
|
4040
|
+
const HighsInt original_lp_num_row = lp.num_row_;
|
|
4041
|
+
std::vector<HighsInt> index(lp.num_col_);
|
|
4042
|
+
std::vector<double> value(lp.num_col_);
|
|
4043
|
+
// Use the solution of one MIP to provide an integer feasible
|
|
4044
|
+
// solution of the next
|
|
4045
|
+
HighsSolution solution;
|
|
4046
|
+
for (HighsInt iIx = 0; iIx < num_linear_objective; iIx++) {
|
|
4047
|
+
HighsInt priority = priority_objective[iIx].first;
|
|
4048
|
+
HighsInt iObj = priority_objective[iIx].second;
|
|
4049
|
+
// Use this objective
|
|
4050
|
+
HighsLinearObjective& linear_objective =
|
|
4051
|
+
this->multi_linear_objective_[iObj];
|
|
4052
|
+
lp.offset_ = linear_objective.offset;
|
|
4053
|
+
lp.col_cost_ = linear_objective.coefficients;
|
|
4054
|
+
lp.sense_ =
|
|
4055
|
+
linear_objective.weight > 0 ? ObjSense::kMinimize : ObjSense::kMaximize;
|
|
4056
|
+
if (lp.isMip() && solution.value_valid) {
|
|
4057
|
+
HighsStatus set_solution_status = this->setSolution(solution);
|
|
4058
|
+
if (set_solution_status == HighsStatus::kError) {
|
|
4059
|
+
highsLogUser(options_.log_options, HighsLogType::kError,
|
|
4060
|
+
"Failure to use one MIP to provide an integer feasible "
|
|
4061
|
+
"solution of the next\n");
|
|
4062
|
+
return returnFromLexicographicOptimization(HighsStatus::kError,
|
|
4063
|
+
original_lp_num_row);
|
|
4064
|
+
}
|
|
4065
|
+
bool valid, integral, feasible;
|
|
4066
|
+
HighsStatus assess_primal_solution =
|
|
4067
|
+
assessPrimalSolution(valid, integral, feasible);
|
|
4068
|
+
if (!valid || !integral || !feasible) {
|
|
4069
|
+
highsLogUser(options_.log_options, HighsLogType::kWarning,
|
|
4070
|
+
"Failure to use one MIP to provide an integer feasible "
|
|
4071
|
+
"solution of the next: "
|
|
4072
|
+
"status is valid = %s, integral = %s, feasible = %s\n",
|
|
4073
|
+
highsBoolToString(valid).c_str(),
|
|
4074
|
+
highsBoolToString(integral).c_str(),
|
|
4075
|
+
highsBoolToString(feasible).c_str());
|
|
4076
|
+
}
|
|
4077
|
+
}
|
|
4078
|
+
multi_objective_log =
|
|
4079
|
+
std::unique_ptr<std::stringstream>(new std::stringstream());
|
|
4080
|
+
*multi_objective_log << highsFormatToString("Solving with objective %d",
|
|
4081
|
+
int(iObj));
|
|
4082
|
+
if (lp.num_col_ < coeff_logging_size_limit) {
|
|
4083
|
+
*multi_objective_log << highsFormatToString(
|
|
4084
|
+
": %s %g", lp.sense_ == ObjSense::kMinimize ? "min" : "max",
|
|
4085
|
+
lp.offset_);
|
|
4086
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
|
|
4087
|
+
*multi_objective_log << highsFormatToString(
|
|
4088
|
+
" + (%g) x[%d]", lp.col_cost_[iCol], int(iCol));
|
|
4089
|
+
}
|
|
4090
|
+
*multi_objective_log << "\n";
|
|
4091
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo, "%s",
|
|
4092
|
+
multi_objective_log->str().c_str());
|
|
4093
|
+
HighsStatus optimize_model_status = this->optimizeModel();
|
|
4094
|
+
if (optimize_model_status == HighsStatus::kError)
|
|
4095
|
+
return returnFromLexicographicOptimization(HighsStatus::kError,
|
|
4096
|
+
original_lp_num_row);
|
|
4097
|
+
if (model_status_ != HighsModelStatus::kOptimal) {
|
|
4098
|
+
highsLogUser(options_.log_options, HighsLogType::kWarning,
|
|
4099
|
+
"After priority %d solve, model status is %s\n",
|
|
4100
|
+
int(priority), modelStatusToString(model_status_).c_str());
|
|
4101
|
+
return returnFromLexicographicOptimization(HighsStatus::kWarning,
|
|
4102
|
+
original_lp_num_row);
|
|
4103
|
+
}
|
|
4104
|
+
if (iIx == num_linear_objective - 1) break;
|
|
4105
|
+
if (lp.isMip()) {
|
|
4106
|
+
// Save the solution to provide an integer feasible solution of
|
|
4107
|
+
// the next MIP
|
|
4108
|
+
solution.col_value = this->solution_.col_value;
|
|
4109
|
+
solution.value_valid = true;
|
|
4110
|
+
}
|
|
4111
|
+
// Add the constraint
|
|
4112
|
+
HighsInt nnz = 0;
|
|
4113
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
4114
|
+
if (lp.col_cost_[iCol]) {
|
|
4115
|
+
index[nnz] = iCol;
|
|
4116
|
+
value[nnz] = lp.col_cost_[iCol];
|
|
4117
|
+
nnz++;
|
|
4118
|
+
}
|
|
4119
|
+
}
|
|
4120
|
+
double objective = info_.objective_function_value;
|
|
4121
|
+
HighsStatus add_row_status;
|
|
4122
|
+
double lower_bound = -kHighsInf;
|
|
4123
|
+
double upper_bound = kHighsInf;
|
|
4124
|
+
if (lp.sense_ == ObjSense::kMinimize) {
|
|
4125
|
+
// Minimizing, so set a greater upper bound than the objective
|
|
4126
|
+
if (linear_objective.abs_tolerance >= 0)
|
|
4127
|
+
upper_bound = objective + linear_objective.abs_tolerance;
|
|
4128
|
+
if (linear_objective.rel_tolerance >= 0) {
|
|
4129
|
+
if (objective >= 0) {
|
|
4130
|
+
// Guarantees objective of at least (1+t).f^*
|
|
4131
|
+
//
|
|
4132
|
+
// so ((1+t).f^*-f^*)/f^* = t
|
|
4133
|
+
upper_bound = std::min(
|
|
4134
|
+
objective * (1.0 + linear_objective.rel_tolerance), upper_bound);
|
|
4135
|
+
} else if (objective < 0) {
|
|
4136
|
+
// Guarantees objective of at least (1-t).f^*
|
|
4137
|
+
//
|
|
4138
|
+
// so ((1-t).f^*-f^*)/f^* = -t
|
|
4139
|
+
upper_bound = std::min(
|
|
4140
|
+
objective * (1.0 - linear_objective.rel_tolerance), upper_bound);
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
upper_bound -= lp.offset_;
|
|
4144
|
+
} else {
|
|
4145
|
+
// Maximizing, so set a lesser lower bound than the objective
|
|
4146
|
+
if (linear_objective.abs_tolerance >= 0)
|
|
4147
|
+
lower_bound = objective - linear_objective.abs_tolerance;
|
|
4148
|
+
if (linear_objective.rel_tolerance >= 0) {
|
|
4149
|
+
if (objective >= 0) {
|
|
4150
|
+
// Guarantees objective of at most (1-t).f^*
|
|
4151
|
+
//
|
|
4152
|
+
// so ((1-t).f^*-f^*)/f^* = -t
|
|
4153
|
+
lower_bound = std::max(
|
|
4154
|
+
objective * (1.0 - linear_objective.rel_tolerance), lower_bound);
|
|
4155
|
+
} else if (objective < 0) {
|
|
4156
|
+
// Guarantees objective of at least (1+t).f^*
|
|
4157
|
+
//
|
|
4158
|
+
// so ((1+t).f^*-f^*)/f^* = t
|
|
4159
|
+
lower_bound = std::max(
|
|
4160
|
+
objective * (1.0 + linear_objective.rel_tolerance), lower_bound);
|
|
4161
|
+
}
|
|
4162
|
+
}
|
|
4163
|
+
lower_bound -= lp.offset_;
|
|
4164
|
+
}
|
|
4165
|
+
if (lower_bound == -kHighsInf && upper_bound == kHighsInf)
|
|
4166
|
+
highsLogUser(options_.log_options, HighsLogType::kWarning,
|
|
4167
|
+
"After priority %d solve, no objective constraint due to "
|
|
4168
|
+
"absolute tolerance being %g < 0,"
|
|
4169
|
+
" and relative tolerance being %g < 0\n",
|
|
4170
|
+
int(priority), linear_objective.abs_tolerance,
|
|
4171
|
+
linear_objective.rel_tolerance);
|
|
4172
|
+
multi_objective_log =
|
|
4173
|
+
std::unique_ptr<std::stringstream>(new std::stringstream());
|
|
4174
|
+
*multi_objective_log << highsFormatToString(
|
|
4175
|
+
"Add constraint for objective %d: ", int(iObj));
|
|
4176
|
+
if (nnz < coeff_logging_size_limit) {
|
|
4177
|
+
*multi_objective_log << highsFormatToString("%g <= ", lower_bound);
|
|
4178
|
+
for (HighsInt iEl = 0; iEl < nnz; iEl++)
|
|
4179
|
+
*multi_objective_log << highsFormatToString(
|
|
4180
|
+
"%s(%g) x[%d]", iEl > 0 ? " + " : "", value[iEl], int(index[iEl]));
|
|
4181
|
+
*multi_objective_log << highsFormatToString(" <= %g\n", upper_bound);
|
|
4182
|
+
} else {
|
|
4183
|
+
*multi_objective_log << highsFormatToString("Bounds [%g, %g]\n",
|
|
4184
|
+
lower_bound, upper_bound);
|
|
4185
|
+
}
|
|
4186
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo, "%s",
|
|
4187
|
+
multi_objective_log->str().c_str());
|
|
4188
|
+
add_row_status =
|
|
4189
|
+
this->addRow(lower_bound, upper_bound, nnz, index.data(), value.data());
|
|
4190
|
+
assert(add_row_status == HighsStatus::kOk);
|
|
4191
|
+
}
|
|
4192
|
+
return returnFromLexicographicOptimization(HighsStatus::kOk,
|
|
4193
|
+
original_lp_num_row);
|
|
4194
|
+
}
|
|
4195
|
+
|
|
4196
|
+
bool Highs::tryPdlpCleanup(HighsInt& pdlp_cleanup_iteration_limit,
|
|
4197
|
+
const HighsInfo& presolved_lp_info) const {
|
|
4198
|
+
// Primal/dual infeasibilities/residuals can be magnified in
|
|
4199
|
+
// postsolve after PDLP, and IPX without crossover can fail,
|
|
4200
|
+
// both leading to model_status_ == HighsModelStatus::kUnknown.
|
|
4201
|
+
//
|
|
4202
|
+
// If the primal/dual infeasibilities/residuals are too large, then it's not
|
|
4203
|
+
// worth it, so measure this
|
|
4204
|
+
//
|
|
4205
|
+
const double tolerance_margin = 1e2;
|
|
4206
|
+
bool no_cleanup = false;
|
|
4207
|
+
double max_relative_violation = 0;
|
|
4208
|
+
// Lambda for updating no_cleanup and max_relative_violation
|
|
4209
|
+
auto noCleanup = [&](const std::string& kkt_name, const double kkt_error,
|
|
4210
|
+
const double kkt_tolerance) {
|
|
4211
|
+
double use_kkt_tolerance =
|
|
4212
|
+
this->options_.kkt_tolerance != kDefaultKktTolerance
|
|
4213
|
+
? this->options_.kkt_tolerance
|
|
4214
|
+
: kkt_tolerance;
|
|
4215
|
+
double relative_violation = kkt_error / use_kkt_tolerance;
|
|
4216
|
+
if (relative_violation > tolerance_margin)
|
|
4217
|
+
printf(
|
|
4218
|
+
"KKT measure (%11.4g, %11.4g) gives relative violation of %11.4g "
|
|
4219
|
+
"for "
|
|
4220
|
+
"%s\n",
|
|
4221
|
+
kkt_error, use_kkt_tolerance, relative_violation, kkt_name.c_str());
|
|
4222
|
+
max_relative_violation =
|
|
4223
|
+
std::max(relative_violation, max_relative_violation);
|
|
4224
|
+
no_cleanup = max_relative_violation > tolerance_margin;
|
|
4225
|
+
};
|
|
4226
|
+
noCleanup("Max relative primal infeasibility",
|
|
4227
|
+
this->info_.max_relative_primal_infeasibility,
|
|
4228
|
+
this->options_.primal_feasibility_tolerance);
|
|
4229
|
+
noCleanup("Max relative dual infeasibility",
|
|
4230
|
+
this->info_.max_relative_dual_infeasibility,
|
|
4231
|
+
this->options_.dual_feasibility_tolerance);
|
|
4232
|
+
noCleanup("Max relative primal residual error",
|
|
4233
|
+
this->info_.max_relative_primal_residual_error,
|
|
4234
|
+
this->options_.primal_residual_tolerance);
|
|
4235
|
+
noCleanup("Max relative dual residual error",
|
|
4236
|
+
this->info_.max_relative_dual_residual_error,
|
|
4237
|
+
this->options_.dual_residual_tolerance);
|
|
4238
|
+
noCleanup("Primal-dual objective error",
|
|
4239
|
+
this->info_.primal_dual_objective_error,
|
|
4240
|
+
this->options_.optimality_tolerance);
|
|
4241
|
+
if (no_cleanup) {
|
|
4242
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
4243
|
+
"No PDLP cleanup due to KKT errors exceeding tolerances by a "
|
|
4244
|
+
"max factor = %g > %g = allowed margin\n",
|
|
4245
|
+
max_relative_violation, tolerance_margin);
|
|
4246
|
+
return false;
|
|
4247
|
+
}
|
|
4248
|
+
//
|
|
4249
|
+
// Force PDLP to be used with an iteration limit
|
|
4250
|
+
if (presolved_lp_info.pdlp_iteration_count > 0) {
|
|
4251
|
+
// PDLP was used, so allow 10% of the iterations to clean up
|
|
4252
|
+
HighsInt ten_percent_pdlp_iteration_count =
|
|
4253
|
+
presolved_lp_info.pdlp_iteration_count / 10;
|
|
4254
|
+
pdlp_cleanup_iteration_limit =
|
|
4255
|
+
std::max(HighsInt(10000), ten_percent_pdlp_iteration_count);
|
|
4256
|
+
} else {
|
|
4257
|
+
// IPX without crossover was used, so can only guess what PDLP iteration
|
|
4258
|
+
// limit to use
|
|
4259
|
+
pdlp_cleanup_iteration_limit = 1000;
|
|
4260
|
+
}
|
|
4261
|
+
return true;
|
|
4262
|
+
}
|
|
4263
|
+
|
|
4264
|
+
void HighsLinearObjective::clear() {
|
|
4265
|
+
this->weight = 0.0;
|
|
4266
|
+
this->offset = 0.0;
|
|
4267
|
+
this->coefficients.clear();
|
|
4268
|
+
this->abs_tolerance = 0.0;
|
|
4269
|
+
this->rel_tolerance = 0.0;
|
|
4270
|
+
this->priority = 0;
|
|
4271
|
+
}
|
|
4272
|
+
|
|
4273
|
+
void HighsSubSolverCallTime::initialise() {
|
|
4274
|
+
this->num_call.assign(kSubSolverCount, 0);
|
|
4275
|
+
this->run_time.assign(kSubSolverCount, 0);
|
|
4276
|
+
this->name.assign(kSubSolverCount, "");
|
|
4277
|
+
this->name[kSubSolverDuSimplexBasis] = "Du simplex (basis)";
|
|
4278
|
+
this->name[kSubSolverDuSimplexNoBasis] = "Du simplex (no basis)";
|
|
4279
|
+
this->name[kSubSolverPrSimplexBasis] = "Pr simplex (basis)";
|
|
4280
|
+
this->name[kSubSolverPrSimplexNoBasis] = "Pr simplex (no basis)";
|
|
4281
|
+
this->name[kSubSolverHipo] = "HiPO";
|
|
4282
|
+
this->name[kSubSolverIpx] = "IPX";
|
|
4283
|
+
this->name[kSubSolverHipoAc] = "HiPO (AC)";
|
|
4284
|
+
this->name[kSubSolverIpxAc] = "IPX (AC)";
|
|
4285
|
+
this->name[kSubSolverPdlp] = "PDLP";
|
|
4286
|
+
this->name[kSubSolverQpAsm] = "QP ASM";
|
|
4287
|
+
this->name[kSubSolverMip] = "MIP";
|
|
4288
|
+
this->name[kSubSolverSubMip] = "Sub-MIP";
|
|
4289
|
+
}
|
|
4290
|
+
|
|
4291
|
+
void HighsSubSolverCallTime::add(
|
|
4292
|
+
const HighsSubSolverCallTime& sub_solver_call_time,
|
|
4293
|
+
const bool analytic_centre) {
|
|
4294
|
+
for (HighsInt Ix = 0; Ix < kSubSolverCount; Ix++) {
|
|
4295
|
+
HighsInt ToIx = Ix;
|
|
4296
|
+
if (Ix == kSubSolverHipo) {
|
|
4297
|
+
if (analytic_centre) ToIx = kSubSolverHipoAc;
|
|
4298
|
+
} else if (Ix == kSubSolverIpx) {
|
|
4299
|
+
if (analytic_centre) ToIx = kSubSolverIpxAc;
|
|
4300
|
+
}
|
|
4301
|
+
this->num_call[ToIx] += sub_solver_call_time.num_call[Ix];
|
|
4302
|
+
this->run_time[ToIx] += sub_solver_call_time.run_time[Ix];
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4305
|
+
|
|
4306
|
+
void Highs::reportSubSolverCallTime() const {
|
|
4307
|
+
double mip_time = this->sub_solver_call_time_.run_time[kSubSolverMip];
|
|
4308
|
+
std::stringstream ss;
|
|
4309
|
+
ss.str(std::string());
|
|
4310
|
+
ss << highsFormatToString(
|
|
4311
|
+
"\nSub-solver timing\nSolver Calls Time "
|
|
4312
|
+
"Time/call");
|
|
4313
|
+
if (mip_time > 0) ss << " MIP%";
|
|
4314
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo, "%s\n",
|
|
4315
|
+
ss.str().c_str());
|
|
4316
|
+
|
|
4317
|
+
double sum_mip_sub_solve_time = 0;
|
|
4318
|
+
for (HighsInt Ix = 0; Ix < kSubSolverCount; Ix++) {
|
|
4319
|
+
if (this->sub_solver_call_time_.num_call[Ix]) {
|
|
4320
|
+
ss.str(std::string());
|
|
4321
|
+
ss << highsFormatToString(
|
|
4322
|
+
"%-21s %9d %11.4e %11.4e",
|
|
4323
|
+
this->sub_solver_call_time_.name[Ix].c_str(),
|
|
4324
|
+
int(this->sub_solver_call_time_.num_call[Ix]),
|
|
4325
|
+
this->sub_solver_call_time_.run_time[Ix],
|
|
4326
|
+
this->sub_solver_call_time_.run_time[Ix] /
|
|
4327
|
+
(1.0 * this->sub_solver_call_time_.num_call[Ix]));
|
|
4328
|
+
if (mip_time > 0 && Ix != kSubSolverMip) {
|
|
4329
|
+
if (Ix != kSubSolverHipoAc && Ix != kSubSolverIpxAc)
|
|
4330
|
+
sum_mip_sub_solve_time += this->sub_solver_call_time_.run_time[Ix];
|
|
4331
|
+
ss << highsFormatToString(
|
|
4332
|
+
" %5.1f",
|
|
4333
|
+
1e2 * this->sub_solver_call_time_.run_time[Ix] / mip_time);
|
|
4334
|
+
}
|
|
4335
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo, "%s\n",
|
|
4336
|
+
ss.str().c_str());
|
|
4337
|
+
}
|
|
4338
|
+
}
|
|
4339
|
+
if (mip_time > 0)
|
|
4340
|
+
highsLogUser(options_.log_options, HighsLogType::kInfo,
|
|
4341
|
+
"TOTAL (excluding AC) %11.4e %5.1f\n",
|
|
4342
|
+
sum_mip_sub_solve_time,
|
|
4343
|
+
1e2 * sum_mip_sub_solve_time / mip_time);
|
|
4344
|
+
}
|