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,3794 @@
|
|
|
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/HighsUtils.cpp
|
|
9
|
+
* @brief Class-independent utilities for HiGHS
|
|
10
|
+
*/
|
|
11
|
+
#include "lp_data/HighsLpUtils.h"
|
|
12
|
+
|
|
13
|
+
#include <algorithm>
|
|
14
|
+
#include <cassert>
|
|
15
|
+
|
|
16
|
+
#include "HConfig.h"
|
|
17
|
+
#include "io/Filereader.h"
|
|
18
|
+
#include "io/HMPSIO.h"
|
|
19
|
+
#include "io/HighsIO.h"
|
|
20
|
+
#include "lp_data/HighsModelUtils.h"
|
|
21
|
+
#include "lp_data/HighsSolution.h"
|
|
22
|
+
#include "lp_data/HighsStatus.h"
|
|
23
|
+
#include "util/HighsCDouble.h"
|
|
24
|
+
#include "util/HighsMatrixUtils.h"
|
|
25
|
+
#include "util/HighsSort.h"
|
|
26
|
+
|
|
27
|
+
using std::fabs;
|
|
28
|
+
using std::max;
|
|
29
|
+
using std::min;
|
|
30
|
+
|
|
31
|
+
const HighsInt kMaxLineLength = 80;
|
|
32
|
+
|
|
33
|
+
HighsStatus assessLp(HighsLp& lp, const HighsOptions& options) {
|
|
34
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
35
|
+
HighsStatus call_status = lpDimensionsOk("assessLp", lp, options.log_options)
|
|
36
|
+
? HighsStatus::kOk
|
|
37
|
+
: HighsStatus::kError;
|
|
38
|
+
return_status = interpretCallStatus(options.log_options, call_status,
|
|
39
|
+
return_status, "assessLpDimensions");
|
|
40
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
41
|
+
|
|
42
|
+
if (lp.num_col_) {
|
|
43
|
+
// Assess the LP column costs
|
|
44
|
+
HighsIndexCollection index_collection;
|
|
45
|
+
index_collection.dimension_ = lp.num_col_;
|
|
46
|
+
index_collection.is_interval_ = true;
|
|
47
|
+
index_collection.from_ = 0;
|
|
48
|
+
index_collection.to_ = lp.num_col_ - 1;
|
|
49
|
+
call_status = assessCosts(options, 0, index_collection, lp.col_cost_,
|
|
50
|
+
lp.has_infinite_cost_, options.infinite_cost);
|
|
51
|
+
return_status = interpretCallStatus(options.log_options, call_status,
|
|
52
|
+
return_status, "assessCosts");
|
|
53
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
54
|
+
// Assess the LP column bounds
|
|
55
|
+
call_status = assessBounds(
|
|
56
|
+
options, "Col", 0, index_collection, lp.col_lower_, lp.col_upper_,
|
|
57
|
+
options.infinite_bound, lp.isMip() ? lp.integrality_.data() : nullptr);
|
|
58
|
+
return_status = interpretCallStatus(options.log_options, call_status,
|
|
59
|
+
return_status, "assessBounds");
|
|
60
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
61
|
+
}
|
|
62
|
+
if (lp.num_row_) {
|
|
63
|
+
// Assess the LP row bounds
|
|
64
|
+
HighsIndexCollection index_collection;
|
|
65
|
+
index_collection.dimension_ = lp.num_row_;
|
|
66
|
+
index_collection.is_interval_ = true;
|
|
67
|
+
index_collection.from_ = 0;
|
|
68
|
+
index_collection.to_ = lp.num_row_ - 1;
|
|
69
|
+
call_status =
|
|
70
|
+
assessBounds(options, "Row", 0, index_collection, lp.row_lower_,
|
|
71
|
+
lp.row_upper_, options.infinite_bound);
|
|
72
|
+
return_status = interpretCallStatus(options.log_options, call_status,
|
|
73
|
+
return_status, "assessBounds");
|
|
74
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
75
|
+
}
|
|
76
|
+
// If the LP has no columns the matrix must be empty and there is
|
|
77
|
+
// nothing left to test
|
|
78
|
+
if (lp.num_col_ == 0) {
|
|
79
|
+
assert(!lp.a_matrix_.numNz());
|
|
80
|
+
return HighsStatus::kOk;
|
|
81
|
+
}
|
|
82
|
+
// From here, any LP has lp.num_col_ > 0 and lp.a_matrix_.start_[lp.num_col_]
|
|
83
|
+
// exists (as the number of nonzeros)
|
|
84
|
+
assert(lp.num_col_ > 0);
|
|
85
|
+
|
|
86
|
+
// Assess the LP matrix - even if there are no rows!
|
|
87
|
+
call_status =
|
|
88
|
+
lp.a_matrix_.assess(options.log_options, "LP", options.small_matrix_value,
|
|
89
|
+
options.large_matrix_value);
|
|
90
|
+
return_status = interpretCallStatus(options.log_options, call_status,
|
|
91
|
+
return_status, "assessMatrix");
|
|
92
|
+
if (return_status == HighsStatus::kError) return return_status;
|
|
93
|
+
// If entries have been removed from the matrix, resize the index
|
|
94
|
+
// and value vectors to prevent bug in presolve
|
|
95
|
+
HighsInt lp_num_nz = lp.a_matrix_.numNz();
|
|
96
|
+
if ((HighsInt)lp.a_matrix_.index_.size() > lp_num_nz)
|
|
97
|
+
lp.a_matrix_.index_.resize(lp_num_nz);
|
|
98
|
+
if ((HighsInt)lp.a_matrix_.value_.size() > lp_num_nz)
|
|
99
|
+
lp.a_matrix_.value_.resize(lp_num_nz);
|
|
100
|
+
if (return_status != HighsStatus::kOk)
|
|
101
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
102
|
+
"assessLp returns HighsStatus = %s\n",
|
|
103
|
+
highsStatusToString(return_status).c_str());
|
|
104
|
+
return return_status;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
bool lpDimensionsOk(const std::string& message, const HighsLp& lp,
|
|
108
|
+
const HighsLogOptions& log_options) {
|
|
109
|
+
bool ok = true;
|
|
110
|
+
const HighsInt num_col = lp.num_col_;
|
|
111
|
+
const HighsInt num_row = lp.num_row_;
|
|
112
|
+
if (!(num_col >= 0))
|
|
113
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
114
|
+
"LP dimension validation (%s) fails on num_col = %d >= 0\n",
|
|
115
|
+
message.c_str(), (int)num_col);
|
|
116
|
+
ok = num_col >= 0 && ok;
|
|
117
|
+
if (!(num_row >= 0))
|
|
118
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
119
|
+
"LP dimension validation (%s) fails on num_row = %d >= 0\n",
|
|
120
|
+
message.c_str(), (int)num_row);
|
|
121
|
+
ok = num_row >= 0 && ok;
|
|
122
|
+
if (!ok) return ok;
|
|
123
|
+
|
|
124
|
+
HighsInt col_cost_size = lp.col_cost_.size();
|
|
125
|
+
HighsInt col_lower_size = lp.col_lower_.size();
|
|
126
|
+
HighsInt col_upper_size = lp.col_upper_.size();
|
|
127
|
+
bool legal_col_cost_size = col_cost_size >= num_col;
|
|
128
|
+
bool legal_col_lower_size = col_lower_size >= num_col;
|
|
129
|
+
bool legal_col_upper_size = col_upper_size >= num_col;
|
|
130
|
+
if (!legal_col_cost_size)
|
|
131
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
132
|
+
"LP dimension validation (%s) fails on col_cost.size() = %d < "
|
|
133
|
+
"%d = num_col\n",
|
|
134
|
+
message.c_str(), (int)col_cost_size, (int)num_col);
|
|
135
|
+
ok = legal_col_cost_size && ok;
|
|
136
|
+
if (!legal_col_lower_size)
|
|
137
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
138
|
+
"LP dimension validation (%s) fails on col_lower.size() = %d "
|
|
139
|
+
"< %d = num_col\n",
|
|
140
|
+
message.c_str(), (int)col_lower_size, (int)num_col);
|
|
141
|
+
ok = legal_col_lower_size && ok;
|
|
142
|
+
if (!legal_col_upper_size)
|
|
143
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
144
|
+
"LP dimension validation (%s) fails on col_upper.size() = %d "
|
|
145
|
+
"< %d = num_col\n",
|
|
146
|
+
message.c_str(), (int)col_upper_size, (int)num_col);
|
|
147
|
+
ok = legal_col_upper_size && ok;
|
|
148
|
+
|
|
149
|
+
bool legal_format = lp.a_matrix_.format_ == MatrixFormat::kColwise ||
|
|
150
|
+
lp.a_matrix_.format_ == MatrixFormat::kRowwise;
|
|
151
|
+
if (!legal_format)
|
|
152
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
153
|
+
"LP dimension validation (%s) fails on a_matrix_.format\n",
|
|
154
|
+
message.c_str());
|
|
155
|
+
ok = legal_format && ok;
|
|
156
|
+
HighsInt num_vec;
|
|
157
|
+
if (lp.a_matrix_.isColwise()) {
|
|
158
|
+
num_vec = num_col;
|
|
159
|
+
} else {
|
|
160
|
+
num_vec = num_row;
|
|
161
|
+
}
|
|
162
|
+
const bool partitioned = false;
|
|
163
|
+
vector<HighsInt> a_matrix_p_end;
|
|
164
|
+
bool legal_matrix_dimensions =
|
|
165
|
+
assessMatrixDimensions(log_options, num_vec, partitioned,
|
|
166
|
+
lp.a_matrix_.start_, a_matrix_p_end,
|
|
167
|
+
lp.a_matrix_.index_,
|
|
168
|
+
lp.a_matrix_.value_) == HighsStatus::kOk;
|
|
169
|
+
if (!legal_matrix_dimensions)
|
|
170
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
171
|
+
"LP dimension validation (%s) fails on a_matrix dimensions\n",
|
|
172
|
+
message.c_str());
|
|
173
|
+
ok = legal_matrix_dimensions && ok;
|
|
174
|
+
|
|
175
|
+
HighsInt row_lower_size = lp.row_lower_.size();
|
|
176
|
+
HighsInt row_upper_size = lp.row_upper_.size();
|
|
177
|
+
bool legal_row_lower_size = row_lower_size >= num_row;
|
|
178
|
+
bool legal_row_upper_size = row_upper_size >= num_row;
|
|
179
|
+
if (!legal_row_lower_size)
|
|
180
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
181
|
+
"LP dimension validation (%s) fails on row_lower.size() = %d "
|
|
182
|
+
"< %d = num_row\n",
|
|
183
|
+
message.c_str(), (int)row_lower_size, (int)num_row);
|
|
184
|
+
ok = legal_row_lower_size && ok;
|
|
185
|
+
if (!legal_row_upper_size)
|
|
186
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
187
|
+
"LP dimension validation (%s) fails on row_upper.size() = %d "
|
|
188
|
+
"< %d = num_row\n",
|
|
189
|
+
message.c_str(), (int)row_upper_size, (int)num_row);
|
|
190
|
+
ok = legal_row_upper_size && ok;
|
|
191
|
+
|
|
192
|
+
bool legal_a_matrix_num_col = lp.a_matrix_.num_col_ == num_col;
|
|
193
|
+
bool legal_a_matrix_num_row = lp.a_matrix_.num_row_ == num_row;
|
|
194
|
+
if (!legal_a_matrix_num_col)
|
|
195
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
196
|
+
"LP dimension validation (%s) fails on a_matrix.num_col_ = %d "
|
|
197
|
+
"!= %d = num_col\n",
|
|
198
|
+
message.c_str(), (int)lp.a_matrix_.num_col_, (int)num_col);
|
|
199
|
+
ok = legal_a_matrix_num_col && ok;
|
|
200
|
+
if (!legal_a_matrix_num_row)
|
|
201
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
202
|
+
"LP dimension validation (%s) fails on a_matrix.num_row_ = %d "
|
|
203
|
+
"!= %d = num_row\n",
|
|
204
|
+
message.c_str(), (int)lp.a_matrix_.num_row_, (int)num_row);
|
|
205
|
+
ok = legal_a_matrix_num_row && ok;
|
|
206
|
+
|
|
207
|
+
HighsInt scale_strategy = (HighsInt)lp.scale_.strategy;
|
|
208
|
+
bool legal_scale_strategy = scale_strategy >= 0;
|
|
209
|
+
if (!legal_scale_strategy)
|
|
210
|
+
highsLogUser(
|
|
211
|
+
log_options, HighsLogType::kError,
|
|
212
|
+
"LP dimension validation (%s) fails on scale_.scale_strategy\n",
|
|
213
|
+
message.c_str());
|
|
214
|
+
ok = legal_scale_strategy && ok;
|
|
215
|
+
HighsInt scale_row_size = (HighsInt)lp.scale_.row.size();
|
|
216
|
+
HighsInt scale_col_size = (HighsInt)lp.scale_.col.size();
|
|
217
|
+
bool legal_scale_num_col = false;
|
|
218
|
+
bool legal_scale_num_row = false;
|
|
219
|
+
bool legal_scale_row_size = false;
|
|
220
|
+
bool legal_scale_col_size = false;
|
|
221
|
+
if (lp.scale_.has_scaling) {
|
|
222
|
+
legal_scale_num_col = lp.scale_.num_col == num_col;
|
|
223
|
+
legal_scale_num_row = lp.scale_.num_row == num_row;
|
|
224
|
+
legal_scale_row_size = scale_row_size >= num_row;
|
|
225
|
+
legal_scale_col_size = scale_col_size >= num_col;
|
|
226
|
+
} else {
|
|
227
|
+
legal_scale_num_col = lp.scale_.num_col == 0;
|
|
228
|
+
legal_scale_num_row = lp.scale_.num_row == 0;
|
|
229
|
+
legal_scale_row_size = scale_row_size == 0;
|
|
230
|
+
legal_scale_col_size = scale_col_size == 0;
|
|
231
|
+
}
|
|
232
|
+
if (!legal_scale_num_col)
|
|
233
|
+
highsLogUser(
|
|
234
|
+
log_options, HighsLogType::kError,
|
|
235
|
+
"LP dimension validation (%s) fails on scale_.num_col = %d != %d\n",
|
|
236
|
+
message.c_str(), (int)lp.scale_.num_col,
|
|
237
|
+
(int)(lp.scale_.has_scaling ? num_col : 0));
|
|
238
|
+
ok = legal_scale_num_col && ok;
|
|
239
|
+
if (!legal_scale_num_row)
|
|
240
|
+
highsLogUser(
|
|
241
|
+
log_options, HighsLogType::kError,
|
|
242
|
+
"LP dimension validation (%s) fails on scale_.num_row = %d != %d\n",
|
|
243
|
+
message.c_str(), (int)lp.scale_.num_row,
|
|
244
|
+
(int)(lp.scale_.has_scaling ? num_row : 0));
|
|
245
|
+
ok = legal_scale_num_row && ok;
|
|
246
|
+
if (!legal_scale_col_size)
|
|
247
|
+
highsLogUser(
|
|
248
|
+
log_options, HighsLogType::kError,
|
|
249
|
+
"LP dimension validation (%s) fails on scale_.col.size() = %d %s %d\n",
|
|
250
|
+
message.c_str(), (int)scale_col_size,
|
|
251
|
+
lp.scale_.has_scaling ? ">=" : "==",
|
|
252
|
+
(int)(lp.scale_.has_scaling ? num_col : 0));
|
|
253
|
+
ok = legal_scale_col_size && ok;
|
|
254
|
+
if (!legal_scale_row_size)
|
|
255
|
+
highsLogUser(
|
|
256
|
+
log_options, HighsLogType::kError,
|
|
257
|
+
"LP dimension validation (%s) fails on scale_.row.size() = %d %s %d\n",
|
|
258
|
+
message.c_str(), (int)scale_row_size,
|
|
259
|
+
lp.scale_.has_scaling ? ">=" : "==",
|
|
260
|
+
(int)(lp.scale_.has_scaling ? num_row : 0));
|
|
261
|
+
ok = legal_scale_row_size && ok;
|
|
262
|
+
if (!ok) {
|
|
263
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
264
|
+
"LP dimension validation (%s) fails\n", message.c_str());
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return ok;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
HighsStatus assessCosts(const HighsOptions& options, const HighsInt ml_col_os,
|
|
271
|
+
const HighsIndexCollection& index_collection,
|
|
272
|
+
vector<double>& cost, bool& has_infinite_cost,
|
|
273
|
+
const double infinite_cost) {
|
|
274
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
275
|
+
assert(ok(index_collection));
|
|
276
|
+
HighsInt from_k;
|
|
277
|
+
HighsInt to_k;
|
|
278
|
+
limits(index_collection, from_k, to_k);
|
|
279
|
+
if (from_k > to_k) return return_status;
|
|
280
|
+
|
|
281
|
+
return_status = HighsStatus::kOk;
|
|
282
|
+
// Work through the data to be assessed.
|
|
283
|
+
//
|
|
284
|
+
// Loop is k \in [from_k...to_k) covering the entries in the
|
|
285
|
+
// interval, set or mask to be considered.
|
|
286
|
+
//
|
|
287
|
+
// For an interval or mask, these values of k are the columns to be
|
|
288
|
+
// considered in a local sense, as well as the entries in the
|
|
289
|
+
// cost data to be assessed
|
|
290
|
+
//
|
|
291
|
+
// For a set, these values of k are the indices in the set, from
|
|
292
|
+
// which the columns to be considered in a local sense are
|
|
293
|
+
// drawn. The entries in the cost data to be assessed correspond
|
|
294
|
+
// to the values of k
|
|
295
|
+
//
|
|
296
|
+
// Adding the value of ml_col_os to local_col yields the value of
|
|
297
|
+
// ml_col, being the column in a global (whole-model) sense. This is
|
|
298
|
+
// necessary when assessing the costs of columns being added to a
|
|
299
|
+
// model, since they are specified using an interval
|
|
300
|
+
// [0...num_new_col) which must be offset by the current number of
|
|
301
|
+
// columns in the model.
|
|
302
|
+
//
|
|
303
|
+
HighsInt local_col;
|
|
304
|
+
HighsInt usr_col = -1;
|
|
305
|
+
HighsInt num_infinite_cost = 0;
|
|
306
|
+
for (HighsInt k = from_k; k < to_k + 1; k++) {
|
|
307
|
+
if (index_collection.is_interval_ || index_collection.is_mask_) {
|
|
308
|
+
local_col = k;
|
|
309
|
+
} else {
|
|
310
|
+
local_col = index_collection.set_[k];
|
|
311
|
+
}
|
|
312
|
+
if (index_collection.is_interval_) {
|
|
313
|
+
usr_col++;
|
|
314
|
+
} else {
|
|
315
|
+
usr_col = k;
|
|
316
|
+
}
|
|
317
|
+
if (index_collection.is_mask_ && !index_collection.mask_[local_col])
|
|
318
|
+
continue;
|
|
319
|
+
if (cost[usr_col] >= infinite_cost) {
|
|
320
|
+
num_infinite_cost++;
|
|
321
|
+
cost[usr_col] = kHighsInf;
|
|
322
|
+
} else if (cost[usr_col] <= -infinite_cost) {
|
|
323
|
+
num_infinite_cost++;
|
|
324
|
+
cost[usr_col] = -kHighsInf;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (num_infinite_cost > 0) {
|
|
328
|
+
has_infinite_cost = true;
|
|
329
|
+
highsLogUser(options.log_options, HighsLogType::kInfo,
|
|
330
|
+
"%" HIGHSINT_FORMAT
|
|
331
|
+
" |cost| values greater than or equal to %12g are treated as "
|
|
332
|
+
"Infinity\n",
|
|
333
|
+
num_infinite_cost, infinite_cost);
|
|
334
|
+
}
|
|
335
|
+
return return_status;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
HighsStatus assessBounds(const HighsOptions& options, const char* type,
|
|
339
|
+
const HighsInt ml_ix_os,
|
|
340
|
+
const HighsIndexCollection& index_collection,
|
|
341
|
+
vector<double>& lower, vector<double>& upper,
|
|
342
|
+
const double infinite_bound,
|
|
343
|
+
const HighsVarType* integrality) {
|
|
344
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
345
|
+
assert(ok(index_collection));
|
|
346
|
+
HighsInt from_k;
|
|
347
|
+
HighsInt to_k;
|
|
348
|
+
limits(index_collection, from_k, to_k);
|
|
349
|
+
if (from_k > to_k) return HighsStatus::kOk;
|
|
350
|
+
|
|
351
|
+
return_status = HighsStatus::kOk;
|
|
352
|
+
bool error_found = false;
|
|
353
|
+
bool warning_found = false;
|
|
354
|
+
// Work through the data to be assessed.
|
|
355
|
+
//
|
|
356
|
+
// Loop is k \in [from_k...to_k) covering the entries in the
|
|
357
|
+
// interval, set or mask to be considered.
|
|
358
|
+
//
|
|
359
|
+
// For an interval or mask, these values of k are the row/column
|
|
360
|
+
// indices to be considered in a local sense, as well as the entries
|
|
361
|
+
// in the lower and upper bound data to be assessed
|
|
362
|
+
//
|
|
363
|
+
// For a set, these values of k are the indices in the set, from
|
|
364
|
+
// which the indices to be considered in a local sense are
|
|
365
|
+
// drawn. The entries in the lower and
|
|
366
|
+
// upper bound data to be assessed correspond to the values of
|
|
367
|
+
// k.
|
|
368
|
+
//
|
|
369
|
+
// Adding the value of ml_ix_os to local_ix yields the value of
|
|
370
|
+
// ml_ix, being the index in a global (whole-model) sense. This is
|
|
371
|
+
// necessary when assessing the bounds of rows/columns being added
|
|
372
|
+
// to a model, since they are specified using an interval
|
|
373
|
+
// [0...num_new_row/col) which must be offset by the current number
|
|
374
|
+
// of rows/columns (generically indices) in the model.
|
|
375
|
+
//
|
|
376
|
+
HighsInt num_infinite_lower_bound = 0;
|
|
377
|
+
HighsInt num_infinite_upper_bound = 0;
|
|
378
|
+
HighsInt local_ix;
|
|
379
|
+
HighsInt ml_ix;
|
|
380
|
+
HighsInt usr_ix = -1;
|
|
381
|
+
for (HighsInt k = from_k; k < to_k + 1; k++) {
|
|
382
|
+
if (index_collection.is_interval_ || index_collection.is_mask_) {
|
|
383
|
+
local_ix = k;
|
|
384
|
+
} else {
|
|
385
|
+
local_ix = index_collection.set_[k];
|
|
386
|
+
}
|
|
387
|
+
if (index_collection.is_interval_) {
|
|
388
|
+
usr_ix++;
|
|
389
|
+
} else {
|
|
390
|
+
usr_ix = k;
|
|
391
|
+
}
|
|
392
|
+
ml_ix = ml_ix_os + local_ix;
|
|
393
|
+
if (index_collection.is_mask_ && !index_collection.mask_[local_ix])
|
|
394
|
+
continue;
|
|
395
|
+
|
|
396
|
+
if (!highs_isInfinity(-lower[usr_ix])) {
|
|
397
|
+
// Check whether a finite lower bound will be treated as -Infinity
|
|
398
|
+
bool infinite_lower_bound = lower[usr_ix] <= -infinite_bound;
|
|
399
|
+
if (infinite_lower_bound) {
|
|
400
|
+
lower[usr_ix] = -kHighsInf;
|
|
401
|
+
num_infinite_lower_bound++;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (!highs_isInfinity(upper[usr_ix])) {
|
|
405
|
+
// Check whether a finite upper bound will be treated as Infinity
|
|
406
|
+
bool infinite_upper_bound = upper[usr_ix] >= infinite_bound;
|
|
407
|
+
if (infinite_upper_bound) {
|
|
408
|
+
upper[usr_ix] = kHighsInf;
|
|
409
|
+
num_infinite_upper_bound++;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
// Check that the lower bound does not exceed the upper bound
|
|
413
|
+
bool legalLowerUpperBound = lower[usr_ix] <= upper[usr_ix];
|
|
414
|
+
if (integrality) {
|
|
415
|
+
// Legal for semi-variables to have inconsistent bounds
|
|
416
|
+
if (integrality[usr_ix] == HighsVarType::kSemiContinuous ||
|
|
417
|
+
integrality[usr_ix] == HighsVarType::kSemiInteger)
|
|
418
|
+
legalLowerUpperBound = true;
|
|
419
|
+
}
|
|
420
|
+
if (!legalLowerUpperBound) {
|
|
421
|
+
// Leave inconsistent bounds to be used to deduce infeasibility
|
|
422
|
+
highsLogUser(options.log_options, HighsLogType::kWarning,
|
|
423
|
+
"%3s %12" HIGHSINT_FORMAT
|
|
424
|
+
" has inconsistent bounds [%12g, %12g]\n",
|
|
425
|
+
type, ml_ix, lower[usr_ix], upper[usr_ix]);
|
|
426
|
+
warning_found = true;
|
|
427
|
+
}
|
|
428
|
+
// Check that the lower bound is not as much as +Infinity
|
|
429
|
+
bool legalLowerBound = lower[usr_ix] < infinite_bound;
|
|
430
|
+
if (!legalLowerBound) {
|
|
431
|
+
highsLogUser(options.log_options, HighsLogType::kError,
|
|
432
|
+
"%3s %12" HIGHSINT_FORMAT
|
|
433
|
+
" has lower bound of %12g >= %12g\n",
|
|
434
|
+
type, ml_ix, lower[usr_ix], infinite_bound);
|
|
435
|
+
error_found = true;
|
|
436
|
+
}
|
|
437
|
+
// Check that the upper bound is not as little as -Infinity
|
|
438
|
+
bool legalUpperBound = upper[usr_ix] > -infinite_bound;
|
|
439
|
+
if (!legalUpperBound) {
|
|
440
|
+
highsLogUser(options.log_options, HighsLogType::kError,
|
|
441
|
+
"%3s %12" HIGHSINT_FORMAT
|
|
442
|
+
" has upper bound of %12g <= %12g\n",
|
|
443
|
+
type, ml_ix, upper[usr_ix], -infinite_bound);
|
|
444
|
+
error_found = true;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (num_infinite_lower_bound) {
|
|
448
|
+
highsLogUser(options.log_options, HighsLogType::kInfo,
|
|
449
|
+
"%3ss:%12" HIGHSINT_FORMAT
|
|
450
|
+
" lower bounds less than or equal to %12g are treated as "
|
|
451
|
+
"-Infinity\n",
|
|
452
|
+
type, num_infinite_lower_bound, -infinite_bound);
|
|
453
|
+
}
|
|
454
|
+
if (num_infinite_upper_bound) {
|
|
455
|
+
highsLogUser(options.log_options, HighsLogType::kInfo,
|
|
456
|
+
"%3ss:%12" HIGHSINT_FORMAT
|
|
457
|
+
" upper bounds greater than or equal to %12g are treated as "
|
|
458
|
+
"+Infinity\n",
|
|
459
|
+
type, num_infinite_upper_bound, infinite_bound);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (error_found)
|
|
463
|
+
return_status = HighsStatus::kError;
|
|
464
|
+
else if (warning_found)
|
|
465
|
+
return_status = HighsStatus::kWarning;
|
|
466
|
+
else
|
|
467
|
+
return_status = HighsStatus::kOk;
|
|
468
|
+
|
|
469
|
+
return return_status;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
HighsStatus assessSemiVariables(HighsLp& lp, const HighsOptions& options,
|
|
473
|
+
bool& made_semi_variable_mods) {
|
|
474
|
+
made_semi_variable_mods = false;
|
|
475
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
476
|
+
if (!lp.integrality_.size()) return return_status;
|
|
477
|
+
assert((HighsInt)lp.integrality_.size() == lp.num_col_);
|
|
478
|
+
HighsInt num_illegal_lower = 0;
|
|
479
|
+
HighsInt num_illegal_upper = 0;
|
|
480
|
+
HighsInt num_tightened_upper = 0;
|
|
481
|
+
HighsInt num_inconsistent_semi = 0;
|
|
482
|
+
HighsInt num_non_semi = 0;
|
|
483
|
+
HighsInt num_non_continuous_variables = 0;
|
|
484
|
+
const double kLowerBoundMu = 10.0;
|
|
485
|
+
|
|
486
|
+
std::vector<HighsInt>& save_non_semi_variable_index =
|
|
487
|
+
lp.mods_.save_non_semi_variable_index;
|
|
488
|
+
std::vector<HighsInt>& inconsistent_semi_variable_index =
|
|
489
|
+
lp.mods_.save_inconsistent_semi_variable_index;
|
|
490
|
+
std::vector<double>& inconsistent_semi_variable_lower_bound_value =
|
|
491
|
+
lp.mods_.save_inconsistent_semi_variable_lower_bound_value;
|
|
492
|
+
std::vector<double>& inconsistent_semi_variable_upper_bound_value =
|
|
493
|
+
lp.mods_.save_inconsistent_semi_variable_upper_bound_value;
|
|
494
|
+
std::vector<HighsVarType>& inconsistent_semi_variable_type =
|
|
495
|
+
lp.mods_.save_inconsistent_semi_variable_type;
|
|
496
|
+
|
|
497
|
+
std::vector<HighsInt>& tightened_semi_variable_upper_bound_index =
|
|
498
|
+
lp.mods_.save_tightened_semi_variable_upper_bound_index;
|
|
499
|
+
std::vector<double>& tightened_semi_variable_upper_bound_value =
|
|
500
|
+
lp.mods_.save_tightened_semi_variable_upper_bound_value;
|
|
501
|
+
|
|
502
|
+
assert(int(lp.mods_.save_inconsistent_semi_variable_index.size()) == 0);
|
|
503
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
504
|
+
if (lp.integrality_[iCol] == HighsVarType::kSemiContinuous ||
|
|
505
|
+
lp.integrality_[iCol] == HighsVarType::kSemiInteger) {
|
|
506
|
+
if (lp.col_lower_[iCol] > lp.col_upper_[iCol]) {
|
|
507
|
+
// Semi-variables with inconsistent bounds become continuous
|
|
508
|
+
// and fixed at zero
|
|
509
|
+
num_inconsistent_semi++;
|
|
510
|
+
inconsistent_semi_variable_index.push_back(iCol);
|
|
511
|
+
inconsistent_semi_variable_lower_bound_value.push_back(
|
|
512
|
+
lp.col_lower_[iCol]);
|
|
513
|
+
inconsistent_semi_variable_upper_bound_value.push_back(
|
|
514
|
+
lp.col_upper_[iCol]);
|
|
515
|
+
inconsistent_semi_variable_type.push_back(lp.integrality_[iCol]);
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
// Semi-variables with zero lower bound are not semi
|
|
519
|
+
if (lp.col_lower_[iCol] == 0) {
|
|
520
|
+
num_non_semi++;
|
|
521
|
+
save_non_semi_variable_index.push_back(iCol);
|
|
522
|
+
// Semi-integer become integer so still have a non-continuous variable
|
|
523
|
+
if (lp.integrality_[iCol] == HighsVarType::kSemiInteger)
|
|
524
|
+
num_non_continuous_variables++;
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
if (lp.col_lower_[iCol] < 0) {
|
|
528
|
+
// Semi-variables must have a positive lower bound
|
|
529
|
+
num_illegal_lower++;
|
|
530
|
+
} else if (lp.col_upper_[iCol] > kMaxSemiVariableUpper) {
|
|
531
|
+
// Semi-variables must have upper bound that's not too large,
|
|
532
|
+
// so see whether the limiting value is sufficiently larger than the
|
|
533
|
+
// lower bound
|
|
534
|
+
if (kLowerBoundMu * lp.col_lower_[iCol] > kMaxSemiVariableUpper) {
|
|
535
|
+
num_illegal_upper++;
|
|
536
|
+
} else {
|
|
537
|
+
// Record the upper bound change to be made later
|
|
538
|
+
tightened_semi_variable_upper_bound_index.push_back(iCol);
|
|
539
|
+
tightened_semi_variable_upper_bound_value.push_back(
|
|
540
|
+
kMaxSemiVariableUpper);
|
|
541
|
+
num_tightened_upper++;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
num_non_continuous_variables++;
|
|
545
|
+
} else if (lp.integrality_[iCol] == HighsVarType::kInteger) {
|
|
546
|
+
num_non_continuous_variables++;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
if (num_inconsistent_semi) {
|
|
550
|
+
highsLogUser(
|
|
551
|
+
options.log_options, HighsLogType::kWarning,
|
|
552
|
+
"%" HIGHSINT_FORMAT
|
|
553
|
+
" semi-continuous/integer variable(s) have inconsistent bounds "
|
|
554
|
+
"so are fixed at zero\n",
|
|
555
|
+
num_inconsistent_semi);
|
|
556
|
+
return_status = HighsStatus::kWarning;
|
|
557
|
+
}
|
|
558
|
+
if (num_non_semi) {
|
|
559
|
+
highsLogUser(options.log_options, HighsLogType::kWarning,
|
|
560
|
+
"%" HIGHSINT_FORMAT
|
|
561
|
+
" semi-continuous/integer variable(s) have zero lower bound "
|
|
562
|
+
"so are continuous/integer\n",
|
|
563
|
+
num_non_semi);
|
|
564
|
+
return_status = HighsStatus::kWarning;
|
|
565
|
+
}
|
|
566
|
+
if (!num_non_continuous_variables) {
|
|
567
|
+
highsLogUser(options.log_options, HighsLogType::kWarning,
|
|
568
|
+
"No semi-integer/integer variables in model with non-empty "
|
|
569
|
+
"integrality\n");
|
|
570
|
+
return_status = HighsStatus::kWarning;
|
|
571
|
+
}
|
|
572
|
+
const bool has_illegal_bounds = num_illegal_lower || num_illegal_upper;
|
|
573
|
+
if (num_tightened_upper) {
|
|
574
|
+
highsLogUser(options.log_options, HighsLogType::kWarning,
|
|
575
|
+
"%" HIGHSINT_FORMAT
|
|
576
|
+
" semi-continuous/integer variable(s) have upper bounds "
|
|
577
|
+
"exceeding %g that can be tightened to %g > %g*lower)\n",
|
|
578
|
+
num_tightened_upper, kMaxSemiVariableUpper,
|
|
579
|
+
kMaxSemiVariableUpper, kLowerBoundMu);
|
|
580
|
+
return_status = HighsStatus::kWarning;
|
|
581
|
+
if (has_illegal_bounds) {
|
|
582
|
+
// Don't apply upper bound tightenings if there are illegal bounds
|
|
583
|
+
assert(num_illegal_lower || num_illegal_upper);
|
|
584
|
+
tightened_semi_variable_upper_bound_index.clear();
|
|
585
|
+
tightened_semi_variable_upper_bound_value.clear();
|
|
586
|
+
num_tightened_upper = 0;
|
|
587
|
+
} else {
|
|
588
|
+
// Apply the upper bound tightenings, saving the over-written
|
|
589
|
+
// values
|
|
590
|
+
for (HighsInt k = 0; k < num_tightened_upper; k++) {
|
|
591
|
+
const double use_upper_bound =
|
|
592
|
+
tightened_semi_variable_upper_bound_value[k];
|
|
593
|
+
const HighsInt iCol = tightened_semi_variable_upper_bound_index[k];
|
|
594
|
+
tightened_semi_variable_upper_bound_value[k] = lp.col_upper_[iCol];
|
|
595
|
+
lp.col_upper_[iCol] = use_upper_bound;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
if (num_inconsistent_semi) {
|
|
600
|
+
if (has_illegal_bounds) {
|
|
601
|
+
// Don't apply bound changes if there are illegal bounds
|
|
602
|
+
inconsistent_semi_variable_index.clear();
|
|
603
|
+
inconsistent_semi_variable_lower_bound_value.clear();
|
|
604
|
+
inconsistent_semi_variable_upper_bound_value.clear();
|
|
605
|
+
inconsistent_semi_variable_type.clear();
|
|
606
|
+
num_inconsistent_semi = 0;
|
|
607
|
+
} else {
|
|
608
|
+
for (HighsInt k = 0; k < num_inconsistent_semi; k++) {
|
|
609
|
+
const HighsInt iCol = inconsistent_semi_variable_index[k];
|
|
610
|
+
lp.col_lower_[iCol] = 0;
|
|
611
|
+
lp.col_upper_[iCol] = 0;
|
|
612
|
+
lp.integrality_[iCol] = HighsVarType::kContinuous;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
if (num_non_semi) {
|
|
617
|
+
if (has_illegal_bounds) {
|
|
618
|
+
// Don't apply type changes if there are illegal bounds
|
|
619
|
+
save_non_semi_variable_index.clear();
|
|
620
|
+
} else {
|
|
621
|
+
for (HighsInt k = 0; k < num_non_semi; k++) {
|
|
622
|
+
const HighsInt iCol = save_non_semi_variable_index[k];
|
|
623
|
+
if (lp.integrality_[iCol] == HighsVarType::kSemiContinuous) {
|
|
624
|
+
// Semi-continuous become continuous
|
|
625
|
+
lp.integrality_[iCol] = HighsVarType::kContinuous;
|
|
626
|
+
} else {
|
|
627
|
+
// Semi-integer become integer
|
|
628
|
+
lp.integrality_[iCol] = HighsVarType::kInteger;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
if (num_illegal_lower) {
|
|
634
|
+
highsLogUser(
|
|
635
|
+
options.log_options, HighsLogType::kError,
|
|
636
|
+
"%" HIGHSINT_FORMAT
|
|
637
|
+
" semi-continuous/integer variable(s) have negative lower bounds\n",
|
|
638
|
+
num_illegal_lower);
|
|
639
|
+
return_status = HighsStatus::kError;
|
|
640
|
+
}
|
|
641
|
+
if (num_illegal_upper) {
|
|
642
|
+
highsLogUser(
|
|
643
|
+
options.log_options, HighsLogType::kError,
|
|
644
|
+
"%" HIGHSINT_FORMAT
|
|
645
|
+
" semi-continuous/integer variables have upper bounds "
|
|
646
|
+
"exceeding %g that cannot be modified due to large lower bounds\n",
|
|
647
|
+
num_illegal_upper, kMaxSemiVariableUpper);
|
|
648
|
+
return_status = HighsStatus::kError;
|
|
649
|
+
}
|
|
650
|
+
made_semi_variable_mods =
|
|
651
|
+
num_non_semi > 0 || num_inconsistent_semi > 0 || num_tightened_upper > 0;
|
|
652
|
+
assert(static_cast<size_t>(num_non_semi) <=
|
|
653
|
+
save_non_semi_variable_index.size());
|
|
654
|
+
assert(static_cast<size_t>(num_inconsistent_semi) <=
|
|
655
|
+
inconsistent_semi_variable_index.size());
|
|
656
|
+
assert(static_cast<size_t>(num_tightened_upper) <=
|
|
657
|
+
tightened_semi_variable_upper_bound_index.size());
|
|
658
|
+
// save_non_semi_variable_index.size() > 0 ||
|
|
659
|
+
// inconsistent_semi_variable_index.size() > 0 ||
|
|
660
|
+
// tightened_semi_variable_upper_bound_index.size() > 0;
|
|
661
|
+
return return_status;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
void relaxSemiVariables(HighsLp& lp, bool& made_semi_variable_mods) {
|
|
665
|
+
// When solving relaxation, semi-variables are continuous between 0
|
|
666
|
+
// and their upper bound, so have to modify the lower bound to be
|
|
667
|
+
// zero
|
|
668
|
+
made_semi_variable_mods = false;
|
|
669
|
+
if (!lp.integrality_.size()) return;
|
|
670
|
+
assert((HighsInt)lp.integrality_.size() == lp.num_col_);
|
|
671
|
+
std::vector<HighsInt>& relaxed_semi_variable_lower_index =
|
|
672
|
+
lp.mods_.save_relaxed_semi_variable_lower_bound_index;
|
|
673
|
+
std::vector<double>& relaxed_semi_variable_lower_value =
|
|
674
|
+
lp.mods_.save_relaxed_semi_variable_lower_bound_value;
|
|
675
|
+
assert(relaxed_semi_variable_lower_index.size() == 0);
|
|
676
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
677
|
+
if (lp.integrality_[iCol] == HighsVarType::kSemiContinuous ||
|
|
678
|
+
lp.integrality_[iCol] == HighsVarType::kSemiInteger) {
|
|
679
|
+
relaxed_semi_variable_lower_index.push_back(iCol);
|
|
680
|
+
relaxed_semi_variable_lower_value.push_back(lp.col_lower_[iCol]);
|
|
681
|
+
lp.col_lower_[iCol] = 0;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
made_semi_variable_mods = relaxed_semi_variable_lower_index.size() > 0;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
bool activeModifiedUpperBounds(const HighsOptions& options, const HighsLp& lp,
|
|
688
|
+
const std::vector<double>& col_value) {
|
|
689
|
+
const std::vector<HighsInt>& tightened_semi_variable_upper_bound_index =
|
|
690
|
+
lp.mods_.save_tightened_semi_variable_upper_bound_index;
|
|
691
|
+
const HighsInt num_tightened_upper =
|
|
692
|
+
tightened_semi_variable_upper_bound_index.size();
|
|
693
|
+
HighsInt num_active_modified_upper = 0;
|
|
694
|
+
double min_semi_variable_margin = kHighsInf;
|
|
695
|
+
for (HighsInt k = 0; k < num_tightened_upper; k++) {
|
|
696
|
+
const double value =
|
|
697
|
+
col_value[tightened_semi_variable_upper_bound_index[k]];
|
|
698
|
+
const double upper =
|
|
699
|
+
lp.col_upper_[tightened_semi_variable_upper_bound_index[k]];
|
|
700
|
+
double semi_variable_margin = upper - value;
|
|
701
|
+
if (value > upper - options.primal_feasibility_tolerance) {
|
|
702
|
+
min_semi_variable_margin = 0;
|
|
703
|
+
num_active_modified_upper++;
|
|
704
|
+
} else {
|
|
705
|
+
min_semi_variable_margin =
|
|
706
|
+
std::min(semi_variable_margin, min_semi_variable_margin);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
if (num_active_modified_upper) {
|
|
710
|
+
highsLogUser(options.log_options, HighsLogType::kError,
|
|
711
|
+
"%" HIGHSINT_FORMAT
|
|
712
|
+
" semi-variables are active at modified upper bounds\n",
|
|
713
|
+
num_active_modified_upper);
|
|
714
|
+
} else if (num_tightened_upper) {
|
|
715
|
+
highsLogUser(options.log_options, HighsLogType::kWarning,
|
|
716
|
+
"No semi-variables are active at modified upper bounds:"
|
|
717
|
+
" a large minimum margin (%g) suggests optimality,"
|
|
718
|
+
" but there is no guarantee\n",
|
|
719
|
+
min_semi_variable_margin);
|
|
720
|
+
}
|
|
721
|
+
return (num_active_modified_upper != 0);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
HighsStatus cleanBounds(const HighsOptions& options, HighsLp& lp) {
|
|
725
|
+
double max_residual = 0;
|
|
726
|
+
HighsInt num_change = 0;
|
|
727
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
728
|
+
double residual = lp.col_lower_[iCol] - lp.col_upper_[iCol];
|
|
729
|
+
if (residual > options.primal_feasibility_tolerance) {
|
|
730
|
+
highsLogUser(options.log_options, HighsLogType::kError,
|
|
731
|
+
"Column %" HIGHSINT_FORMAT
|
|
732
|
+
" has inconsistent bounds [%g, %g] (residual = "
|
|
733
|
+
"%g) after presolve\n",
|
|
734
|
+
iCol, lp.col_lower_[iCol], lp.col_upper_[iCol], residual);
|
|
735
|
+
return HighsStatus::kError;
|
|
736
|
+
} else if (residual > 0) {
|
|
737
|
+
num_change++;
|
|
738
|
+
max_residual = std::max(residual, max_residual);
|
|
739
|
+
double mid = 0.5 * (lp.col_lower_[iCol] + lp.col_upper_[iCol]);
|
|
740
|
+
lp.col_lower_[iCol] = mid;
|
|
741
|
+
lp.col_upper_[iCol] = mid;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
745
|
+
double residual = lp.row_lower_[iRow] - lp.row_upper_[iRow];
|
|
746
|
+
if (residual > options.primal_feasibility_tolerance) {
|
|
747
|
+
highsLogUser(options.log_options, HighsLogType::kError,
|
|
748
|
+
"Row %" HIGHSINT_FORMAT
|
|
749
|
+
" has inconsistent bounds [%g, %g] (residual = %g) "
|
|
750
|
+
"after presolve\n",
|
|
751
|
+
iRow, lp.row_lower_[iRow], lp.row_upper_[iRow], residual);
|
|
752
|
+
return HighsStatus::kError;
|
|
753
|
+
} else if (residual > 0) {
|
|
754
|
+
num_change++;
|
|
755
|
+
max_residual = std::max(residual, max_residual);
|
|
756
|
+
double mid = 0.5 * (lp.row_lower_[iRow] + lp.row_upper_[iRow]);
|
|
757
|
+
lp.row_lower_[iRow] = mid;
|
|
758
|
+
lp.row_upper_[iRow] = mid;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
if (num_change) {
|
|
762
|
+
highsLogUser(options.log_options, HighsLogType::kWarning,
|
|
763
|
+
"Resolved %" HIGHSINT_FORMAT
|
|
764
|
+
" inconsistent bounds (maximum residual = "
|
|
765
|
+
"%9.4g) after presolve\n",
|
|
766
|
+
num_change, max_residual);
|
|
767
|
+
return HighsStatus::kWarning;
|
|
768
|
+
}
|
|
769
|
+
return HighsStatus::kOk;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
HighsStatus userScaleLp(HighsLp& lp, HighsUserScaleData& data,
|
|
773
|
+
const HighsLogOptions& log_options) {
|
|
774
|
+
userScaleLp(lp, data, false);
|
|
775
|
+
HighsStatus return_status = userScaleStatus(log_options, data);
|
|
776
|
+
if (return_status == HighsStatus::kError) return HighsStatus::kError;
|
|
777
|
+
userScaleLp(lp, data);
|
|
778
|
+
return return_status;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
void userScaleLp(HighsLp& lp, HighsUserScaleData& data, const bool apply) {
|
|
782
|
+
userScaleCosts(lp.integrality_, lp.col_cost_, data, apply);
|
|
783
|
+
userScaleColBounds(lp.integrality_, lp.col_lower_, lp.col_upper_, data,
|
|
784
|
+
apply);
|
|
785
|
+
userScaleMatrix(lp.integrality_, lp.a_matrix_, data, apply);
|
|
786
|
+
userScaleRowBounds(lp.row_lower_, lp.row_upper_, data, apply);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
void userScaleCosts(const vector<HighsVarType>& integrality,
|
|
790
|
+
vector<double>& cost, HighsUserScaleData& data,
|
|
791
|
+
const bool apply) {
|
|
792
|
+
data.num_infinite_costs = 0;
|
|
793
|
+
const HighsInt user_bound_scale = data.user_bound_scale;
|
|
794
|
+
const HighsInt user_objective_scale = data.user_objective_scale;
|
|
795
|
+
if (!user_bound_scale && !user_objective_scale) return;
|
|
796
|
+
const HighsInt num_col = cost.size();
|
|
797
|
+
if (num_col <= 0) return;
|
|
798
|
+
const HighsInt integrality_size = HighsInt(integrality.size());
|
|
799
|
+
const bool has_integrality = integrality_size > 0;
|
|
800
|
+
double bound_scale_value = std::pow(2, user_bound_scale);
|
|
801
|
+
double objective_scale_value = std::pow(2, user_objective_scale);
|
|
802
|
+
assert(!has_integrality || integrality_size >= num_col);
|
|
803
|
+
for (HighsInt iCol = 0; iCol < num_col; iCol++) {
|
|
804
|
+
double value = cost[iCol];
|
|
805
|
+
if (has_integrality && integrality[iCol] != HighsVarType::kContinuous)
|
|
806
|
+
value *= bound_scale_value;
|
|
807
|
+
value *= objective_scale_value;
|
|
808
|
+
if (std::abs(value) > data.infinite_cost) data.num_infinite_costs++;
|
|
809
|
+
if (apply) cost[iCol] = value;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
void userScaleColBounds(const vector<HighsVarType>& integrality,
|
|
814
|
+
vector<double>& lower, vector<double>& upper,
|
|
815
|
+
HighsUserScaleData& data, const bool apply) {
|
|
816
|
+
data.num_infinite_col_bounds = 0;
|
|
817
|
+
const HighsInt user_bound_scale = data.user_bound_scale;
|
|
818
|
+
if (!user_bound_scale) return;
|
|
819
|
+
const HighsInt num_col = lower.size();
|
|
820
|
+
if (num_col <= 0) return;
|
|
821
|
+
const HighsInt integrality_size = HighsInt(integrality.size());
|
|
822
|
+
const bool has_integrality = integrality_size > 0;
|
|
823
|
+
assert(!has_integrality || integrality_size >= num_col);
|
|
824
|
+
double bound_scale_value = std::pow(2, user_bound_scale);
|
|
825
|
+
for (HighsInt iCol = 0; iCol < num_col; iCol++) {
|
|
826
|
+
if (!has_integrality || integrality[iCol] == HighsVarType::kContinuous) {
|
|
827
|
+
if (lower[iCol] > -kHighsInf) {
|
|
828
|
+
double value = lower[iCol] * bound_scale_value;
|
|
829
|
+
if (std::abs(value) > data.infinite_bound)
|
|
830
|
+
data.num_infinite_col_bounds++;
|
|
831
|
+
if (apply) lower[iCol] = value;
|
|
832
|
+
}
|
|
833
|
+
if (upper[iCol] < kHighsInf) {
|
|
834
|
+
double value = upper[iCol] * bound_scale_value;
|
|
835
|
+
if (std::abs(value) > data.infinite_bound)
|
|
836
|
+
data.num_infinite_col_bounds++;
|
|
837
|
+
if (apply) upper[iCol] = value;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
void userScaleRowBounds(vector<double>& lower, vector<double>& upper,
|
|
844
|
+
HighsUserScaleData& data, const bool apply) {
|
|
845
|
+
data.num_infinite_row_bounds = 0;
|
|
846
|
+
const HighsInt user_bound_scale = data.user_bound_scale;
|
|
847
|
+
if (!user_bound_scale) return;
|
|
848
|
+
const HighsInt num_row = lower.size();
|
|
849
|
+
if (num_row <= 0) return;
|
|
850
|
+
double bound_scale_value = std::pow(2, user_bound_scale);
|
|
851
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
852
|
+
if (lower[iRow] > -kHighsInf) {
|
|
853
|
+
double value = lower[iRow] * bound_scale_value;
|
|
854
|
+
if (std::abs(value) > data.infinite_bound) data.num_infinite_row_bounds++;
|
|
855
|
+
if (apply) lower[iRow] = value;
|
|
856
|
+
}
|
|
857
|
+
if (upper[iRow] < kHighsInf) {
|
|
858
|
+
double value = upper[iRow] * bound_scale_value;
|
|
859
|
+
if (std::abs(value) > data.infinite_bound) data.num_infinite_row_bounds++;
|
|
860
|
+
if (apply) upper[iRow] = value;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
void userScaleMatrix(const vector<HighsVarType>& integrality,
|
|
866
|
+
HighsSparseMatrix& matrix, HighsUserScaleData& data,
|
|
867
|
+
const bool apply) {
|
|
868
|
+
data.num_small_matrix_values = 0;
|
|
869
|
+
data.num_large_matrix_values = 0;
|
|
870
|
+
const HighsInt user_bound_scale = data.user_bound_scale;
|
|
871
|
+
if (!user_bound_scale) return;
|
|
872
|
+
if (!integrality.size()) return;
|
|
873
|
+
const HighsInt num_col = matrix.num_col_;
|
|
874
|
+
if (num_col <= 0) return;
|
|
875
|
+
const HighsInt num_row = matrix.num_row_;
|
|
876
|
+
if (num_row <= 0) return;
|
|
877
|
+
assert(HighsInt(integrality.size()) >= num_col);
|
|
878
|
+
double bound_scale_value = std::pow(2, user_bound_scale);
|
|
879
|
+
if (matrix.isColwise()) {
|
|
880
|
+
for (HighsInt iCol = 0; iCol < num_col; iCol++) {
|
|
881
|
+
if (integrality[iCol] == HighsVarType::kContinuous) continue;
|
|
882
|
+
for (HighsInt iEl = matrix.start_[iCol]; iEl < matrix.start_[iCol + 1];
|
|
883
|
+
iEl++) {
|
|
884
|
+
double value = matrix.value_[iEl] * bound_scale_value;
|
|
885
|
+
double abs_value = std::fabs(value);
|
|
886
|
+
if (abs_value <= data.small_matrix_value)
|
|
887
|
+
data.num_small_matrix_values++;
|
|
888
|
+
else if (abs_value >= data.large_matrix_value)
|
|
889
|
+
data.num_large_matrix_values++;
|
|
890
|
+
if (apply) matrix.value_[iEl] = value;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
} else {
|
|
894
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
895
|
+
for (HighsInt iEl = matrix.start_[iRow]; iEl < matrix.start_[iRow + 1];
|
|
896
|
+
iEl++) {
|
|
897
|
+
HighsInt iCol = matrix.index_[iEl];
|
|
898
|
+
if (integrality[iCol] == HighsVarType::kContinuous) continue;
|
|
899
|
+
double value = matrix.value_[iEl] * bound_scale_value;
|
|
900
|
+
double abs_value = std::fabs(value);
|
|
901
|
+
if (abs_value <= data.small_matrix_value)
|
|
902
|
+
data.num_small_matrix_values++;
|
|
903
|
+
else if (abs_value >= data.large_matrix_value)
|
|
904
|
+
data.num_large_matrix_values++;
|
|
905
|
+
if (apply) matrix.value_[iEl] = value;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
HighsStatus userScaleStatus(const HighsLogOptions& log_options,
|
|
912
|
+
const HighsUserScaleData& data) {
|
|
913
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
914
|
+
std::string message;
|
|
915
|
+
if (data.scaleWarning(message)) {
|
|
916
|
+
highsLogUser(log_options, HighsLogType::kWarning, "%s\n", message.c_str());
|
|
917
|
+
return_status = HighsStatus::kWarning;
|
|
918
|
+
}
|
|
919
|
+
if (data.scaleError(message)) {
|
|
920
|
+
highsLogUser(log_options, HighsLogType::kError, "%s\n", message.c_str());
|
|
921
|
+
return_status = HighsStatus::kError;
|
|
922
|
+
}
|
|
923
|
+
return return_status;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
bool considerScaling(const HighsOptions& options, HighsLp& lp) {
|
|
927
|
+
// Indicate whether new scaling has been determined in the return value.
|
|
928
|
+
bool new_scaling = false;
|
|
929
|
+
// Consider scaling the LP - either by finding new factors or by
|
|
930
|
+
// applying any existing factors
|
|
931
|
+
const bool allow_scaling =
|
|
932
|
+
lp.num_col_ > 0 &&
|
|
933
|
+
options.simplex_scale_strategy != kSimplexScaleStrategyOff;
|
|
934
|
+
if (lp.scale_.has_scaling && !allow_scaling) {
|
|
935
|
+
// LP had scaling before, but now it is not permitted, clear any
|
|
936
|
+
// scaling. Return true as scaling position has changed
|
|
937
|
+
lp.clearScale();
|
|
938
|
+
return true;
|
|
939
|
+
}
|
|
940
|
+
const bool scaling_not_tried = lp.scale_.strategy == kSimplexScaleStrategyOff;
|
|
941
|
+
const bool new_scaling_strategy =
|
|
942
|
+
options.simplex_scale_strategy != lp.scale_.strategy &&
|
|
943
|
+
options.simplex_scale_strategy != kSimplexScaleStrategyChoose;
|
|
944
|
+
const bool try_scaling =
|
|
945
|
+
allow_scaling && (scaling_not_tried || new_scaling_strategy);
|
|
946
|
+
if (try_scaling) {
|
|
947
|
+
// Scaling will be tried, so ensure that any previous scaling is not applied
|
|
948
|
+
lp.unapplyScale();
|
|
949
|
+
const bool analyse_lp_data =
|
|
950
|
+
kHighsAnalysisLevelModelData & options.highs_analysis_level;
|
|
951
|
+
if (analyse_lp_data) analyseLp(options.log_options, lp);
|
|
952
|
+
scaleLp(options, lp);
|
|
953
|
+
// If the LP is now scaled, then the scaling is new
|
|
954
|
+
new_scaling = lp.is_scaled_;
|
|
955
|
+
if (analyse_lp_data && lp.is_scaled_) analyseLp(options.log_options, lp);
|
|
956
|
+
} else if (lp.scale_.has_scaling) {
|
|
957
|
+
// Scaling factors are known, so ensure that they are applied
|
|
958
|
+
lp.applyScale();
|
|
959
|
+
}
|
|
960
|
+
// Ensure that either the LP has scale factors and is scaled, or
|
|
961
|
+
// it doesn't have scale factors and isn't scaled
|
|
962
|
+
assert(lp.scale_.has_scaling == lp.is_scaled_);
|
|
963
|
+
return new_scaling;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
void scaleLp(const HighsOptions& options, HighsLp& lp,
|
|
967
|
+
const bool force_scaling) {
|
|
968
|
+
lp.clearScaling();
|
|
969
|
+
HighsInt numCol = lp.num_col_;
|
|
970
|
+
HighsInt numRow = lp.num_row_;
|
|
971
|
+
// Scaling not well defined for models with no columns
|
|
972
|
+
assert(numCol > 0);
|
|
973
|
+
vector<double>& colCost = lp.col_cost_;
|
|
974
|
+
vector<double>& colLower = lp.col_lower_;
|
|
975
|
+
vector<double>& colUpper = lp.col_upper_;
|
|
976
|
+
vector<double>& rowLower = lp.row_lower_;
|
|
977
|
+
vector<double>& rowUpper = lp.row_upper_;
|
|
978
|
+
|
|
979
|
+
// Save the simplex_scale_strategy so that the option can be
|
|
980
|
+
// modified for the course of this method
|
|
981
|
+
HighsInt simplex_scale_strategy = options.simplex_scale_strategy;
|
|
982
|
+
// Determine the actual strategy to use
|
|
983
|
+
HighsInt use_scale_strategy = simplex_scale_strategy;
|
|
984
|
+
if (use_scale_strategy == kSimplexScaleStrategyChoose) {
|
|
985
|
+
// HiGHS is left to choose: currently use forced equilibration, but maybe do
|
|
986
|
+
// something more intelligent
|
|
987
|
+
use_scale_strategy = kSimplexScaleStrategyForcedEquilibration;
|
|
988
|
+
}
|
|
989
|
+
// Find out range of matrix values and skip matrix scaling if all
|
|
990
|
+
// |values| are in [0.2, 5]
|
|
991
|
+
const double no_scaling_original_matrix_min_value = 0.2;
|
|
992
|
+
const double no_scaling_original_matrix_max_value = 5.0;
|
|
993
|
+
double original_matrix_min_value = kHighsInf;
|
|
994
|
+
double original_matrix_max_value = 0;
|
|
995
|
+
lp.a_matrix_.range(original_matrix_min_value, original_matrix_max_value);
|
|
996
|
+
// Possibly force scaling, otherwise base the decision on the range
|
|
997
|
+
// of values in the matrix, values that will be used later for
|
|
998
|
+
// reporting
|
|
999
|
+
const bool no_scaling = force_scaling
|
|
1000
|
+
? false
|
|
1001
|
+
: (original_matrix_min_value >=
|
|
1002
|
+
no_scaling_original_matrix_min_value) &&
|
|
1003
|
+
(original_matrix_max_value <=
|
|
1004
|
+
no_scaling_original_matrix_max_value);
|
|
1005
|
+
bool scaled_matrix = false;
|
|
1006
|
+
if (no_scaling) {
|
|
1007
|
+
// No matrix scaling, but possible cost scaling
|
|
1008
|
+
if (options.highs_analysis_level)
|
|
1009
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
1010
|
+
"Scaling: Matrix has [min, max] values of [%g, %g] within "
|
|
1011
|
+
"[%g, %g] so no scaling performed\n",
|
|
1012
|
+
original_matrix_min_value, original_matrix_max_value,
|
|
1013
|
+
no_scaling_original_matrix_min_value,
|
|
1014
|
+
no_scaling_original_matrix_max_value);
|
|
1015
|
+
} else {
|
|
1016
|
+
// Try scaling, so assign unit factors - partly because initial
|
|
1017
|
+
// factors may be assumed by the scaling method, but also because
|
|
1018
|
+
// scaling factors may not be computed for empty rows/columns
|
|
1019
|
+
HighsScale& scale = lp.scale_;
|
|
1020
|
+
scale.col.assign(numCol, 1);
|
|
1021
|
+
scale.row.assign(numRow, 1);
|
|
1022
|
+
const bool equilibration_scaling =
|
|
1023
|
+
use_scale_strategy == kSimplexScaleStrategyEquilibration ||
|
|
1024
|
+
use_scale_strategy == kSimplexScaleStrategyForcedEquilibration;
|
|
1025
|
+
// Try scaling. Value of scaled_matrix indicates whether scaling
|
|
1026
|
+
// was considered valuable (and performed). If it's not valuable
|
|
1027
|
+
// then the matrix remains unscaled
|
|
1028
|
+
if (equilibration_scaling) {
|
|
1029
|
+
scaled_matrix = equilibrationScaleMatrix(options, lp, use_scale_strategy);
|
|
1030
|
+
} else {
|
|
1031
|
+
scaled_matrix = maxValueScaleMatrix(options, lp, use_scale_strategy);
|
|
1032
|
+
}
|
|
1033
|
+
if (scaled_matrix) {
|
|
1034
|
+
// Matrix is scaled, so scale the bounds and costs
|
|
1035
|
+
for (HighsInt iCol = 0; iCol < numCol; iCol++) {
|
|
1036
|
+
colLower[iCol] /= scale.col[iCol];
|
|
1037
|
+
colUpper[iCol] /= scale.col[iCol];
|
|
1038
|
+
colCost[iCol] *= scale.col[iCol];
|
|
1039
|
+
}
|
|
1040
|
+
for (HighsInt iRow = 0; iRow < numRow; iRow++) {
|
|
1041
|
+
rowLower[iRow] *= scale.row[iRow];
|
|
1042
|
+
rowUpper[iRow] *= scale.row[iRow];
|
|
1043
|
+
}
|
|
1044
|
+
scale.has_scaling = true;
|
|
1045
|
+
scale.num_col = numCol;
|
|
1046
|
+
scale.num_row = numRow;
|
|
1047
|
+
scale.cost = 1.0;
|
|
1048
|
+
lp.is_scaled_ = true;
|
|
1049
|
+
} else {
|
|
1050
|
+
// Matrix is not scaled, so clear the scaling
|
|
1051
|
+
lp.clearScaling();
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
// Record the scaling strategy used
|
|
1055
|
+
lp.scale_.strategy = use_scale_strategy;
|
|
1056
|
+
// Possibly scale the costs
|
|
1057
|
+
// if (allow_cost_scaling) scaleSimplexCost(options, lp, scale.cost);
|
|
1058
|
+
|
|
1059
|
+
// If matrix is unscaled, then LP is only scaled if there is a cost scaling
|
|
1060
|
+
// factor
|
|
1061
|
+
// if (!scaled_matrix) lp.is_scaled_ = scale.cost != 1;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
bool equilibrationScaleMatrix(const HighsOptions& options, HighsLp& lp,
|
|
1065
|
+
const HighsInt use_scale_strategy) {
|
|
1066
|
+
HighsInt numCol = lp.num_col_;
|
|
1067
|
+
HighsInt numRow = lp.num_row_;
|
|
1068
|
+
HighsScale& scale = lp.scale_;
|
|
1069
|
+
vector<double>& colScale = scale.col;
|
|
1070
|
+
vector<double>& rowScale = scale.row;
|
|
1071
|
+
vector<HighsInt>& Astart = lp.a_matrix_.start_;
|
|
1072
|
+
vector<HighsInt>& Aindex = lp.a_matrix_.index_;
|
|
1073
|
+
vector<double>& Avalue = lp.a_matrix_.value_;
|
|
1074
|
+
vector<double>& colCost = lp.col_cost_;
|
|
1075
|
+
|
|
1076
|
+
HighsInt simplex_scale_strategy = use_scale_strategy;
|
|
1077
|
+
|
|
1078
|
+
double original_matrix_min_value = kHighsInf;
|
|
1079
|
+
double original_matrix_max_value = 0;
|
|
1080
|
+
for (HighsInt k = 0, AnX = Astart[numCol]; k < AnX; k++) {
|
|
1081
|
+
double value = fabs(Avalue[k]);
|
|
1082
|
+
original_matrix_min_value = min(original_matrix_min_value, value);
|
|
1083
|
+
original_matrix_max_value = max(original_matrix_max_value, value);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// Include cost in scaling if minimum nonzero cost is less than 0.1
|
|
1087
|
+
double min_nonzero_cost = kHighsInf;
|
|
1088
|
+
for (HighsInt i = 0; i < numCol; i++) {
|
|
1089
|
+
if (colCost[i]) min_nonzero_cost = min(fabs(colCost[i]), min_nonzero_cost);
|
|
1090
|
+
}
|
|
1091
|
+
bool include_cost_in_scaling = false;
|
|
1092
|
+
include_cost_in_scaling = min_nonzero_cost < 0.1;
|
|
1093
|
+
|
|
1094
|
+
// Limits on scaling factors
|
|
1095
|
+
double max_allow_scale;
|
|
1096
|
+
double min_allow_scale;
|
|
1097
|
+
// Now that kHighsInf =
|
|
1098
|
+
// std::numeric_limits<double>::infinity(), this Qi-trick doesn't
|
|
1099
|
+
// work so, in recognition, use the old value of kHighsInf
|
|
1100
|
+
const double finite_infinity = 1e200;
|
|
1101
|
+
max_allow_scale = pow(2.0, options.allowed_matrix_scale_factor);
|
|
1102
|
+
min_allow_scale = 1 / max_allow_scale;
|
|
1103
|
+
|
|
1104
|
+
double min_allow_col_scale = min_allow_scale;
|
|
1105
|
+
double max_allow_col_scale = max_allow_scale;
|
|
1106
|
+
double min_allow_row_scale = min_allow_scale;
|
|
1107
|
+
double max_allow_row_scale = max_allow_scale;
|
|
1108
|
+
|
|
1109
|
+
// Search up to 6 times
|
|
1110
|
+
vector<double> row_min_value(numRow, finite_infinity);
|
|
1111
|
+
vector<double> row_max_value(numRow, 1 / finite_infinity);
|
|
1112
|
+
for (HighsInt search_count = 0; search_count < 6; search_count++) {
|
|
1113
|
+
// Find column scale, prepare row data
|
|
1114
|
+
for (HighsInt iCol = 0; iCol < numCol; iCol++) {
|
|
1115
|
+
// For column scale (find)
|
|
1116
|
+
double col_min_value = finite_infinity;
|
|
1117
|
+
double col_max_value = 1 / finite_infinity;
|
|
1118
|
+
double abs_col_cost = fabs(colCost[iCol]);
|
|
1119
|
+
if (include_cost_in_scaling && abs_col_cost != 0) {
|
|
1120
|
+
col_min_value = min(col_min_value, abs_col_cost);
|
|
1121
|
+
col_max_value = max(col_max_value, abs_col_cost);
|
|
1122
|
+
}
|
|
1123
|
+
for (HighsInt k = Astart[iCol]; k < Astart[iCol + 1]; k++) {
|
|
1124
|
+
double value = fabs(Avalue[k]) * rowScale[Aindex[k]];
|
|
1125
|
+
col_min_value = min(col_min_value, value);
|
|
1126
|
+
col_max_value = max(col_max_value, value);
|
|
1127
|
+
}
|
|
1128
|
+
double col_equilibration = 1 / sqrt(col_min_value * col_max_value);
|
|
1129
|
+
// Ensure that column scale factor is not excessively large or small
|
|
1130
|
+
colScale[iCol] =
|
|
1131
|
+
min(max(min_allow_col_scale, col_equilibration), max_allow_col_scale);
|
|
1132
|
+
// For row scale (only collect)
|
|
1133
|
+
for (HighsInt k = Astart[iCol]; k < Astart[iCol + 1]; k++) {
|
|
1134
|
+
HighsInt iRow = Aindex[k];
|
|
1135
|
+
double value = fabs(Avalue[k]) * colScale[iCol];
|
|
1136
|
+
row_min_value[iRow] = min(row_min_value[iRow], value);
|
|
1137
|
+
row_max_value[iRow] = max(row_max_value[iRow], value);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
// For row scale (find)
|
|
1141
|
+
for (HighsInt iRow = 0; iRow < numRow; iRow++) {
|
|
1142
|
+
double row_equilibration =
|
|
1143
|
+
1 / sqrt(row_min_value[iRow] * row_max_value[iRow]);
|
|
1144
|
+
// Ensure that row scale factor is not excessively large or small
|
|
1145
|
+
rowScale[iRow] =
|
|
1146
|
+
min(max(min_allow_row_scale, row_equilibration), max_allow_row_scale);
|
|
1147
|
+
}
|
|
1148
|
+
row_min_value.assign(numRow, finite_infinity);
|
|
1149
|
+
row_max_value.assign(numRow, 1 / finite_infinity);
|
|
1150
|
+
}
|
|
1151
|
+
// Make it numerically better
|
|
1152
|
+
// Also determine the max and min row and column scaling factors
|
|
1153
|
+
double min_col_scale = finite_infinity;
|
|
1154
|
+
double max_col_scale = 1 / finite_infinity;
|
|
1155
|
+
double min_row_scale = finite_infinity;
|
|
1156
|
+
double max_row_scale = 1 / finite_infinity;
|
|
1157
|
+
const double log2 = log(2.0);
|
|
1158
|
+
for (HighsInt iCol = 0; iCol < numCol; iCol++) {
|
|
1159
|
+
colScale[iCol] = pow(2.0, floor(log(colScale[iCol]) / log2 + 0.5));
|
|
1160
|
+
min_col_scale = min(colScale[iCol], min_col_scale);
|
|
1161
|
+
max_col_scale = max(colScale[iCol], max_col_scale);
|
|
1162
|
+
}
|
|
1163
|
+
for (HighsInt iRow = 0; iRow < numRow; iRow++) {
|
|
1164
|
+
rowScale[iRow] = pow(2.0, floor(log(rowScale[iRow]) / log2 + 0.5));
|
|
1165
|
+
min_row_scale = min(rowScale[iRow], min_row_scale);
|
|
1166
|
+
max_row_scale = max(rowScale[iRow], max_row_scale);
|
|
1167
|
+
}
|
|
1168
|
+
// Apply scaling to matrix and bounds
|
|
1169
|
+
double matrix_min_value = finite_infinity;
|
|
1170
|
+
double matrix_max_value = 0;
|
|
1171
|
+
double min_original_col_equilibration = finite_infinity;
|
|
1172
|
+
double sum_original_log_col_equilibration = 0;
|
|
1173
|
+
double max_original_col_equilibration = 0;
|
|
1174
|
+
double min_original_row_equilibration = finite_infinity;
|
|
1175
|
+
double sum_original_log_row_equilibration = 0;
|
|
1176
|
+
double max_original_row_equilibration = 0;
|
|
1177
|
+
double min_col_equilibration = finite_infinity;
|
|
1178
|
+
double sum_log_col_equilibration = 0;
|
|
1179
|
+
double max_col_equilibration = 0;
|
|
1180
|
+
double min_row_equilibration = finite_infinity;
|
|
1181
|
+
double sum_log_row_equilibration = 0;
|
|
1182
|
+
double max_row_equilibration = 0;
|
|
1183
|
+
vector<double> original_row_min_value(numRow, finite_infinity);
|
|
1184
|
+
vector<double> original_row_max_value(numRow, 1 / finite_infinity);
|
|
1185
|
+
row_min_value.assign(numRow, finite_infinity);
|
|
1186
|
+
row_max_value.assign(numRow, 1 / finite_infinity);
|
|
1187
|
+
for (HighsInt iCol = 0; iCol < numCol; iCol++) {
|
|
1188
|
+
double original_col_min_value = finite_infinity;
|
|
1189
|
+
double original_col_max_value = 1 / finite_infinity;
|
|
1190
|
+
double col_min_value = finite_infinity;
|
|
1191
|
+
double col_max_value = 1 / finite_infinity;
|
|
1192
|
+
for (HighsInt k = Astart[iCol]; k < Astart[iCol + 1]; k++) {
|
|
1193
|
+
HighsInt iRow = Aindex[k];
|
|
1194
|
+
const double original_value = fabs(Avalue[k]);
|
|
1195
|
+
original_col_min_value = min(original_value, original_col_min_value);
|
|
1196
|
+
original_col_max_value = max(original_value, original_col_max_value);
|
|
1197
|
+
original_row_min_value[iRow] =
|
|
1198
|
+
min(original_row_min_value[iRow], original_value);
|
|
1199
|
+
original_row_max_value[iRow] =
|
|
1200
|
+
max(original_row_max_value[iRow], original_value);
|
|
1201
|
+
Avalue[k] *= (colScale[iCol] * rowScale[iRow]);
|
|
1202
|
+
const double value = fabs(Avalue[k]);
|
|
1203
|
+
col_min_value = min(value, col_min_value);
|
|
1204
|
+
col_max_value = max(value, col_max_value);
|
|
1205
|
+
row_min_value[iRow] = min(row_min_value[iRow], value);
|
|
1206
|
+
row_max_value[iRow] = max(row_max_value[iRow], value);
|
|
1207
|
+
}
|
|
1208
|
+
matrix_min_value = min(matrix_min_value, col_min_value);
|
|
1209
|
+
matrix_max_value = max(matrix_max_value, col_max_value);
|
|
1210
|
+
|
|
1211
|
+
const double original_col_equilibration =
|
|
1212
|
+
1 / sqrt(original_col_min_value * original_col_max_value);
|
|
1213
|
+
min_original_col_equilibration =
|
|
1214
|
+
min(original_col_equilibration, min_original_col_equilibration);
|
|
1215
|
+
sum_original_log_col_equilibration += log(original_col_equilibration);
|
|
1216
|
+
max_original_col_equilibration =
|
|
1217
|
+
max(original_col_equilibration, max_original_col_equilibration);
|
|
1218
|
+
const double col_equilibration = 1 / sqrt(col_min_value * col_max_value);
|
|
1219
|
+
min_col_equilibration = min(col_equilibration, min_col_equilibration);
|
|
1220
|
+
sum_log_col_equilibration += log(col_equilibration);
|
|
1221
|
+
max_col_equilibration = max(col_equilibration, max_col_equilibration);
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
for (HighsInt iRow = 0; iRow < numRow; iRow++) {
|
|
1225
|
+
const double original_row_equilibration =
|
|
1226
|
+
1 / sqrt(original_row_min_value[iRow] * original_row_max_value[iRow]);
|
|
1227
|
+
min_original_row_equilibration =
|
|
1228
|
+
min(original_row_equilibration, min_original_row_equilibration);
|
|
1229
|
+
sum_original_log_row_equilibration += log(original_row_equilibration);
|
|
1230
|
+
max_original_row_equilibration =
|
|
1231
|
+
max(original_row_equilibration, max_original_row_equilibration);
|
|
1232
|
+
const double row_equilibration =
|
|
1233
|
+
1 / sqrt(row_min_value[iRow] * row_max_value[iRow]);
|
|
1234
|
+
min_row_equilibration = min(row_equilibration, min_row_equilibration);
|
|
1235
|
+
sum_log_row_equilibration += log(row_equilibration);
|
|
1236
|
+
max_row_equilibration = max(row_equilibration, max_row_equilibration);
|
|
1237
|
+
}
|
|
1238
|
+
const double geomean_original_col_equilibration =
|
|
1239
|
+
exp(sum_original_log_col_equilibration / numCol);
|
|
1240
|
+
const double geomean_original_row_equilibration =
|
|
1241
|
+
exp(sum_original_log_row_equilibration / numRow);
|
|
1242
|
+
const double geomean_col_equilibration =
|
|
1243
|
+
exp(sum_log_col_equilibration / numCol);
|
|
1244
|
+
const double geomean_row_equilibration =
|
|
1245
|
+
exp(sum_log_row_equilibration / numRow);
|
|
1246
|
+
if (options.log_dev_level) {
|
|
1247
|
+
highsLogDev(
|
|
1248
|
+
options.log_options, HighsLogType::kInfo,
|
|
1249
|
+
"Scaling: Original equilibration: min/mean/max %11.4g/%11.4g/%11.4g "
|
|
1250
|
+
"(cols); min/mean/max %11.4g/%11.4g/%11.4g (rows)\n",
|
|
1251
|
+
min_original_col_equilibration, geomean_original_col_equilibration,
|
|
1252
|
+
max_original_col_equilibration, min_original_row_equilibration,
|
|
1253
|
+
geomean_original_row_equilibration, max_original_row_equilibration);
|
|
1254
|
+
highsLogDev(
|
|
1255
|
+
options.log_options, HighsLogType::kInfo,
|
|
1256
|
+
"Scaling: Final equilibration: min/mean/max %11.4g/%11.4g/%11.4g "
|
|
1257
|
+
"(cols); min/mean/max %11.4g/%11.4g/%11.4g (rows)\n",
|
|
1258
|
+
min_col_equilibration, geomean_col_equilibration, max_col_equilibration,
|
|
1259
|
+
min_row_equilibration, geomean_row_equilibration,
|
|
1260
|
+
max_row_equilibration);
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
// Compute the mean equilibration improvement
|
|
1264
|
+
const double geomean_original_col =
|
|
1265
|
+
max(geomean_original_col_equilibration,
|
|
1266
|
+
1 / geomean_original_col_equilibration);
|
|
1267
|
+
const double geomean_original_row =
|
|
1268
|
+
max(geomean_original_row_equilibration,
|
|
1269
|
+
1 / geomean_original_row_equilibration);
|
|
1270
|
+
const double geomean_col =
|
|
1271
|
+
max(geomean_col_equilibration, 1 / geomean_col_equilibration);
|
|
1272
|
+
const double geomean_row =
|
|
1273
|
+
max(geomean_row_equilibration, 1 / geomean_row_equilibration);
|
|
1274
|
+
const double mean_equilibration_improvement =
|
|
1275
|
+
sqrt((geomean_original_col * geomean_original_row) /
|
|
1276
|
+
(geomean_col * geomean_row));
|
|
1277
|
+
// Compute the extreme equilibration improvement
|
|
1278
|
+
const double original_col_ratio =
|
|
1279
|
+
max_original_col_equilibration / min_original_col_equilibration;
|
|
1280
|
+
const double original_row_ratio =
|
|
1281
|
+
max_original_row_equilibration / min_original_row_equilibration;
|
|
1282
|
+
const double col_ratio = max_col_equilibration / min_col_equilibration;
|
|
1283
|
+
const double row_ratio = max_row_equilibration / min_row_equilibration;
|
|
1284
|
+
const double extreme_equilibration_improvement =
|
|
1285
|
+
(original_col_ratio + original_row_ratio) / (col_ratio + row_ratio);
|
|
1286
|
+
// Compute the max/min matrix value improvement
|
|
1287
|
+
const double matrix_value_ratio = matrix_max_value / matrix_min_value;
|
|
1288
|
+
const double original_matrix_value_ratio =
|
|
1289
|
+
original_matrix_max_value / original_matrix_min_value;
|
|
1290
|
+
const double matrix_value_ratio_improvement =
|
|
1291
|
+
original_matrix_value_ratio / matrix_value_ratio;
|
|
1292
|
+
if (options.log_dev_level) {
|
|
1293
|
+
highsLogDev(
|
|
1294
|
+
options.log_options, HighsLogType::kInfo,
|
|
1295
|
+
"Scaling: Extreme equilibration improvement = ( %11.4g + "
|
|
1296
|
+
"%11.4g) / ( %11.4g + %11.4g) = %11.4g / %11.4g = %11.4g\n",
|
|
1297
|
+
original_col_ratio, original_row_ratio, col_ratio, row_ratio,
|
|
1298
|
+
(original_col_ratio + original_row_ratio), (col_ratio + row_ratio),
|
|
1299
|
+
extreme_equilibration_improvement);
|
|
1300
|
+
highsLogDev(
|
|
1301
|
+
options.log_options, HighsLogType::kInfo,
|
|
1302
|
+
"Scaling: Mean equilibration improvement = sqrt(( %11.4g * "
|
|
1303
|
+
"%11.4g) / ( %11.4g * %11.4g)) = sqrt(%11.4g / %11.4g) = %11.4g\n",
|
|
1304
|
+
geomean_original_col, geomean_original_row, geomean_col, geomean_row,
|
|
1305
|
+
(geomean_original_col * geomean_original_row),
|
|
1306
|
+
(geomean_col * geomean_row), mean_equilibration_improvement);
|
|
1307
|
+
highsLogDev(
|
|
1308
|
+
options.log_options, HighsLogType::kInfo,
|
|
1309
|
+
"Scaling: Yields [min, max, ratio] matrix values of [%0.4g, %0.4g, "
|
|
1310
|
+
"%0.4g]; Originally [%0.4g, %0.4g, %0.4g]: Improvement of %0.4g\n",
|
|
1311
|
+
matrix_min_value, matrix_max_value, matrix_value_ratio,
|
|
1312
|
+
original_matrix_min_value, original_matrix_max_value,
|
|
1313
|
+
original_matrix_value_ratio, matrix_value_ratio_improvement);
|
|
1314
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
1315
|
+
"Scaling: Improves mean equilibration by a factor %0.4g\n",
|
|
1316
|
+
mean_equilibration_improvement);
|
|
1317
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
1318
|
+
"Scaling: Improves extreme equilibration by a factor %0.4g\n",
|
|
1319
|
+
extreme_equilibration_improvement);
|
|
1320
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
1321
|
+
"Scaling: Improves max/min matrix values by a factor %0.4g\n",
|
|
1322
|
+
matrix_value_ratio_improvement);
|
|
1323
|
+
}
|
|
1324
|
+
const bool possibly_abandon_scaling =
|
|
1325
|
+
simplex_scale_strategy != kSimplexScaleStrategyForcedEquilibration;
|
|
1326
|
+
const double improvement_factor = extreme_equilibration_improvement *
|
|
1327
|
+
mean_equilibration_improvement *
|
|
1328
|
+
matrix_value_ratio_improvement;
|
|
1329
|
+
|
|
1330
|
+
const double improvement_factor_required = 1.0;
|
|
1331
|
+
const bool poor_improvement =
|
|
1332
|
+
improvement_factor < improvement_factor_required;
|
|
1333
|
+
|
|
1334
|
+
// Possibly abandon scaling if it's not improved equilibration significantly
|
|
1335
|
+
if (possibly_abandon_scaling && poor_improvement) {
|
|
1336
|
+
// Unscale the matrix
|
|
1337
|
+
for (HighsInt iCol = 0; iCol < numCol; iCol++) {
|
|
1338
|
+
for (HighsInt k = Astart[iCol]; k < Astart[iCol + 1]; k++) {
|
|
1339
|
+
HighsInt iRow = Aindex[k];
|
|
1340
|
+
Avalue[k] /= (colScale[iCol] * rowScale[iRow]);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
if (options.log_dev_level)
|
|
1344
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
1345
|
+
"Scaling: Improvement factor %0.4g < %0.4g required, so no "
|
|
1346
|
+
"scaling applied\n",
|
|
1347
|
+
improvement_factor, improvement_factor_required);
|
|
1348
|
+
return false;
|
|
1349
|
+
} else {
|
|
1350
|
+
if (options.log_dev_level) {
|
|
1351
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
1352
|
+
"Scaling: Factors are in [%0.4g, %0.4g] for columns and in "
|
|
1353
|
+
"[%0.4g, %0.4g] for rows\n",
|
|
1354
|
+
min_col_scale, max_col_scale, min_row_scale, max_row_scale);
|
|
1355
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
1356
|
+
"Scaling: Improvement factor is %0.4g >= %0.4g so scale LP\n",
|
|
1357
|
+
improvement_factor, improvement_factor_required);
|
|
1358
|
+
if (extreme_equilibration_improvement < 1.0) {
|
|
1359
|
+
highsLogDev(
|
|
1360
|
+
options.log_options, HighsLogType::kWarning,
|
|
1361
|
+
"Scaling: Applying scaling with extreme improvement of %0.4g\n",
|
|
1362
|
+
extreme_equilibration_improvement);
|
|
1363
|
+
}
|
|
1364
|
+
if (mean_equilibration_improvement < 1.0) {
|
|
1365
|
+
highsLogDev(
|
|
1366
|
+
options.log_options, HighsLogType::kWarning,
|
|
1367
|
+
"Scaling: Applying scaling with mean improvement of %0.4g\n",
|
|
1368
|
+
mean_equilibration_improvement);
|
|
1369
|
+
}
|
|
1370
|
+
if (matrix_value_ratio_improvement < 1.0) {
|
|
1371
|
+
highsLogDev(options.log_options, HighsLogType::kWarning,
|
|
1372
|
+
"Scaling: Applying scaling with matrix value ratio "
|
|
1373
|
+
"improvement of %0.4g\n",
|
|
1374
|
+
matrix_value_ratio_improvement);
|
|
1375
|
+
}
|
|
1376
|
+
if (improvement_factor < 10 * improvement_factor_required) {
|
|
1377
|
+
highsLogDev(options.log_options, HighsLogType::kWarning,
|
|
1378
|
+
"Scaling: Applying scaling with improvement factor %0.4g "
|
|
1379
|
+
"< 10*(%0.4g) improvement\n",
|
|
1380
|
+
improvement_factor, improvement_factor_required);
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
return true;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
bool maxValueScaleMatrix(const HighsOptions& options, HighsLp& lp,
|
|
1388
|
+
const HighsInt use_scale_strategy) {
|
|
1389
|
+
HighsInt numCol = lp.num_col_;
|
|
1390
|
+
HighsInt numRow = lp.num_row_;
|
|
1391
|
+
HighsScale& scale = lp.scale_;
|
|
1392
|
+
vector<double>& colScale = scale.col;
|
|
1393
|
+
vector<double>& rowScale = scale.row;
|
|
1394
|
+
vector<HighsInt>& Astart = lp.a_matrix_.start_;
|
|
1395
|
+
vector<HighsInt>& Aindex = lp.a_matrix_.index_;
|
|
1396
|
+
vector<double>& Avalue = lp.a_matrix_.value_;
|
|
1397
|
+
|
|
1398
|
+
assert(options.simplex_scale_strategy == kSimplexScaleStrategyMaxValue);
|
|
1399
|
+
assert(kSimplexScaleStrategyMaxValue015 == kSimplexScaleStrategyMaxValue);
|
|
1400
|
+
assert(kSimplexScaleStrategyMaxValue0157 == kSimplexScaleStrategyMaxValue);
|
|
1401
|
+
|
|
1402
|
+
// The 015(7) values refer to bit settings in FICO's scaling options.
|
|
1403
|
+
// Specifically
|
|
1404
|
+
//
|
|
1405
|
+
// 0: Row scaling
|
|
1406
|
+
//
|
|
1407
|
+
// 1: Column scaling
|
|
1408
|
+
//
|
|
1409
|
+
// 5: Scale by maximum element
|
|
1410
|
+
//
|
|
1411
|
+
// 7: Scale objective function for the simplex method
|
|
1412
|
+
//
|
|
1413
|
+
// Note that 7 is not yet implemented, so
|
|
1414
|
+
// kSimplexScaleStrategyMaxValue015 and
|
|
1415
|
+
// kSimplexScaleStrategyMaxValue0157 are equivalent. However, cost
|
|
1416
|
+
// scaling could be well worth adding, now that the unscaled problem
|
|
1417
|
+
// can be solved using scaled NLA
|
|
1418
|
+
|
|
1419
|
+
const double log2 = log(2.0);
|
|
1420
|
+
const double max_allow_scale = pow(2.0, options.allowed_matrix_scale_factor);
|
|
1421
|
+
const double min_allow_scale = 1 / max_allow_scale;
|
|
1422
|
+
|
|
1423
|
+
const double min_allow_col_scale = min_allow_scale;
|
|
1424
|
+
const double max_allow_col_scale = max_allow_scale;
|
|
1425
|
+
const double min_allow_row_scale = min_allow_scale;
|
|
1426
|
+
const double max_allow_row_scale = max_allow_scale;
|
|
1427
|
+
|
|
1428
|
+
double min_row_scale = kHighsInf;
|
|
1429
|
+
double max_row_scale = 0;
|
|
1430
|
+
double original_matrix_min_value = kHighsInf;
|
|
1431
|
+
double original_matrix_max_value = 0;
|
|
1432
|
+
// Determine the row scaling. Also determine the max/min row scaling
|
|
1433
|
+
// factors, and max/min original matrix values
|
|
1434
|
+
vector<double> row_max_value(numRow, 0);
|
|
1435
|
+
for (HighsInt iCol = 0; iCol < numCol; iCol++) {
|
|
1436
|
+
for (HighsInt k = Astart[iCol]; k < Astart[iCol + 1]; k++) {
|
|
1437
|
+
const HighsInt iRow = Aindex[k];
|
|
1438
|
+
const double value = fabs(Avalue[k]);
|
|
1439
|
+
row_max_value[iRow] = max(row_max_value[iRow], value);
|
|
1440
|
+
original_matrix_min_value = min(original_matrix_min_value, value);
|
|
1441
|
+
original_matrix_max_value = max(original_matrix_max_value, value);
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
for (HighsInt iRow = 0; iRow < numRow; iRow++) {
|
|
1445
|
+
if (row_max_value[iRow]) {
|
|
1446
|
+
double row_scale_value = 1 / row_max_value[iRow];
|
|
1447
|
+
// Convert the row scale factor to the nearest power of two, and
|
|
1448
|
+
// ensure that it is not excessively large or small
|
|
1449
|
+
row_scale_value = pow(2.0, floor(log(row_scale_value) / log2 + 0.5));
|
|
1450
|
+
row_scale_value =
|
|
1451
|
+
min(max(min_allow_row_scale, row_scale_value), max_allow_row_scale);
|
|
1452
|
+
min_row_scale = min(row_scale_value, min_row_scale);
|
|
1453
|
+
max_row_scale = max(row_scale_value, max_row_scale);
|
|
1454
|
+
rowScale[iRow] = row_scale_value;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
// Determine the column scaling, whilst applying the row scaling
|
|
1458
|
+
// Also determine the max/min column scaling factors, and max/min
|
|
1459
|
+
// matrix values
|
|
1460
|
+
double min_col_scale = kHighsInf;
|
|
1461
|
+
double max_col_scale = 0;
|
|
1462
|
+
double matrix_min_value = kHighsInf;
|
|
1463
|
+
double matrix_max_value = 0;
|
|
1464
|
+
for (HighsInt iCol = 0; iCol < numCol; iCol++) {
|
|
1465
|
+
double col_max_value = 0;
|
|
1466
|
+
for (HighsInt k = Astart[iCol]; k < Astart[iCol + 1]; k++) {
|
|
1467
|
+
const HighsInt iRow = Aindex[k];
|
|
1468
|
+
Avalue[k] *= rowScale[iRow];
|
|
1469
|
+
const double value = fabs(Avalue[k]);
|
|
1470
|
+
col_max_value = max(col_max_value, value);
|
|
1471
|
+
}
|
|
1472
|
+
if (col_max_value) {
|
|
1473
|
+
double col_scale_value = 1 / col_max_value;
|
|
1474
|
+
// Convert the col scale factor to the nearest power of two, and
|
|
1475
|
+
// ensure that it is not excessively large or small
|
|
1476
|
+
col_scale_value = pow(2.0, floor(log(col_scale_value) / log2 + 0.5));
|
|
1477
|
+
col_scale_value =
|
|
1478
|
+
min(max(min_allow_col_scale, col_scale_value), max_allow_col_scale);
|
|
1479
|
+
min_col_scale = min(col_scale_value, min_col_scale);
|
|
1480
|
+
max_col_scale = max(col_scale_value, max_col_scale);
|
|
1481
|
+
colScale[iCol] = col_scale_value;
|
|
1482
|
+
for (HighsInt k = Astart[iCol]; k < Astart[iCol + 1]; k++) {
|
|
1483
|
+
Avalue[k] *= colScale[iCol];
|
|
1484
|
+
const double value = fabs(Avalue[k]);
|
|
1485
|
+
matrix_min_value = min(matrix_min_value, value);
|
|
1486
|
+
matrix_max_value = max(matrix_max_value, value);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
const double matrix_value_ratio = matrix_max_value / matrix_min_value;
|
|
1491
|
+
const double original_matrix_value_ratio =
|
|
1492
|
+
original_matrix_max_value / original_matrix_min_value;
|
|
1493
|
+
const double matrix_value_ratio_improvement =
|
|
1494
|
+
original_matrix_value_ratio / matrix_value_ratio;
|
|
1495
|
+
|
|
1496
|
+
const double improvement_factor = matrix_value_ratio_improvement;
|
|
1497
|
+
|
|
1498
|
+
const double improvement_factor_required = 1.0;
|
|
1499
|
+
const bool poor_improvement =
|
|
1500
|
+
improvement_factor <= improvement_factor_required;
|
|
1501
|
+
|
|
1502
|
+
if (poor_improvement) {
|
|
1503
|
+
// Unscale the matrix
|
|
1504
|
+
for (HighsInt iCol = 0; iCol < numCol; iCol++) {
|
|
1505
|
+
for (HighsInt k = Astart[iCol]; k < Astart[iCol + 1]; k++) {
|
|
1506
|
+
HighsInt iRow = Aindex[k];
|
|
1507
|
+
Avalue[k] /= (colScale[iCol] * rowScale[iRow]);
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
if (options.log_dev_level)
|
|
1511
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
1512
|
+
"Scaling: Improvement factor %0.4g < %0.4g required, so no "
|
|
1513
|
+
"scaling applied\n",
|
|
1514
|
+
improvement_factor, improvement_factor_required);
|
|
1515
|
+
return false;
|
|
1516
|
+
} else {
|
|
1517
|
+
if (options.log_dev_level) {
|
|
1518
|
+
highsLogDev(options.log_options, HighsLogType::kInfo,
|
|
1519
|
+
"Scaling: Factors are in [%0.4g, %0.4g] for columns and in "
|
|
1520
|
+
"[%0.4g, %0.4g] for rows\n",
|
|
1521
|
+
min_col_scale, max_col_scale, min_row_scale, max_row_scale);
|
|
1522
|
+
highsLogDev(
|
|
1523
|
+
options.log_options, HighsLogType::kInfo,
|
|
1524
|
+
"Scaling: Yields [min, max, ratio] matrix values of [%0.4g, %0.4g, "
|
|
1525
|
+
"%0.4g]; Originally [%0.4g, %0.4g, %0.4g]: Improvement of %0.4g\n",
|
|
1526
|
+
matrix_min_value, matrix_max_value, matrix_value_ratio,
|
|
1527
|
+
original_matrix_min_value, original_matrix_max_value,
|
|
1528
|
+
original_matrix_value_ratio, matrix_value_ratio_improvement);
|
|
1529
|
+
}
|
|
1530
|
+
return true;
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
HighsStatus applyScalingToLpCol(HighsLp& lp, const HighsInt col,
|
|
1535
|
+
const double colScale) {
|
|
1536
|
+
if (col < 0) return HighsStatus::kError;
|
|
1537
|
+
if (col >= lp.num_col_) return HighsStatus::kError;
|
|
1538
|
+
if (!colScale) return HighsStatus::kError;
|
|
1539
|
+
|
|
1540
|
+
lp.a_matrix_.scaleCol(col, colScale);
|
|
1541
|
+
lp.col_cost_[col] *= colScale;
|
|
1542
|
+
if (colScale > 0) {
|
|
1543
|
+
lp.col_lower_[col] /= colScale;
|
|
1544
|
+
lp.col_upper_[col] /= colScale;
|
|
1545
|
+
} else {
|
|
1546
|
+
const double new_upper = lp.col_lower_[col] / colScale;
|
|
1547
|
+
lp.col_lower_[col] = lp.col_upper_[col] / colScale;
|
|
1548
|
+
lp.col_upper_[col] = new_upper;
|
|
1549
|
+
}
|
|
1550
|
+
return HighsStatus::kOk;
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
HighsStatus applyScalingToLpRow(HighsLp& lp, const HighsInt row,
|
|
1554
|
+
const double rowScale) {
|
|
1555
|
+
if (row < 0) return HighsStatus::kError;
|
|
1556
|
+
if (row >= lp.num_row_) return HighsStatus::kError;
|
|
1557
|
+
if (!rowScale) return HighsStatus::kError;
|
|
1558
|
+
|
|
1559
|
+
lp.a_matrix_.scaleRow(row, rowScale);
|
|
1560
|
+
if (rowScale > 0) {
|
|
1561
|
+
lp.row_lower_[row] *= rowScale;
|
|
1562
|
+
lp.row_upper_[row] *= rowScale;
|
|
1563
|
+
} else {
|
|
1564
|
+
const double new_upper = lp.row_lower_[row] * rowScale;
|
|
1565
|
+
lp.row_lower_[row] = lp.row_upper_[row] * rowScale;
|
|
1566
|
+
lp.row_upper_[row] = new_upper;
|
|
1567
|
+
}
|
|
1568
|
+
return HighsStatus::kOk;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
void unscaleSolution(HighsSolution& solution, const HighsScale& scale) {
|
|
1572
|
+
assert(scale.has_scaling);
|
|
1573
|
+
assert(solution.col_value.size() == static_cast<size_t>(scale.num_col));
|
|
1574
|
+
assert(solution.col_dual.size() == static_cast<size_t>(scale.num_col));
|
|
1575
|
+
assert(solution.row_value.size() == static_cast<size_t>(scale.num_row));
|
|
1576
|
+
assert(solution.row_dual.size() == static_cast<size_t>(scale.num_row));
|
|
1577
|
+
|
|
1578
|
+
for (HighsInt iCol = 0; iCol < scale.num_col; iCol++) {
|
|
1579
|
+
solution.col_value[iCol] *= scale.col[iCol];
|
|
1580
|
+
solution.col_dual[iCol] /= (scale.col[iCol] / scale.cost);
|
|
1581
|
+
}
|
|
1582
|
+
for (HighsInt iRow = 0; iRow < scale.num_row; iRow++) {
|
|
1583
|
+
solution.row_value[iRow] /= scale.row[iRow];
|
|
1584
|
+
solution.row_dual[iRow] *= (scale.row[iRow] * scale.cost);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
void appendColsToLpVectors(HighsLp& lp, const HighsInt num_new_col,
|
|
1589
|
+
const vector<double>& colCost,
|
|
1590
|
+
const vector<double>& colLower,
|
|
1591
|
+
const vector<double>& colUpper) {
|
|
1592
|
+
assert(num_new_col >= 0);
|
|
1593
|
+
if (num_new_col == 0) return;
|
|
1594
|
+
HighsInt new_num_col = lp.num_col_ + num_new_col;
|
|
1595
|
+
lp.col_cost_.resize(new_num_col);
|
|
1596
|
+
lp.col_lower_.resize(new_num_col);
|
|
1597
|
+
lp.col_upper_.resize(new_num_col);
|
|
1598
|
+
const bool have_integrality = (lp.integrality_.size() != 0);
|
|
1599
|
+
if (have_integrality) {
|
|
1600
|
+
assert(HighsInt(lp.integrality_.size()) == lp.num_col_);
|
|
1601
|
+
lp.integrality_.resize(new_num_col);
|
|
1602
|
+
}
|
|
1603
|
+
bool have_names = (lp.col_names_.size() != 0);
|
|
1604
|
+
if (have_names) lp.col_names_.resize(new_num_col);
|
|
1605
|
+
for (HighsInt new_col = 0; new_col < num_new_col; new_col++) {
|
|
1606
|
+
HighsInt iCol = lp.num_col_ + new_col;
|
|
1607
|
+
lp.col_cost_[iCol] = colCost[new_col];
|
|
1608
|
+
lp.col_lower_[iCol] = colLower[new_col];
|
|
1609
|
+
lp.col_upper_[iCol] = colUpper[new_col];
|
|
1610
|
+
// Cannot guarantee to create unique names, so name is blank
|
|
1611
|
+
if (have_names) lp.col_names_[iCol] = "";
|
|
1612
|
+
if (have_integrality) lp.integrality_[iCol] = HighsVarType::kContinuous;
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
void appendRowsToLpVectors(HighsLp& lp, const HighsInt num_new_row,
|
|
1617
|
+
const vector<double>& rowLower,
|
|
1618
|
+
const vector<double>& rowUpper) {
|
|
1619
|
+
assert(num_new_row >= 0);
|
|
1620
|
+
if (num_new_row == 0) return;
|
|
1621
|
+
HighsInt new_num_row = lp.num_row_ + num_new_row;
|
|
1622
|
+
lp.row_lower_.resize(new_num_row);
|
|
1623
|
+
lp.row_upper_.resize(new_num_row);
|
|
1624
|
+
bool have_names = (lp.row_names_.size() != 0);
|
|
1625
|
+
if (have_names) lp.row_names_.resize(new_num_row);
|
|
1626
|
+
|
|
1627
|
+
for (HighsInt new_row = 0; new_row < num_new_row; new_row++) {
|
|
1628
|
+
HighsInt iRow = lp.num_row_ + new_row;
|
|
1629
|
+
lp.row_lower_[iRow] = rowLower[new_row];
|
|
1630
|
+
lp.row_upper_[iRow] = rowUpper[new_row];
|
|
1631
|
+
// Cannot guarantee to create unique names, so name is blank
|
|
1632
|
+
if (have_names) lp.row_names_[iRow] = "";
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
void deleteScale(vector<double>& scale,
|
|
1637
|
+
const HighsIndexCollection& index_collection) {
|
|
1638
|
+
assert(ok(index_collection));
|
|
1639
|
+
HighsInt from_k;
|
|
1640
|
+
HighsInt to_k;
|
|
1641
|
+
limits(index_collection, from_k, to_k);
|
|
1642
|
+
if (from_k > to_k) return;
|
|
1643
|
+
|
|
1644
|
+
HighsInt delete_from_col;
|
|
1645
|
+
HighsInt delete_to_col;
|
|
1646
|
+
HighsInt keep_from_col;
|
|
1647
|
+
HighsInt keep_to_col = -1;
|
|
1648
|
+
HighsInt current_set_entry = 0;
|
|
1649
|
+
|
|
1650
|
+
HighsInt col_dim = index_collection.dimension_;
|
|
1651
|
+
HighsInt new_num_col = 0;
|
|
1652
|
+
for (HighsInt k = from_k; k <= to_k; k++) {
|
|
1653
|
+
updateOutInIndex(index_collection, delete_from_col, delete_to_col,
|
|
1654
|
+
keep_from_col, keep_to_col, current_set_entry);
|
|
1655
|
+
// Account for the initial columns being kept
|
|
1656
|
+
if (k == from_k) new_num_col = delete_from_col;
|
|
1657
|
+
if (delete_to_col >= col_dim - 1) break;
|
|
1658
|
+
assert(delete_to_col < col_dim);
|
|
1659
|
+
for (HighsInt col = keep_from_col; col <= keep_to_col; col++) {
|
|
1660
|
+
assert((HighsInt)scale.size() > new_num_col);
|
|
1661
|
+
scale[new_num_col] = scale[col];
|
|
1662
|
+
new_num_col++;
|
|
1663
|
+
}
|
|
1664
|
+
if (keep_to_col >= col_dim - 1) break;
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
void changeLpMatrixCoefficient(HighsLp& lp, const HighsInt row,
|
|
1669
|
+
const HighsInt col, const double new_value,
|
|
1670
|
+
const bool zero_new_value) {
|
|
1671
|
+
assert(0 <= row && row < lp.num_row_);
|
|
1672
|
+
assert(0 <= col && col < lp.num_col_);
|
|
1673
|
+
|
|
1674
|
+
// Determine whether the coefficient corresponds to an existing
|
|
1675
|
+
// nonzero
|
|
1676
|
+
HighsInt change_el = -1;
|
|
1677
|
+
for (HighsInt el = lp.a_matrix_.start_[col];
|
|
1678
|
+
el < lp.a_matrix_.start_[col + 1]; el++) {
|
|
1679
|
+
if (lp.a_matrix_.index_[el] == row) {
|
|
1680
|
+
change_el = el;
|
|
1681
|
+
break;
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
if (change_el < 0) {
|
|
1685
|
+
// Coefficient doesn't correspond to an existing nonzero
|
|
1686
|
+
//
|
|
1687
|
+
// If coefficient is small, then just ignore it
|
|
1688
|
+
if (zero_new_value) return;
|
|
1689
|
+
// New nonzero goes at the end of column "col", so have to shift
|
|
1690
|
+
// all index and value entries forward by 1 to accommodate it
|
|
1691
|
+
change_el = lp.a_matrix_.start_[col + 1];
|
|
1692
|
+
HighsInt new_num_nz = lp.a_matrix_.start_[lp.num_col_] + 1;
|
|
1693
|
+
lp.a_matrix_.index_.resize(new_num_nz);
|
|
1694
|
+
lp.a_matrix_.value_.resize(new_num_nz);
|
|
1695
|
+
for (HighsInt i = col + 1; i <= lp.num_col_; i++) lp.a_matrix_.start_[i]++;
|
|
1696
|
+
for (HighsInt el = new_num_nz - 1; el > change_el; el--) {
|
|
1697
|
+
lp.a_matrix_.index_[el] = lp.a_matrix_.index_[el - 1];
|
|
1698
|
+
lp.a_matrix_.value_[el] = lp.a_matrix_.value_[el - 1];
|
|
1699
|
+
}
|
|
1700
|
+
} else if (zero_new_value) {
|
|
1701
|
+
// Coefficient zeroes an existing nonzero, so shift all index and
|
|
1702
|
+
// value entries backward by 1 to eliminate it
|
|
1703
|
+
HighsInt new_num_nz = lp.a_matrix_.start_[lp.num_col_] - 1;
|
|
1704
|
+
for (HighsInt i = col + 1; i <= lp.num_col_; i++) lp.a_matrix_.start_[i]--;
|
|
1705
|
+
for (HighsInt el = change_el; el < new_num_nz; el++) {
|
|
1706
|
+
lp.a_matrix_.index_[el] = lp.a_matrix_.index_[el + 1];
|
|
1707
|
+
lp.a_matrix_.value_[el] = lp.a_matrix_.value_[el + 1];
|
|
1708
|
+
}
|
|
1709
|
+
return;
|
|
1710
|
+
}
|
|
1711
|
+
lp.a_matrix_.index_[change_el] = row;
|
|
1712
|
+
lp.a_matrix_.value_[change_el] = new_value;
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
HighsStatus changeLpIntegrality(HighsLp& lp,
|
|
1716
|
+
const HighsIndexCollection& index_collection,
|
|
1717
|
+
const vector<HighsVarType>& new_integrality,
|
|
1718
|
+
const HighsOptions options) {
|
|
1719
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
1720
|
+
assert(ok(index_collection));
|
|
1721
|
+
HighsInt from_k;
|
|
1722
|
+
HighsInt to_k;
|
|
1723
|
+
limits(index_collection, from_k, to_k);
|
|
1724
|
+
if (from_k > to_k) return return_status;
|
|
1725
|
+
|
|
1726
|
+
const bool& interval = index_collection.is_interval_;
|
|
1727
|
+
const bool& mask = index_collection.is_mask_;
|
|
1728
|
+
const vector<HighsInt>& col_set = index_collection.set_;
|
|
1729
|
+
const vector<HighsInt>& col_mask = index_collection.mask_;
|
|
1730
|
+
|
|
1731
|
+
// Change the integrality to the user-supplied integrality, according to the
|
|
1732
|
+
// technique
|
|
1733
|
+
HighsInt lp_col;
|
|
1734
|
+
HighsInt usr_col = -1;
|
|
1735
|
+
|
|
1736
|
+
// If changing integrality for a problem without an integrality
|
|
1737
|
+
// vector (ie an LP), have to create it for the incumbent columns -
|
|
1738
|
+
// which are naturally continuous
|
|
1739
|
+
if (lp.integrality_.size() == 0)
|
|
1740
|
+
lp.integrality_.assign(lp.num_col_, HighsVarType::kContinuous);
|
|
1741
|
+
|
|
1742
|
+
assert(HighsInt(lp.integrality_.size()) == lp.num_col_);
|
|
1743
|
+
for (HighsInt k = from_k; k < to_k + 1; k++) {
|
|
1744
|
+
if (interval || mask) {
|
|
1745
|
+
lp_col = k;
|
|
1746
|
+
} else {
|
|
1747
|
+
lp_col = col_set[k];
|
|
1748
|
+
}
|
|
1749
|
+
HighsInt col = lp_col;
|
|
1750
|
+
if (interval) {
|
|
1751
|
+
usr_col++;
|
|
1752
|
+
} else {
|
|
1753
|
+
usr_col = k;
|
|
1754
|
+
}
|
|
1755
|
+
if (mask && !col_mask[col]) continue;
|
|
1756
|
+
lp.integrality_[col] = new_integrality[usr_col];
|
|
1757
|
+
}
|
|
1758
|
+
// If integrality_ contains only HighsVarType::kContinuous then
|
|
1759
|
+
// clear it
|
|
1760
|
+
if (!lp.isMip()) lp.integrality_.clear();
|
|
1761
|
+
return return_status;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
void changeLpCosts(HighsLp& lp, const HighsIndexCollection& index_collection,
|
|
1765
|
+
const vector<double>& new_col_cost,
|
|
1766
|
+
const double infinite_cost) {
|
|
1767
|
+
assert(ok(index_collection));
|
|
1768
|
+
HighsInt from_k;
|
|
1769
|
+
HighsInt to_k;
|
|
1770
|
+
limits(index_collection, from_k, to_k);
|
|
1771
|
+
if (from_k > to_k) return;
|
|
1772
|
+
|
|
1773
|
+
const bool& interval = index_collection.is_interval_;
|
|
1774
|
+
const bool& mask = index_collection.is_mask_;
|
|
1775
|
+
const vector<HighsInt>& col_set = index_collection.set_;
|
|
1776
|
+
const vector<HighsInt>& col_mask = index_collection.mask_;
|
|
1777
|
+
|
|
1778
|
+
// Change the costs to the user-supplied costs, according to the technique
|
|
1779
|
+
HighsInt lp_col;
|
|
1780
|
+
HighsInt usr_col = -1;
|
|
1781
|
+
for (HighsInt k = from_k; k < to_k + 1; k++) {
|
|
1782
|
+
if (interval || mask) {
|
|
1783
|
+
lp_col = k;
|
|
1784
|
+
} else {
|
|
1785
|
+
lp_col = col_set[k];
|
|
1786
|
+
}
|
|
1787
|
+
HighsInt col = lp_col;
|
|
1788
|
+
if (interval) {
|
|
1789
|
+
usr_col++;
|
|
1790
|
+
} else {
|
|
1791
|
+
usr_col = k;
|
|
1792
|
+
}
|
|
1793
|
+
if (mask && !col_mask[col]) continue;
|
|
1794
|
+
lp.col_cost_[col] = new_col_cost[usr_col];
|
|
1795
|
+
}
|
|
1796
|
+
// Check whether the LP still has an infinite cost
|
|
1797
|
+
if (lp.has_infinite_cost_)
|
|
1798
|
+
lp.has_infinite_cost_ = lp.hasInfiniteCost(infinite_cost);
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
void changeLpColBounds(HighsLp& lp,
|
|
1802
|
+
const HighsIndexCollection& index_collection,
|
|
1803
|
+
const vector<double>& new_col_lower,
|
|
1804
|
+
const vector<double>& new_col_upper) {
|
|
1805
|
+
changeBounds(lp.col_lower_, lp.col_upper_, index_collection, new_col_lower,
|
|
1806
|
+
new_col_upper);
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
void changeLpRowBounds(HighsLp& lp,
|
|
1810
|
+
const HighsIndexCollection& index_collection,
|
|
1811
|
+
const vector<double>& new_row_lower,
|
|
1812
|
+
const vector<double>& new_row_upper) {
|
|
1813
|
+
changeBounds(lp.row_lower_, lp.row_upper_, index_collection, new_row_lower,
|
|
1814
|
+
new_row_upper);
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
void changeBounds(vector<double>& lower, vector<double>& upper,
|
|
1818
|
+
const HighsIndexCollection& index_collection,
|
|
1819
|
+
const vector<double>& new_lower,
|
|
1820
|
+
const vector<double>& new_upper) {
|
|
1821
|
+
assert(ok(index_collection));
|
|
1822
|
+
HighsInt from_k;
|
|
1823
|
+
HighsInt to_k;
|
|
1824
|
+
limits(index_collection, from_k, to_k);
|
|
1825
|
+
if (from_k > to_k) return;
|
|
1826
|
+
|
|
1827
|
+
const bool& interval = index_collection.is_interval_;
|
|
1828
|
+
const bool& mask = index_collection.is_mask_;
|
|
1829
|
+
const vector<HighsInt>& ix_set = index_collection.set_;
|
|
1830
|
+
const vector<HighsInt>& ix_mask = index_collection.mask_;
|
|
1831
|
+
|
|
1832
|
+
// Change the bounds to the user-supplied bounds, according to the technique
|
|
1833
|
+
HighsInt lp_ix;
|
|
1834
|
+
HighsInt usr_ix = -1;
|
|
1835
|
+
for (HighsInt k = from_k; k < to_k + 1; k++) {
|
|
1836
|
+
if (interval || mask) {
|
|
1837
|
+
lp_ix = k;
|
|
1838
|
+
} else {
|
|
1839
|
+
lp_ix = ix_set[k];
|
|
1840
|
+
}
|
|
1841
|
+
HighsInt ix = lp_ix;
|
|
1842
|
+
if (interval) {
|
|
1843
|
+
usr_ix++;
|
|
1844
|
+
} else {
|
|
1845
|
+
usr_ix = k;
|
|
1846
|
+
}
|
|
1847
|
+
if (mask && !ix_mask[ix]) continue;
|
|
1848
|
+
lower[ix] = new_lower[usr_ix];
|
|
1849
|
+
upper[ix] = new_upper[usr_ix];
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
HighsInt getNumInt(const HighsLp& lp) {
|
|
1854
|
+
HighsInt num_int = 0;
|
|
1855
|
+
if (lp.integrality_.size()) {
|
|
1856
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
|
|
1857
|
+
if (lp.integrality_[iCol] == HighsVarType::kInteger) num_int++;
|
|
1858
|
+
}
|
|
1859
|
+
return num_int;
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
void getLpCosts(const HighsLp& lp, const HighsInt from_col,
|
|
1863
|
+
const HighsInt to_col, double* XcolCost) {
|
|
1864
|
+
assert(0 <= from_col && from_col < lp.num_col_);
|
|
1865
|
+
assert(0 <= to_col && to_col < lp.num_col_);
|
|
1866
|
+
if (from_col > to_col) return;
|
|
1867
|
+
for (HighsInt col = from_col; col < to_col + 1; col++)
|
|
1868
|
+
XcolCost[col - from_col] = lp.col_cost_[col];
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
void getLpColBounds(const HighsLp& lp, const HighsInt from_col,
|
|
1872
|
+
const HighsInt to_col, double* XcolLower,
|
|
1873
|
+
double* XcolUpper) {
|
|
1874
|
+
assert(0 <= from_col && from_col < lp.num_col_);
|
|
1875
|
+
assert(0 <= to_col && to_col < lp.num_col_);
|
|
1876
|
+
if (from_col > to_col) return;
|
|
1877
|
+
for (HighsInt col = from_col; col < to_col + 1; col++) {
|
|
1878
|
+
if (XcolLower != nullptr) XcolLower[col - from_col] = lp.col_lower_[col];
|
|
1879
|
+
if (XcolUpper != nullptr) XcolUpper[col - from_col] = lp.col_upper_[col];
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
void getLpRowBounds(const HighsLp& lp, const HighsInt from_row,
|
|
1884
|
+
const HighsInt to_row, double* XrowLower,
|
|
1885
|
+
double* XrowUpper) {
|
|
1886
|
+
assert(0 <= from_row && from_row < lp.num_row_);
|
|
1887
|
+
assert(0 <= to_row && to_row < lp.num_row_);
|
|
1888
|
+
if (from_row > to_row) return;
|
|
1889
|
+
for (HighsInt row = from_row; row < to_row + 1; row++) {
|
|
1890
|
+
if (XrowLower != nullptr) XrowLower[row - from_row] = lp.row_lower_[row];
|
|
1891
|
+
if (XrowUpper != nullptr) XrowUpper[row - from_row] = lp.row_upper_[row];
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
// Get a single coefficient from the matrix
|
|
1896
|
+
void getLpMatrixCoefficient(const HighsLp& lp, const HighsInt Xrow,
|
|
1897
|
+
const HighsInt Xcol, double* val) {
|
|
1898
|
+
assert(0 <= Xrow && Xrow < lp.num_row_);
|
|
1899
|
+
assert(0 <= Xcol && Xcol < lp.num_col_);
|
|
1900
|
+
|
|
1901
|
+
HighsInt get_el = -1;
|
|
1902
|
+
for (HighsInt el = lp.a_matrix_.start_[Xcol];
|
|
1903
|
+
el < lp.a_matrix_.start_[Xcol + 1]; el++) {
|
|
1904
|
+
if (lp.a_matrix_.index_[el] == Xrow) {
|
|
1905
|
+
get_el = el;
|
|
1906
|
+
break;
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
if (get_el < 0) {
|
|
1910
|
+
*val = 0;
|
|
1911
|
+
} else {
|
|
1912
|
+
*val = lp.a_matrix_.value_[get_el];
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
// Methods for reporting an LP, including its row and column data and matrix
|
|
1917
|
+
//
|
|
1918
|
+
// Report the whole LP
|
|
1919
|
+
void reportLp(const HighsLogOptions& log_options, const HighsLp& lp,
|
|
1920
|
+
const HighsLogType report_level) {
|
|
1921
|
+
reportLpBrief(log_options, lp);
|
|
1922
|
+
if ((HighsInt)report_level >= (HighsInt)HighsLogType::kDetailed) {
|
|
1923
|
+
reportLpColVectors(log_options, lp);
|
|
1924
|
+
reportLpRowVectors(log_options, lp);
|
|
1925
|
+
if ((HighsInt)report_level >= (HighsInt)HighsLogType::kVerbose)
|
|
1926
|
+
reportLpColMatrix(log_options, lp);
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
// Report the LP briefly
|
|
1931
|
+
void reportLpBrief(const HighsLogOptions& log_options, const HighsLp& lp) {
|
|
1932
|
+
reportLpDimensions(log_options, lp);
|
|
1933
|
+
reportLpObjSense(log_options, lp);
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
// Report the LP dimensions
|
|
1937
|
+
void reportLpDimensions(const HighsLogOptions& log_options, const HighsLp& lp) {
|
|
1938
|
+
HighsInt lp_num_nz;
|
|
1939
|
+
if (lp.num_col_ == 0)
|
|
1940
|
+
lp_num_nz = 0;
|
|
1941
|
+
else
|
|
1942
|
+
lp_num_nz = lp.a_matrix_.start_[lp.num_col_];
|
|
1943
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
1944
|
+
"LP has %" HIGHSINT_FORMAT " row%s, %" HIGHSINT_FORMAT
|
|
1945
|
+
" column%s",
|
|
1946
|
+
lp.num_row_, lp.num_row_ == 1 ? "" : "s", lp.num_col_,
|
|
1947
|
+
lp.num_col_ == 1 ? "" : "s");
|
|
1948
|
+
HighsInt num_int = getNumInt(lp);
|
|
1949
|
+
if (num_int) {
|
|
1950
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
1951
|
+
", %" HIGHSINT_FORMAT " nonzero%s and %" HIGHSINT_FORMAT
|
|
1952
|
+
" integer column%s\n",
|
|
1953
|
+
lp_num_nz, lp_num_nz == 1 ? "" : "s", num_int,
|
|
1954
|
+
num_int == 1 ? "" : "s");
|
|
1955
|
+
} else {
|
|
1956
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
1957
|
+
" and %" HIGHSINT_FORMAT " nonzero%s\n", lp_num_nz,
|
|
1958
|
+
lp_num_nz == 1 ? "" : "s");
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
// Report the LP objective sense
|
|
1963
|
+
void reportLpObjSense(const HighsLogOptions& log_options, const HighsLp& lp) {
|
|
1964
|
+
if (lp.sense_ == ObjSense::kMinimize)
|
|
1965
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
1966
|
+
"Objective sense is minimize\n");
|
|
1967
|
+
else if (lp.sense_ == ObjSense::kMaximize)
|
|
1968
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
1969
|
+
"Objective sense is maximize\n");
|
|
1970
|
+
else
|
|
1971
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
1972
|
+
"Objective sense is ill-defined as %" HIGHSINT_FORMAT "\n",
|
|
1973
|
+
lp.sense_);
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
static std::string getBoundType(const double lower, const double upper) {
|
|
1977
|
+
std::string type;
|
|
1978
|
+
if (highs_isInfinity(-lower)) {
|
|
1979
|
+
if (highs_isInfinity(upper)) {
|
|
1980
|
+
type = "FR";
|
|
1981
|
+
} else {
|
|
1982
|
+
type = "UB";
|
|
1983
|
+
}
|
|
1984
|
+
} else {
|
|
1985
|
+
if (highs_isInfinity(upper)) {
|
|
1986
|
+
type = "LB";
|
|
1987
|
+
} else {
|
|
1988
|
+
if (lower < upper) {
|
|
1989
|
+
type = "BX";
|
|
1990
|
+
} else {
|
|
1991
|
+
type = "FX";
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
return type;
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
// Report the vectors of LP column data
|
|
1999
|
+
void reportLpColVectors(const HighsLogOptions& log_options, const HighsLp& lp) {
|
|
2000
|
+
if (lp.num_col_ <= 0) return;
|
|
2001
|
+
std::string type;
|
|
2002
|
+
HighsInt count;
|
|
2003
|
+
bool have_integer_columns = (getNumInt(lp) != 0);
|
|
2004
|
+
bool have_col_names =
|
|
2005
|
+
lp.col_names_.size() == static_cast<size_t>(lp.num_col_);
|
|
2006
|
+
|
|
2007
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
2008
|
+
" Column Lower Upper Cost "
|
|
2009
|
+
"Type Count");
|
|
2010
|
+
if (have_integer_columns)
|
|
2011
|
+
highsLogUser(log_options, HighsLogType::kInfo, " Discrete");
|
|
2012
|
+
if (have_col_names) highsLogUser(log_options, HighsLogType::kInfo, " Name");
|
|
2013
|
+
highsLogUser(log_options, HighsLogType::kInfo, "\n");
|
|
2014
|
+
|
|
2015
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
2016
|
+
type = getBoundType(lp.col_lower_[iCol], lp.col_upper_[iCol]);
|
|
2017
|
+
count = lp.a_matrix_.start_[iCol + 1] - lp.a_matrix_.start_[iCol];
|
|
2018
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
2019
|
+
"%8" HIGHSINT_FORMAT
|
|
2020
|
+
" %12g %12g %12g %2s %12" HIGHSINT_FORMAT "",
|
|
2021
|
+
iCol, lp.col_lower_[iCol], lp.col_upper_[iCol],
|
|
2022
|
+
lp.col_cost_[iCol], type.c_str(), count);
|
|
2023
|
+
if (have_integer_columns) {
|
|
2024
|
+
std::string integer_column = "";
|
|
2025
|
+
if (lp.integrality_[iCol] == HighsVarType::kInteger) {
|
|
2026
|
+
if (lp.col_lower_[iCol] == 0 && lp.col_upper_[iCol] == 1) {
|
|
2027
|
+
integer_column = "Binary";
|
|
2028
|
+
} else {
|
|
2029
|
+
integer_column = "Integer";
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
highsLogUser(log_options, HighsLogType::kInfo, " %-8s",
|
|
2033
|
+
integer_column.c_str());
|
|
2034
|
+
}
|
|
2035
|
+
if (have_col_names)
|
|
2036
|
+
highsLogUser(log_options, HighsLogType::kInfo, " %-s",
|
|
2037
|
+
lp.col_names_[iCol].c_str());
|
|
2038
|
+
highsLogUser(log_options, HighsLogType::kInfo, "\n");
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
// Report the vectors of LP row data
|
|
2043
|
+
void reportLpRowVectors(const HighsLogOptions& log_options, const HighsLp& lp) {
|
|
2044
|
+
if (lp.num_row_ <= 0) return;
|
|
2045
|
+
std::string type;
|
|
2046
|
+
vector<HighsInt> count;
|
|
2047
|
+
bool have_row_names = (lp.row_names_.size() != 0);
|
|
2048
|
+
|
|
2049
|
+
count.resize(lp.num_row_, 0);
|
|
2050
|
+
if (lp.num_col_ > 0) {
|
|
2051
|
+
for (HighsInt el = 0; el < lp.a_matrix_.start_[lp.num_col_]; el++)
|
|
2052
|
+
count[lp.a_matrix_.index_[el]]++;
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
2056
|
+
" Row Lower Upper Type Count");
|
|
2057
|
+
if (have_row_names) highsLogUser(log_options, HighsLogType::kInfo, " Name");
|
|
2058
|
+
highsLogUser(log_options, HighsLogType::kInfo, "\n");
|
|
2059
|
+
|
|
2060
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
2061
|
+
type = getBoundType(lp.row_lower_[iRow], lp.row_upper_[iRow]);
|
|
2062
|
+
std::string name = "";
|
|
2063
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
2064
|
+
"%8" HIGHSINT_FORMAT
|
|
2065
|
+
" %12g %12g %2s %12" HIGHSINT_FORMAT "",
|
|
2066
|
+
iRow, lp.row_lower_[iRow], lp.row_upper_[iRow], type.c_str(),
|
|
2067
|
+
count[iRow]);
|
|
2068
|
+
if (have_row_names)
|
|
2069
|
+
highsLogUser(log_options, HighsLogType::kInfo, " %-s",
|
|
2070
|
+
lp.row_names_[iRow].c_str());
|
|
2071
|
+
highsLogUser(log_options, HighsLogType::kInfo, "\n");
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
// Report the LP column-wise matrix
|
|
2076
|
+
void reportLpColMatrix(const HighsLogOptions& log_options, const HighsLp& lp) {
|
|
2077
|
+
if (lp.num_col_ <= 0) return;
|
|
2078
|
+
if (lp.num_row_) {
|
|
2079
|
+
// With positive number of rows, can assume that there are index and value
|
|
2080
|
+
// vectors to pass
|
|
2081
|
+
reportMatrix(log_options, "Column", lp.num_col_,
|
|
2082
|
+
lp.a_matrix_.start_[lp.num_col_], lp.a_matrix_.start_.data(),
|
|
2083
|
+
lp.a_matrix_.index_.data(), lp.a_matrix_.value_.data());
|
|
2084
|
+
} else {
|
|
2085
|
+
// With no rows, can's assume that there are index and value vectors to pass
|
|
2086
|
+
reportMatrix(log_options, "Column", lp.num_col_,
|
|
2087
|
+
lp.a_matrix_.start_[lp.num_col_], lp.a_matrix_.start_.data(),
|
|
2088
|
+
NULL, NULL);
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
void reportMatrix(const HighsLogOptions& log_options,
|
|
2093
|
+
const std::string& message, const HighsInt num_col,
|
|
2094
|
+
const HighsInt num_nz, const HighsInt* start,
|
|
2095
|
+
const HighsInt* index, const double* value) {
|
|
2096
|
+
if (num_col <= 0) return;
|
|
2097
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
2098
|
+
"%-7s Index Value\n", message.c_str());
|
|
2099
|
+
for (HighsInt col = 0; col < num_col; col++) {
|
|
2100
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
2101
|
+
" %8" HIGHSINT_FORMAT " Start %10" HIGHSINT_FORMAT "\n",
|
|
2102
|
+
col, start[col]);
|
|
2103
|
+
HighsInt to_el = (col < num_col - 1 ? start[col + 1] : num_nz);
|
|
2104
|
+
for (HighsInt el = start[col]; el < to_el; el++)
|
|
2105
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
2106
|
+
" %8" HIGHSINT_FORMAT " %12g\n", index[el],
|
|
2107
|
+
value[el]);
|
|
2108
|
+
}
|
|
2109
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
2110
|
+
" Start %10" HIGHSINT_FORMAT "\n", num_nz);
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
void analyseLp(const HighsLogOptions& log_options, const HighsLp& lp) {
|
|
2114
|
+
/*
|
|
2115
|
+
vector<double> min_colBound;
|
|
2116
|
+
vector<double> min_rowBound;
|
|
2117
|
+
vector<double> colRange;
|
|
2118
|
+
vector<double> rowRange;
|
|
2119
|
+
min_colBound.resize(lp.num_col_);
|
|
2120
|
+
min_rowBound.resize(lp.num_row_);
|
|
2121
|
+
colRange.resize(lp.num_col_);
|
|
2122
|
+
rowRange.resize(lp.num_row_);
|
|
2123
|
+
for (HighsInt col = 0; col < lp.num_col_; col++)
|
|
2124
|
+
min_colBound[col] = min(fabs(lp.col_lower_[col]), fabs(lp.col_upper_[col]));
|
|
2125
|
+
for (HighsInt row = 0; row < lp.num_row_; row++)
|
|
2126
|
+
min_rowBound[row] = min(fabs(lp.row_lower_[row]), fabs(lp.row_upper_[row]));
|
|
2127
|
+
for (HighsInt col = 0; col < lp.num_col_; col++)
|
|
2128
|
+
colRange[col] = lp.col_upper_[col] - lp.col_lower_[col];
|
|
2129
|
+
for (HighsInt row = 0; row < lp.num_row_; row++)
|
|
2130
|
+
rowRange[row] = lp.row_upper_[row] - lp.row_lower_[row];
|
|
2131
|
+
*/
|
|
2132
|
+
std::string message;
|
|
2133
|
+
if (lp.is_scaled_) {
|
|
2134
|
+
message = "Scaled";
|
|
2135
|
+
} else {
|
|
2136
|
+
message = "Unscaled";
|
|
2137
|
+
}
|
|
2138
|
+
highsLogDev(log_options, HighsLogType::kInfo, "\n%s model data: Analysis\n",
|
|
2139
|
+
message.c_str());
|
|
2140
|
+
if (lp.is_scaled_) {
|
|
2141
|
+
const HighsScale& scale = lp.scale_;
|
|
2142
|
+
analyseVectorValues(&log_options, "Column scaling factors", lp.num_col_,
|
|
2143
|
+
scale.col, true, lp.model_name_);
|
|
2144
|
+
analyseVectorValues(&log_options, "Row scaling factors", lp.num_row_,
|
|
2145
|
+
scale.row, true, lp.model_name_);
|
|
2146
|
+
}
|
|
2147
|
+
analyseVectorValues(&log_options, "Column costs", lp.num_col_, lp.col_cost_,
|
|
2148
|
+
true, lp.model_name_);
|
|
2149
|
+
analyseVectorValues(&log_options, "Column lower bounds", lp.num_col_,
|
|
2150
|
+
lp.col_lower_, true, lp.model_name_);
|
|
2151
|
+
analyseVectorValues(&log_options, "Column upper bounds", lp.num_col_,
|
|
2152
|
+
lp.col_upper_, true, lp.model_name_);
|
|
2153
|
+
// analyseVectorValues(&log_options, "Column min abs bound", lp.num_col_,
|
|
2154
|
+
// min_colBound, true, lp.model_name_);
|
|
2155
|
+
// analyseVectorValues(&log_options, "Column range", lp.num_col_, colRange,
|
|
2156
|
+
// true,
|
|
2157
|
+
// lp.model_name_);
|
|
2158
|
+
analyseVectorValues(&log_options, "Row lower bounds", lp.num_row_,
|
|
2159
|
+
lp.row_lower_, true, lp.model_name_);
|
|
2160
|
+
analyseVectorValues(&log_options, "Row upper bounds", lp.num_row_,
|
|
2161
|
+
lp.row_upper_, true, lp.model_name_);
|
|
2162
|
+
// analyseVectorValues(&log_options, "Row min abs bound", lp.num_row_,
|
|
2163
|
+
// min_rowBound, true, lp.model_name_);
|
|
2164
|
+
// analyseVectorValues(&log_options, "Row range", lp.num_row_, rowRange,
|
|
2165
|
+
// true,
|
|
2166
|
+
// lp.model_name_);
|
|
2167
|
+
analyseVectorValues(&log_options, "Matrix sparsity",
|
|
2168
|
+
lp.a_matrix_.start_[lp.num_col_], lp.a_matrix_.value_,
|
|
2169
|
+
true, lp.model_name_);
|
|
2170
|
+
analyseMatrixSparsity(log_options, "Constraint matrix", lp.num_col_,
|
|
2171
|
+
lp.num_row_, lp.a_matrix_.start_, lp.a_matrix_.index_);
|
|
2172
|
+
analyseModelBounds(log_options, "Column", lp.num_col_, lp.col_lower_,
|
|
2173
|
+
lp.col_upper_);
|
|
2174
|
+
analyseModelBounds(log_options, "Row", lp.num_row_, lp.row_lower_,
|
|
2175
|
+
lp.row_upper_);
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
HighsStatus readSolutionFile(const std::string& filename,
|
|
2179
|
+
const HighsOptions& options, HighsLp& lp,
|
|
2180
|
+
HighsBasis& basis, HighsSolution& solution,
|
|
2181
|
+
const HighsInt style) {
|
|
2182
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
2183
|
+
const HighsLogOptions& log_options = options.log_options;
|
|
2184
|
+
if (style != kSolutionStyleRaw && style != kSolutionStyleSparse) {
|
|
2185
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
2186
|
+
"readSolutionFile: Cannot read file of style %d\n",
|
|
2187
|
+
(int)style);
|
|
2188
|
+
return HighsStatus::kError;
|
|
2189
|
+
}
|
|
2190
|
+
std::ifstream in_file(filename);
|
|
2191
|
+
if (in_file.fail()) {
|
|
2192
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
2193
|
+
"readSolutionFile: Cannot open readable file \"%s\"\n",
|
|
2194
|
+
filename.c_str());
|
|
2195
|
+
return HighsStatus::kError;
|
|
2196
|
+
}
|
|
2197
|
+
std::string from_method = "readSolutionFile";
|
|
2198
|
+
std::string hash;
|
|
2199
|
+
std::string keyword;
|
|
2200
|
+
std::string value_string;
|
|
2201
|
+
std::string name;
|
|
2202
|
+
double value;
|
|
2203
|
+
HighsInt num_col = -1;
|
|
2204
|
+
HighsInt num_row = -1;
|
|
2205
|
+
const HighsInt lp_num_col = lp.num_col_;
|
|
2206
|
+
const HighsInt lp_num_row = lp.num_row_;
|
|
2207
|
+
// Define identifiers for reading in
|
|
2208
|
+
HighsSolution read_solution = solution;
|
|
2209
|
+
HighsBasis read_basis = basis;
|
|
2210
|
+
read_solution.clear();
|
|
2211
|
+
read_basis.clear();
|
|
2212
|
+
read_solution.col_value.resize(lp_num_col);
|
|
2213
|
+
read_solution.row_value.resize(lp_num_row);
|
|
2214
|
+
read_solution.col_dual.resize(lp_num_col);
|
|
2215
|
+
read_solution.row_dual.resize(lp_num_row);
|
|
2216
|
+
read_basis.col_status.resize(lp_num_col);
|
|
2217
|
+
read_basis.row_status.resize(lp_num_row);
|
|
2218
|
+
std::string section_name;
|
|
2219
|
+
if (!readSolutionFileIdIgnoreLineOk(section_name, in_file))
|
|
2220
|
+
return readSolutionFileErrorReturn(
|
|
2221
|
+
in_file); // Model (status) or =obj= (value)
|
|
2222
|
+
const bool miplib_sol = section_name == "=obj=";
|
|
2223
|
+
const bool have_col_names =
|
|
2224
|
+
lp.col_names_.size() == static_cast<size_t>(lp_num_col);
|
|
2225
|
+
const bool have_row_names =
|
|
2226
|
+
lp.row_names_.size() == static_cast<size_t>(lp_num_row);
|
|
2227
|
+
if (miplib_sol) {
|
|
2228
|
+
// A MIPLIB solution file has nonzero solution values for a subset
|
|
2229
|
+
// of the variables identified by name, so there must be column
|
|
2230
|
+
// names,
|
|
2231
|
+
if (!have_col_names) {
|
|
2232
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
2233
|
+
"readSolutionFile: Cannot read a MIPLIB solution file "
|
|
2234
|
+
"without column names in the model\n");
|
|
2235
|
+
return HighsStatus::kError;
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
if (have_col_names) {
|
|
2239
|
+
// Ensure that the col name hash table has been formed
|
|
2240
|
+
if (!lp.col_hash_.name2index.size()) lp.col_hash_.form(lp.col_names_);
|
|
2241
|
+
}
|
|
2242
|
+
if (have_row_names) {
|
|
2243
|
+
// Ensure that the row name hash table has been formed
|
|
2244
|
+
if (!lp.row_hash_.name2index.size()) lp.row_hash_.form(lp.row_names_);
|
|
2245
|
+
}
|
|
2246
|
+
bool sparse = false;
|
|
2247
|
+
if (!miplib_sol) {
|
|
2248
|
+
if (!readSolutionFileIgnoreLineOk(in_file))
|
|
2249
|
+
return readSolutionFileErrorReturn(in_file); // Optimal
|
|
2250
|
+
if (!readSolutionFileIgnoreLineOk(in_file))
|
|
2251
|
+
return readSolutionFileErrorReturn(in_file); //
|
|
2252
|
+
if (!readSolutionFileIgnoreLineOk(in_file))
|
|
2253
|
+
return readSolutionFileErrorReturn(in_file); // # Primal solution values
|
|
2254
|
+
if (!readSolutionFileKeywordLineOk(keyword, in_file))
|
|
2255
|
+
return readSolutionFileErrorReturn(in_file);
|
|
2256
|
+
// Read in the primal solution values: return warning if there is none
|
|
2257
|
+
if (keyword == "None")
|
|
2258
|
+
return readSolutionFileReturn(HighsStatus::kWarning, solution, basis,
|
|
2259
|
+
read_solution, read_basis, in_file);
|
|
2260
|
+
// If there are primal solution values then keyword is the status
|
|
2261
|
+
// and the next line is objective
|
|
2262
|
+
if (!readSolutionFileIgnoreLineOk(in_file))
|
|
2263
|
+
return readSolutionFileErrorReturn(in_file); // EOL
|
|
2264
|
+
if (!readSolutionFileIgnoreLineOk(in_file))
|
|
2265
|
+
return readSolutionFileErrorReturn(in_file); // Objective
|
|
2266
|
+
// Next line should be "Columns" and correct number
|
|
2267
|
+
if (!readSolutionFileHashKeywordIntLineOk(hash, keyword, value_string,
|
|
2268
|
+
num_col, in_file)) {
|
|
2269
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
2270
|
+
"readSolutionFile: Error reading line \"%s %s %s\"\n",
|
|
2271
|
+
hash.c_str(), keyword.c_str(), value_string.c_str());
|
|
2272
|
+
return readSolutionFileErrorReturn(in_file);
|
|
2273
|
+
}
|
|
2274
|
+
assert(keyword == "Columns");
|
|
2275
|
+
// The default style parameter is kSolutionStyleRaw, and this still
|
|
2276
|
+
// allows sparse files to be read. Recognise the latter from num_col
|
|
2277
|
+
// <= 0. Doesn't matter if num_col = 0, since there's nothing to
|
|
2278
|
+
// read either way
|
|
2279
|
+
sparse = num_col <= 0;
|
|
2280
|
+
if (style == kSolutionStyleSparse) assert(sparse);
|
|
2281
|
+
if (sparse) {
|
|
2282
|
+
num_col = -num_col;
|
|
2283
|
+
assert(num_col <= lp_num_col);
|
|
2284
|
+
} else {
|
|
2285
|
+
if (num_col != lp_num_col) {
|
|
2286
|
+
highsLogUser(
|
|
2287
|
+
log_options, HighsLogType::kError,
|
|
2288
|
+
"readSolutionFile: Solution file is for %d columns, not %d\n",
|
|
2289
|
+
int(num_col), int(lp_num_col));
|
|
2290
|
+
return readSolutionFileErrorReturn(in_file);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
bool is_col = true;
|
|
2295
|
+
HighsInt iCol;
|
|
2296
|
+
if (miplib_sol) {
|
|
2297
|
+
HighsInt num_value = 0;
|
|
2298
|
+
read_solution.col_value.assign(lp_num_col, 0);
|
|
2299
|
+
assert(is_col);
|
|
2300
|
+
for (;;) {
|
|
2301
|
+
// Only false return is for encountering EOF
|
|
2302
|
+
if (!readSolutionFileIdDoubleLineOk(name, value, in_file)) break;
|
|
2303
|
+
return_status =
|
|
2304
|
+
getIndexFromName(log_options, from_method, is_col, name,
|
|
2305
|
+
lp.col_hash_.name2index, iCol, lp.col_names_);
|
|
2306
|
+
if (return_status != HighsStatus::kOk) return return_status;
|
|
2307
|
+
read_solution.col_value[iCol] = value;
|
|
2308
|
+
num_value++;
|
|
2309
|
+
if (in_file.eof()) break;
|
|
2310
|
+
}
|
|
2311
|
+
} else if (sparse) {
|
|
2312
|
+
read_solution.col_value.assign(lp_num_col, 0);
|
|
2313
|
+
for (HighsInt iX = 0; iX < num_col; iX++) {
|
|
2314
|
+
if (!readSolutionFileIdDoubleIntLineOk(name, value, iCol, in_file))
|
|
2315
|
+
return readSolutionFileErrorReturn(in_file);
|
|
2316
|
+
if (have_col_names) {
|
|
2317
|
+
// Use the column name if possible
|
|
2318
|
+
return_status =
|
|
2319
|
+
getIndexFromName(log_options, from_method, is_col, name,
|
|
2320
|
+
lp.col_hash_.name2index, iCol, lp.col_names_);
|
|
2321
|
+
if (return_status != HighsStatus::kOk) return return_status;
|
|
2322
|
+
}
|
|
2323
|
+
read_solution.col_value[iCol] = value;
|
|
2324
|
+
}
|
|
2325
|
+
} else {
|
|
2326
|
+
assert(is_col);
|
|
2327
|
+
for (HighsInt iX = 0; iX < num_col; iX++) {
|
|
2328
|
+
if (!readSolutionFileIdDoubleLineOk(name, value, in_file))
|
|
2329
|
+
return readSolutionFileErrorReturn(in_file);
|
|
2330
|
+
if (have_col_names) {
|
|
2331
|
+
// Use the column name if possible
|
|
2332
|
+
return_status =
|
|
2333
|
+
getIndexFromName(log_options, from_method, is_col, name,
|
|
2334
|
+
lp.col_hash_.name2index, iCol, lp.col_names_);
|
|
2335
|
+
if (return_status != HighsStatus::kOk) return return_status;
|
|
2336
|
+
} else {
|
|
2337
|
+
// Have to assume column solution values are in the right order
|
|
2338
|
+
iCol = iX;
|
|
2339
|
+
}
|
|
2340
|
+
read_solution.col_value[iCol] = value;
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
read_solution.value_valid = true;
|
|
2344
|
+
if (miplib_sol || sparse) {
|
|
2345
|
+
// MIPLIB and sparse format only have column values, so compute
|
|
2346
|
+
// the row values and return
|
|
2347
|
+
if (calculateRowValuesQuad(lp, read_solution.col_value,
|
|
2348
|
+
read_solution.row_value) != HighsStatus::kOk)
|
|
2349
|
+
return readSolutionFileErrorReturn(in_file);
|
|
2350
|
+
return readSolutionFileReturn(HighsStatus::kOk, solution, basis,
|
|
2351
|
+
read_solution, read_basis, in_file);
|
|
2352
|
+
}
|
|
2353
|
+
// Read in the row values: OK to have none, otherwise next line
|
|
2354
|
+
// should be "Rows" and correct number
|
|
2355
|
+
if (!readSolutionFileHashKeywordIntLineOk(hash, keyword, value_string,
|
|
2356
|
+
num_row, in_file)) {
|
|
2357
|
+
// Compute the row values since there are none to read
|
|
2358
|
+
if (calculateRowValuesQuad(lp, read_solution.col_value,
|
|
2359
|
+
read_solution.row_value) != HighsStatus::kOk)
|
|
2360
|
+
return readSolutionFileErrorReturn(in_file);
|
|
2361
|
+
return readSolutionFileReturn(HighsStatus::kOk, solution, basis,
|
|
2362
|
+
read_solution, read_basis, in_file);
|
|
2363
|
+
}
|
|
2364
|
+
assert(keyword == "Rows");
|
|
2365
|
+
// OK to read from a file with different number of rows, since the
|
|
2366
|
+
// primal solution is all that's important. For example, see #1284,
|
|
2367
|
+
// where the user is solving a sequence of MIPs with the same number
|
|
2368
|
+
// of variables, but increasing numbers of constraints, and wants to
|
|
2369
|
+
// used the solution from one MIP as the starting solution for the
|
|
2370
|
+
// next.
|
|
2371
|
+
HighsInt iRow;
|
|
2372
|
+
const bool num_row_ok = num_row == lp_num_row;
|
|
2373
|
+
assert(!have_row_names || lp.row_hash_.name2index.size());
|
|
2374
|
+
is_col = false;
|
|
2375
|
+
assert(!is_col);
|
|
2376
|
+
for (HighsInt iX = 0; iX < num_row; iX++) {
|
|
2377
|
+
if (!readSolutionFileIdDoubleLineOk(name, value, in_file))
|
|
2378
|
+
return readSolutionFileErrorReturn(in_file);
|
|
2379
|
+
if (num_row_ok) {
|
|
2380
|
+
if (have_row_names) {
|
|
2381
|
+
// Use the row name if possible
|
|
2382
|
+
return_status =
|
|
2383
|
+
getIndexFromName(log_options, from_method, is_col, name,
|
|
2384
|
+
lp.row_hash_.name2index, iRow, lp.row_names_);
|
|
2385
|
+
if (return_status != HighsStatus::kOk) return return_status;
|
|
2386
|
+
} else {
|
|
2387
|
+
// Have to assume row solution values are in the right order
|
|
2388
|
+
iRow = iX;
|
|
2389
|
+
}
|
|
2390
|
+
read_solution.row_value[iRow] = value;
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
if (!num_row_ok) {
|
|
2394
|
+
highsLogUser(log_options, HighsLogType::kWarning,
|
|
2395
|
+
"readSolutionFile: Solution file is for %d rows, not %d: row "
|
|
2396
|
+
"values ignored\n",
|
|
2397
|
+
int(num_row), int(lp_num_row));
|
|
2398
|
+
// Calculate the row values
|
|
2399
|
+
if (calculateRowValuesQuad(lp, read_solution.col_value,
|
|
2400
|
+
read_solution.row_value) != HighsStatus::kOk)
|
|
2401
|
+
return readSolutionFileErrorReturn(in_file);
|
|
2402
|
+
}
|
|
2403
|
+
// OK to have no EOL
|
|
2404
|
+
if (!readSolutionFileIgnoreLineOk(in_file))
|
|
2405
|
+
return readSolutionFileReturn(HighsStatus::kOk, solution, basis,
|
|
2406
|
+
read_solution, read_basis,
|
|
2407
|
+
in_file); // EOL
|
|
2408
|
+
// OK to have no blank line
|
|
2409
|
+
if (!readSolutionFileIgnoreLineOk(in_file))
|
|
2410
|
+
return readSolutionFileReturn(HighsStatus::kOk, solution, basis,
|
|
2411
|
+
read_solution, read_basis,
|
|
2412
|
+
in_file); //
|
|
2413
|
+
// OK to have no reference to dual solution values
|
|
2414
|
+
if (!readSolutionFileIgnoreLineOk(in_file))
|
|
2415
|
+
return readSolutionFileReturn(HighsStatus::kOk, solution, basis,
|
|
2416
|
+
read_solution, read_basis,
|
|
2417
|
+
in_file); // # Dual solution values
|
|
2418
|
+
// If there's a reference to dual solution values, there's a keyword
|
|
2419
|
+
// to indicate their status
|
|
2420
|
+
if (!readSolutionFileKeywordLineOk(keyword, in_file))
|
|
2421
|
+
return readSolutionFileErrorReturn(in_file);
|
|
2422
|
+
if (keyword != "None") {
|
|
2423
|
+
if (!readSolutionFileIgnoreLineOk(in_file))
|
|
2424
|
+
return readSolutionFileErrorReturn(in_file); // EOL
|
|
2425
|
+
// Next line should be "Columns" and correct number
|
|
2426
|
+
if (!readSolutionFileHashKeywordIntLineOk(hash, keyword, value_string,
|
|
2427
|
+
num_col, in_file)) {
|
|
2428
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
2429
|
+
"readSolutionFile: Error reading line \"%s %s %s\"\n",
|
|
2430
|
+
hash.c_str(), keyword.c_str(), value_string.c_str());
|
|
2431
|
+
return readSolutionFileReturn(HighsStatus::kOk, solution, basis,
|
|
2432
|
+
read_solution, read_basis, in_file);
|
|
2433
|
+
}
|
|
2434
|
+
assert(keyword == "Columns");
|
|
2435
|
+
double dual;
|
|
2436
|
+
is_col = true;
|
|
2437
|
+
assert(is_col);
|
|
2438
|
+
for (HighsInt iX = 0; iX < num_col; iX++) {
|
|
2439
|
+
if (!readSolutionFileIdDoubleLineOk(name, dual, in_file))
|
|
2440
|
+
return readSolutionFileErrorReturn(in_file);
|
|
2441
|
+
if (have_col_names) {
|
|
2442
|
+
// Use the column name if possible
|
|
2443
|
+
return_status =
|
|
2444
|
+
getIndexFromName(log_options, from_method, is_col, name,
|
|
2445
|
+
lp.col_hash_.name2index, iCol, lp.col_names_);
|
|
2446
|
+
if (return_status != HighsStatus::kOk) return return_status;
|
|
2447
|
+
} else {
|
|
2448
|
+
// Have to assume column dual values are in the right order
|
|
2449
|
+
iCol = iX;
|
|
2450
|
+
}
|
|
2451
|
+
read_solution.col_dual[iCol] = dual;
|
|
2452
|
+
}
|
|
2453
|
+
// Read in the col dual values: next line should be "Rows" and correct
|
|
2454
|
+
// number
|
|
2455
|
+
if (!readSolutionFileHashKeywordIntLineOk(hash, keyword, value_string,
|
|
2456
|
+
num_col, in_file)) {
|
|
2457
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
2458
|
+
"readSolutionFile: Error reading line \"%s %s %s\"\n",
|
|
2459
|
+
hash.c_str(), keyword.c_str(), value_string.c_str());
|
|
2460
|
+
return readSolutionFileReturn(HighsStatus::kOk, solution, basis,
|
|
2461
|
+
read_solution, read_basis, in_file);
|
|
2462
|
+
}
|
|
2463
|
+
assert(keyword == "Rows");
|
|
2464
|
+
is_col = false;
|
|
2465
|
+
assert(!is_col);
|
|
2466
|
+
for (HighsInt iX = 0; iX < num_row; iX++) {
|
|
2467
|
+
if (!readSolutionFileIdDoubleLineOk(name, dual, in_file))
|
|
2468
|
+
return readSolutionFileErrorReturn(in_file);
|
|
2469
|
+
if (have_row_names) {
|
|
2470
|
+
// Use the row name if possible
|
|
2471
|
+
return_status =
|
|
2472
|
+
getIndexFromName(log_options, from_method, is_col, name,
|
|
2473
|
+
lp.row_hash_.name2index, iRow, lp.row_names_);
|
|
2474
|
+
if (return_status != HighsStatus::kOk) return return_status;
|
|
2475
|
+
} else {
|
|
2476
|
+
// Have to assume row dual values are in the right order
|
|
2477
|
+
iRow = iX;
|
|
2478
|
+
}
|
|
2479
|
+
read_solution.row_dual[iRow] = dual;
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
// OK to have no EOL
|
|
2483
|
+
if (!readSolutionFileIgnoreLineOk(in_file))
|
|
2484
|
+
return readSolutionFileReturn(HighsStatus::kOk, solution, basis,
|
|
2485
|
+
read_solution, read_basis,
|
|
2486
|
+
in_file); // EOL
|
|
2487
|
+
// OK to have no blank line
|
|
2488
|
+
if (!readSolutionFileIgnoreLineOk(in_file))
|
|
2489
|
+
return readSolutionFileReturn(HighsStatus::kOk, solution, basis,
|
|
2490
|
+
read_solution, read_basis,
|
|
2491
|
+
in_file); //
|
|
2492
|
+
// OK to have no reference to basis
|
|
2493
|
+
if (!readSolutionFileIgnoreLineOk(in_file))
|
|
2494
|
+
return readSolutionFileReturn(HighsStatus::kOk, solution, basis,
|
|
2495
|
+
read_solution, read_basis,
|
|
2496
|
+
in_file); // # Basis
|
|
2497
|
+
HighsStatus basis_read_status =
|
|
2498
|
+
readBasisStream(log_options, lp, read_basis, in_file);
|
|
2499
|
+
// Return with basis read status
|
|
2500
|
+
return readSolutionFileReturn(basis_read_status, solution, basis,
|
|
2501
|
+
read_solution, read_basis, in_file);
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
HighsStatus readSolutionFileErrorReturn(std::ifstream& in_file) {
|
|
2505
|
+
in_file.close();
|
|
2506
|
+
return HighsStatus::kError;
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
HighsStatus readSolutionFileReturn(const HighsStatus status,
|
|
2510
|
+
HighsSolution& solution, HighsBasis& basis,
|
|
2511
|
+
const HighsSolution& read_solution,
|
|
2512
|
+
const HighsBasis& read_basis,
|
|
2513
|
+
std::ifstream& in_file) {
|
|
2514
|
+
in_file.close();
|
|
2515
|
+
if (status != HighsStatus::kOk) {
|
|
2516
|
+
return status;
|
|
2517
|
+
}
|
|
2518
|
+
solution = read_solution;
|
|
2519
|
+
basis = read_basis;
|
|
2520
|
+
return HighsStatus::kOk;
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
bool readSolutionFileIgnoreLineOk(std::ifstream& in_file) {
|
|
2524
|
+
if (in_file.eof()) return false;
|
|
2525
|
+
in_file.ignore(kMaxLineLength, '\n');
|
|
2526
|
+
return true;
|
|
2527
|
+
}
|
|
2528
|
+
|
|
2529
|
+
bool readSolutionFileKeywordLineOk(std::string& keyword,
|
|
2530
|
+
std::ifstream& in_file) {
|
|
2531
|
+
if (in_file.eof()) return false;
|
|
2532
|
+
in_file >> keyword;
|
|
2533
|
+
return true;
|
|
2534
|
+
}
|
|
2535
|
+
|
|
2536
|
+
bool readSolutionFileHashKeywordIntLineOk(std::string& hash,
|
|
2537
|
+
std::string& keyword,
|
|
2538
|
+
std::string& value_string,
|
|
2539
|
+
HighsInt& value,
|
|
2540
|
+
std::ifstream& in_file) {
|
|
2541
|
+
hash = "";
|
|
2542
|
+
keyword = "";
|
|
2543
|
+
value_string = "";
|
|
2544
|
+
// Read the hash symbol
|
|
2545
|
+
if (in_file.eof()) return false;
|
|
2546
|
+
in_file >> hash; // #
|
|
2547
|
+
if (hash != "#") return false;
|
|
2548
|
+
|
|
2549
|
+
// Read the keyword
|
|
2550
|
+
if (in_file.eof()) return false;
|
|
2551
|
+
in_file >> keyword; // keyword
|
|
2552
|
+
|
|
2553
|
+
// Read the value
|
|
2554
|
+
if (in_file.eof()) return false;
|
|
2555
|
+
// Read as a string, and then check it only contains digits
|
|
2556
|
+
in_file >> value_string;
|
|
2557
|
+
if (value_string[std::strspn(value_string.c_str(), "-0123456789")])
|
|
2558
|
+
return false;
|
|
2559
|
+
value = std::stoi(value_string); // integer value
|
|
2560
|
+
return true;
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
bool readSolutionFileIdIgnoreLineOk(std::string& id, std::ifstream& in_file) {
|
|
2564
|
+
if (in_file.eof()) return false;
|
|
2565
|
+
in_file >> id; // Id
|
|
2566
|
+
in_file.ignore(kMaxLineLength, '\n');
|
|
2567
|
+
return true;
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
bool readSolutionFileIdDoubleLineOk(std::string& id, double& value,
|
|
2571
|
+
std::ifstream& in_file) {
|
|
2572
|
+
if (in_file.eof()) return false;
|
|
2573
|
+
in_file >> id; // Id
|
|
2574
|
+
if (in_file.eof()) return false;
|
|
2575
|
+
in_file >> value; // double value
|
|
2576
|
+
return true;
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
bool readSolutionFileIdDoubleIntLineOk(std::string& id, double& value,
|
|
2580
|
+
HighsInt& index,
|
|
2581
|
+
std::ifstream& in_file) {
|
|
2582
|
+
if (in_file.eof()) return false;
|
|
2583
|
+
in_file >> id; // Id
|
|
2584
|
+
if (in_file.eof()) return false;
|
|
2585
|
+
in_file >> value; // double value
|
|
2586
|
+
if (in_file.eof()) return false;
|
|
2587
|
+
in_file >> index; // double value
|
|
2588
|
+
return true;
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
void assessColPrimalSolution(const HighsOptions& options, const double primal,
|
|
2592
|
+
const double lower, const double upper,
|
|
2593
|
+
const HighsVarType type, double& col_infeasibility,
|
|
2594
|
+
double& integer_infeasibility) {
|
|
2595
|
+
// @primal_infeasibility calculation
|
|
2596
|
+
col_infeasibility = 0;
|
|
2597
|
+
if (primal < lower - options.primal_feasibility_tolerance) {
|
|
2598
|
+
col_infeasibility = lower - primal;
|
|
2599
|
+
} else if (primal > upper + options.primal_feasibility_tolerance) {
|
|
2600
|
+
col_infeasibility = primal - upper;
|
|
2601
|
+
}
|
|
2602
|
+
integer_infeasibility = 0;
|
|
2603
|
+
if (type == HighsVarType::kInteger || type == HighsVarType::kSemiInteger) {
|
|
2604
|
+
integer_infeasibility = fractionality(primal);
|
|
2605
|
+
}
|
|
2606
|
+
if (col_infeasibility > 0 && (type == HighsVarType::kSemiContinuous ||
|
|
2607
|
+
type == HighsVarType::kSemiInteger)) {
|
|
2608
|
+
// Semi-variables at zero will have positive col
|
|
2609
|
+
// infeasibility, so possibly zero this
|
|
2610
|
+
if (std::fabs(primal) <= options.mip_feasibility_tolerance)
|
|
2611
|
+
col_infeasibility = 0;
|
|
2612
|
+
// If there is (still) column infeasibility due to value being
|
|
2613
|
+
// off zero or below lower bound, then this counts as an integer
|
|
2614
|
+
// infeasibility
|
|
2615
|
+
if (col_infeasibility && primal < upper)
|
|
2616
|
+
integer_infeasibility =
|
|
2617
|
+
std::max(col_infeasibility, integer_infeasibility);
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
|
|
2621
|
+
// Determine validity, primal feasibility and (when relevant) integer
|
|
2622
|
+
// feasibility of a solution
|
|
2623
|
+
HighsStatus assessLpPrimalSolution(const std::string& message,
|
|
2624
|
+
const HighsOptions& options,
|
|
2625
|
+
const HighsLp& lp,
|
|
2626
|
+
const HighsSolution& solution, bool& valid,
|
|
2627
|
+
bool& integral, bool& feasible) {
|
|
2628
|
+
valid = false;
|
|
2629
|
+
integral = false;
|
|
2630
|
+
feasible = false;
|
|
2631
|
+
HighsInt num_col_infeasibilities = 0;
|
|
2632
|
+
double max_col_infeasibility = 0;
|
|
2633
|
+
double sum_col_infeasibilities = 0;
|
|
2634
|
+
HighsInt num_integer_infeasibilities = 0;
|
|
2635
|
+
double max_integer_infeasibility = 0;
|
|
2636
|
+
double sum_integer_infeasibilities = 0;
|
|
2637
|
+
HighsInt num_row_infeasibilities = 0;
|
|
2638
|
+
double max_row_infeasibility = 0;
|
|
2639
|
+
double sum_row_infeasibilities = 0;
|
|
2640
|
+
HighsInt num_row_residuals = 0;
|
|
2641
|
+
double max_row_residual = 0;
|
|
2642
|
+
double sum_row_residuals = 0;
|
|
2643
|
+
const double kRowResidualTolerance =
|
|
2644
|
+
options.primal_feasibility_tolerance; // 1e-12;
|
|
2645
|
+
const double kPrimalFeasibilityTolerance =
|
|
2646
|
+
lp.isMip() ? options.mip_feasibility_tolerance
|
|
2647
|
+
: options.primal_feasibility_tolerance;
|
|
2648
|
+
highsLogUser(options.log_options, HighsLogType::kInfo,
|
|
2649
|
+
"%sAssessing feasibility of %s tolerance of %11.4g\n",
|
|
2650
|
+
message.c_str(),
|
|
2651
|
+
lp.isMip() ? "MIP using primal feasibility and integrality"
|
|
2652
|
+
: "LP using primal feasibility",
|
|
2653
|
+
kPrimalFeasibilityTolerance);
|
|
2654
|
+
vector<double> row_value;
|
|
2655
|
+
row_value.assign(lp.num_row_, 0);
|
|
2656
|
+
const bool have_integrality = (lp.integrality_.size() != 0);
|
|
2657
|
+
if (!solution.value_valid) return HighsStatus::kError;
|
|
2658
|
+
const bool have_col_names =
|
|
2659
|
+
lp.col_names_.size() == static_cast<size_t>(lp.num_col_);
|
|
2660
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
2661
|
+
const std::string name_string =
|
|
2662
|
+
have_col_names ? (" (" + lp.col_names_[iCol] + ")") : "";
|
|
2663
|
+
const double primal = solution.col_value[iCol];
|
|
2664
|
+
const double lower = lp.col_lower_[iCol];
|
|
2665
|
+
const double upper = lp.col_upper_[iCol];
|
|
2666
|
+
const HighsVarType type =
|
|
2667
|
+
have_integrality ? lp.integrality_[iCol] : HighsVarType::kContinuous;
|
|
2668
|
+
|
|
2669
|
+
double col_infeasibility = 0;
|
|
2670
|
+
double integer_infeasibility = 0;
|
|
2671
|
+
|
|
2672
|
+
assessColPrimalSolution(options, primal, lower, upper, type,
|
|
2673
|
+
col_infeasibility, integer_infeasibility);
|
|
2674
|
+
if (col_infeasibility > 0) {
|
|
2675
|
+
if (col_infeasibility > kPrimalFeasibilityTolerance) {
|
|
2676
|
+
if (col_infeasibility > 2 * max_col_infeasibility)
|
|
2677
|
+
highsLogUser(options.log_options, HighsLogType::kWarning,
|
|
2678
|
+
"Col %6d%s has infeasibility of %11.4g from "
|
|
2679
|
+
"[lower, value, upper] = [%15.8g; %15.8g; %15.8g]\n",
|
|
2680
|
+
int(iCol), name_string.c_str(), col_infeasibility, lower,
|
|
2681
|
+
primal, upper);
|
|
2682
|
+
num_col_infeasibilities++;
|
|
2683
|
+
}
|
|
2684
|
+
max_col_infeasibility =
|
|
2685
|
+
std::max(col_infeasibility, max_col_infeasibility);
|
|
2686
|
+
sum_col_infeasibilities += col_infeasibility;
|
|
2687
|
+
}
|
|
2688
|
+
if (integer_infeasibility > 0) {
|
|
2689
|
+
if (integer_infeasibility > options.mip_feasibility_tolerance) {
|
|
2690
|
+
if (integer_infeasibility > 2 * max_integer_infeasibility)
|
|
2691
|
+
highsLogUser(options.log_options, HighsLogType::kWarning,
|
|
2692
|
+
"Col %6d%s has integer infeasibility of %11.4g\n",
|
|
2693
|
+
(int)iCol, name_string.c_str(), integer_infeasibility);
|
|
2694
|
+
num_integer_infeasibilities++;
|
|
2695
|
+
}
|
|
2696
|
+
max_integer_infeasibility =
|
|
2697
|
+
std::max(integer_infeasibility, max_integer_infeasibility);
|
|
2698
|
+
sum_integer_infeasibilities += integer_infeasibility;
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
HighsStatus return_status =
|
|
2702
|
+
calculateRowValuesQuad(lp, solution.col_value, row_value);
|
|
2703
|
+
if (return_status != HighsStatus::kOk) return return_status;
|
|
2704
|
+
const bool have_row_names =
|
|
2705
|
+
lp.row_names_.size() >= static_cast<size_t>(lp.num_row_);
|
|
2706
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
2707
|
+
const double primal = solution.row_value[iRow];
|
|
2708
|
+
const double lower = lp.row_lower_[iRow];
|
|
2709
|
+
const double upper = lp.row_upper_[iRow];
|
|
2710
|
+
const std::string name_string =
|
|
2711
|
+
have_row_names ? (" (" + lp.row_names_[iRow] + ")") : "";
|
|
2712
|
+
// @primal_infeasibility calculation
|
|
2713
|
+
double row_infeasibility = 0;
|
|
2714
|
+
if (primal < lower - kPrimalFeasibilityTolerance) {
|
|
2715
|
+
row_infeasibility = lower - primal;
|
|
2716
|
+
} else if (primal > upper + kPrimalFeasibilityTolerance) {
|
|
2717
|
+
row_infeasibility = primal - upper;
|
|
2718
|
+
}
|
|
2719
|
+
if (row_infeasibility > 0) {
|
|
2720
|
+
if (row_infeasibility > kPrimalFeasibilityTolerance) {
|
|
2721
|
+
if (row_infeasibility > 2 * max_row_infeasibility)
|
|
2722
|
+
highsLogUser(options.log_options, HighsLogType::kWarning,
|
|
2723
|
+
"Row %6d%s has infeasibility of %11.4g from "
|
|
2724
|
+
"[lower, value, upper] = [%15.8g; %15.8g; %15.8g]\n",
|
|
2725
|
+
(int)iRow, name_string.c_str(), row_infeasibility, lower,
|
|
2726
|
+
primal, upper);
|
|
2727
|
+
num_row_infeasibilities++;
|
|
2728
|
+
}
|
|
2729
|
+
max_row_infeasibility =
|
|
2730
|
+
std::max(row_infeasibility, max_row_infeasibility);
|
|
2731
|
+
sum_row_infeasibilities += row_infeasibility;
|
|
2732
|
+
}
|
|
2733
|
+
double row_residual = fabs(primal - row_value[iRow]);
|
|
2734
|
+
if (row_residual > kRowResidualTolerance) {
|
|
2735
|
+
if (row_residual > 2 * max_row_residual) {
|
|
2736
|
+
highsLogUser(options.log_options, HighsLogType::kWarning,
|
|
2737
|
+
"Row %6d%s has residual of %11.4g\n",
|
|
2738
|
+
(int)iRow, name_string.c_str(), row_residual);
|
|
2739
|
+
}
|
|
2740
|
+
num_row_residuals++;
|
|
2741
|
+
}
|
|
2742
|
+
max_row_residual = std::max(row_residual, max_row_residual);
|
|
2743
|
+
sum_row_residuals += row_residual;
|
|
2744
|
+
}
|
|
2745
|
+
highsLogUser(options.log_options, HighsLogType::kInfo,
|
|
2746
|
+
"Solution has num max sum\n");
|
|
2747
|
+
highsLogUser(options.log_options, HighsLogType::kInfo,
|
|
2748
|
+
"Col infeasibilities %6d %11.4g %11.4g\n",
|
|
2749
|
+
(int)num_col_infeasibilities, max_col_infeasibility,
|
|
2750
|
+
sum_col_infeasibilities);
|
|
2751
|
+
if (lp.isMip())
|
|
2752
|
+
highsLogUser(options.log_options, HighsLogType::kInfo,
|
|
2753
|
+
"Integer infeasibilities %6d %11.4g %11.4g\n",
|
|
2754
|
+
(int)num_integer_infeasibilities, max_integer_infeasibility,
|
|
2755
|
+
sum_integer_infeasibilities);
|
|
2756
|
+
highsLogUser(options.log_options, HighsLogType::kInfo,
|
|
2757
|
+
"Row infeasibilities %6d %11.4g %11.4g\n",
|
|
2758
|
+
(int)num_row_infeasibilities, max_row_infeasibility,
|
|
2759
|
+
sum_row_infeasibilities);
|
|
2760
|
+
highsLogUser(options.log_options, HighsLogType::kInfo,
|
|
2761
|
+
"Row residuals %6d %11.4g %11.4g\n",
|
|
2762
|
+
(int)num_row_residuals, max_row_residual, sum_row_residuals);
|
|
2763
|
+
valid = num_row_residuals == 0;
|
|
2764
|
+
integral = valid && num_integer_infeasibilities == 0;
|
|
2765
|
+
feasible = valid && num_col_infeasibilities == 0 &&
|
|
2766
|
+
num_integer_infeasibilities == 0 && num_row_infeasibilities == 0;
|
|
2767
|
+
if (!(integral && feasible)) return HighsStatus::kWarning;
|
|
2768
|
+
return HighsStatus::kOk;
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
void writeBasisFile(FILE*& file, const HighsOptions& options, const HighsLp& lp,
|
|
2772
|
+
const HighsBasis& basis) {
|
|
2773
|
+
const HighsLogOptions& log_options = options.log_options;
|
|
2774
|
+
std::stringstream ss;
|
|
2775
|
+
// Basis version line
|
|
2776
|
+
ss.str(std::string());
|
|
2777
|
+
ss << highsFormatToString("HiGHS_basis_file %s\n", kHighsBasisFileV2.c_str());
|
|
2778
|
+
highsFprintfString(file, log_options, ss.str());
|
|
2779
|
+
// Basis validity line
|
|
2780
|
+
ss.str(std::string());
|
|
2781
|
+
if (basis.valid == false) {
|
|
2782
|
+
ss << highsFormatToString("None\n");
|
|
2783
|
+
highsFprintfString(file, log_options, ss.str());
|
|
2784
|
+
return;
|
|
2785
|
+
}
|
|
2786
|
+
assert(basis.col_status.size() == static_cast<size_t>(lp.num_col_));
|
|
2787
|
+
assert(basis.row_status.size() == static_cast<size_t>(lp.num_row_));
|
|
2788
|
+
assert(lp.col_names_.size() == static_cast<size_t>(lp.num_col_));
|
|
2789
|
+
assert(lp.row_names_.size() == static_cast<size_t>(lp.num_row_));
|
|
2790
|
+
ss << highsFormatToString("Valid\n");
|
|
2791
|
+
highsFprintfString(file, log_options, ss.str());
|
|
2792
|
+
// Column count line
|
|
2793
|
+
ss.str(std::string());
|
|
2794
|
+
ss << highsFormatToString("# Columns %d\n", int(lp.num_col_));
|
|
2795
|
+
highsFprintfString(file, log_options, ss.str());
|
|
2796
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
2797
|
+
const std::string& name = lp.col_names_[iCol];
|
|
2798
|
+
assert(name.length() != 0);
|
|
2799
|
+
ss.str(std::string());
|
|
2800
|
+
ss << highsFormatToString("%s %d\n", name.c_str(),
|
|
2801
|
+
int(basis.col_status[iCol]));
|
|
2802
|
+
highsFprintfString(file, log_options, ss.str());
|
|
2803
|
+
}
|
|
2804
|
+
// Row count line
|
|
2805
|
+
ss.str(std::string());
|
|
2806
|
+
ss << highsFormatToString("# Rows %d\n", int(lp.num_row_));
|
|
2807
|
+
highsFprintfString(file, log_options, ss.str());
|
|
2808
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
2809
|
+
const std::string& name = lp.row_names_[iRow];
|
|
2810
|
+
assert(name.length() != 0);
|
|
2811
|
+
ss.str(std::string());
|
|
2812
|
+
ss << highsFormatToString("%s %d\n", name.c_str(),
|
|
2813
|
+
int(basis.row_status[iRow]));
|
|
2814
|
+
highsFprintfString(file, log_options, ss.str());
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2818
|
+
HighsStatus getIndexFromName(
|
|
2819
|
+
const HighsLogOptions& log_options, std::string& from_method,
|
|
2820
|
+
const bool is_column, const std::string& name,
|
|
2821
|
+
const std::unordered_map<std::string, int>& name2index, HighsInt& index,
|
|
2822
|
+
const std::vector<std::string>& names) {
|
|
2823
|
+
assert(name2index.size());
|
|
2824
|
+
auto search = name2index.find(name);
|
|
2825
|
+
if (search == name2index.end()) {
|
|
2826
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
2827
|
+
"%s: %s name %s is not found\n", from_method.c_str(),
|
|
2828
|
+
is_column ? "column" : "row", name.c_str());
|
|
2829
|
+
return HighsStatus::kError;
|
|
2830
|
+
}
|
|
2831
|
+
if (search->second == kHashIsDuplicate) {
|
|
2832
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
2833
|
+
"%s: %s name %s is duplicated\n", from_method.c_str(),
|
|
2834
|
+
is_column ? "column" : "row", name.c_str());
|
|
2835
|
+
return HighsStatus::kError;
|
|
2836
|
+
}
|
|
2837
|
+
index = search->second;
|
|
2838
|
+
assert(names[index] == name);
|
|
2839
|
+
return HighsStatus::kOk;
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2842
|
+
HighsStatus readBasisFile(const HighsLogOptions& log_options, HighsLp& lp,
|
|
2843
|
+
HighsBasis& basis, const std::string& filename) {
|
|
2844
|
+
// Opens a basis file as an ifstream
|
|
2845
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
2846
|
+
std::ifstream in_file;
|
|
2847
|
+
in_file.open(filename.c_str(), std::ios::in);
|
|
2848
|
+
if (in_file.is_open()) {
|
|
2849
|
+
return_status = readBasisStream(log_options, lp, basis, in_file);
|
|
2850
|
+
in_file.close();
|
|
2851
|
+
} else {
|
|
2852
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
2853
|
+
"readBasisFile: Cannot open readable file \"%s\"\n",
|
|
2854
|
+
filename.c_str());
|
|
2855
|
+
return_status = HighsStatus::kError;
|
|
2856
|
+
}
|
|
2857
|
+
return return_status;
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2860
|
+
HighsStatus readBasisStream(const HighsLogOptions& log_options, HighsLp& lp,
|
|
2861
|
+
HighsBasis& basis, std::ifstream& in_file) {
|
|
2862
|
+
// Reads a basis as an ifstream, returning an error if what's read is
|
|
2863
|
+
// inconsistent with the sizes of the HighsBasis passed in
|
|
2864
|
+
HighsStatus return_status = HighsStatus::kOk;
|
|
2865
|
+
HighsStatus call_status = HighsStatus::kOk;
|
|
2866
|
+
std::string from_method = "readBasisStream";
|
|
2867
|
+
std::string string_highs, string_version;
|
|
2868
|
+
in_file >> string_highs >> string_version;
|
|
2869
|
+
const bool v1 = string_version == kHighsBasisFileV1;
|
|
2870
|
+
const bool v2 = string_version == kHighsBasisFileV2;
|
|
2871
|
+
const bool have_col_names =
|
|
2872
|
+
lp.col_names_.size() == static_cast<size_t>(lp.num_col_);
|
|
2873
|
+
const bool have_row_names =
|
|
2874
|
+
lp.row_names_.size() == static_cast<size_t>(lp.num_row_);
|
|
2875
|
+
if (have_col_names) {
|
|
2876
|
+
// Ensure that the col name hash table has been formed
|
|
2877
|
+
if (!lp.col_hash_.name2index.size()) lp.col_hash_.form(lp.col_names_);
|
|
2878
|
+
}
|
|
2879
|
+
if (have_row_names) {
|
|
2880
|
+
// Ensure that the row name hash table has been formed
|
|
2881
|
+
if (!lp.row_hash_.name2index.size()) lp.row_hash_.form(lp.row_names_);
|
|
2882
|
+
}
|
|
2883
|
+
if (v1 || v2) {
|
|
2884
|
+
if (v1) {
|
|
2885
|
+
// Ability to read v1 basis files is deprecated
|
|
2886
|
+
highsLogUser(log_options, HighsLogType::kWarning,
|
|
2887
|
+
"readBasisFile: Basis file format %s is deprecated\n",
|
|
2888
|
+
kHighsBasisFileV1.c_str());
|
|
2889
|
+
return_status = HighsStatus::kWarning;
|
|
2890
|
+
}
|
|
2891
|
+
std::string keyword;
|
|
2892
|
+
in_file >> keyword;
|
|
2893
|
+
if (keyword == "None") {
|
|
2894
|
+
basis.valid = false;
|
|
2895
|
+
return return_status;
|
|
2896
|
+
}
|
|
2897
|
+
const HighsInt basis_num_col = (HighsInt)basis.col_status.size();
|
|
2898
|
+
const HighsInt basis_num_row = (HighsInt)basis.row_status.size();
|
|
2899
|
+
HighsInt int_status;
|
|
2900
|
+
std::string name;
|
|
2901
|
+
assert(keyword == "Valid");
|
|
2902
|
+
HighsInt num_col, num_row;
|
|
2903
|
+
// Read in the columns section
|
|
2904
|
+
in_file >> keyword >> keyword;
|
|
2905
|
+
assert(keyword == "Columns");
|
|
2906
|
+
in_file >> num_col;
|
|
2907
|
+
if (num_col != basis_num_col) {
|
|
2908
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
2909
|
+
"readBasisFile: Basis file is for %" HIGHSINT_FORMAT
|
|
2910
|
+
" columns, not %" HIGHSINT_FORMAT "\n",
|
|
2911
|
+
num_col, basis_num_col);
|
|
2912
|
+
return HighsStatus::kError;
|
|
2913
|
+
}
|
|
2914
|
+
bool is_column = true;
|
|
2915
|
+
if (v1) {
|
|
2916
|
+
for (HighsInt iCol = 0; iCol < num_col; iCol++) {
|
|
2917
|
+
in_file >> int_status;
|
|
2918
|
+
basis.col_status[iCol] = (HighsBasisStatus)int_status;
|
|
2919
|
+
}
|
|
2920
|
+
} else {
|
|
2921
|
+
HighsInt iCol;
|
|
2922
|
+
for (HighsInt iX = 0; iX < num_col; iX++) {
|
|
2923
|
+
in_file >> name >> int_status;
|
|
2924
|
+
if (have_col_names) {
|
|
2925
|
+
// Use the column name if possible
|
|
2926
|
+
call_status =
|
|
2927
|
+
getIndexFromName(log_options, from_method, is_column, name,
|
|
2928
|
+
lp.col_hash_.name2index, iCol, lp.col_names_);
|
|
2929
|
+
if (call_status != HighsStatus::kOk) return call_status;
|
|
2930
|
+
} else {
|
|
2931
|
+
// Have to assume column basis status are in the right order
|
|
2932
|
+
iCol = iX;
|
|
2933
|
+
}
|
|
2934
|
+
basis.col_status[iCol] = HighsBasisStatus(int_status);
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2937
|
+
// Read in the rows section
|
|
2938
|
+
in_file >> keyword >> keyword;
|
|
2939
|
+
assert(keyword == "Rows");
|
|
2940
|
+
in_file >> num_row;
|
|
2941
|
+
if (num_row != basis_num_row) {
|
|
2942
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
2943
|
+
"readBasisFile: Basis file is for %" HIGHSINT_FORMAT
|
|
2944
|
+
" rows, not %" HIGHSINT_FORMAT "\n",
|
|
2945
|
+
num_row, basis_num_row);
|
|
2946
|
+
return HighsStatus::kError;
|
|
2947
|
+
}
|
|
2948
|
+
is_column = false;
|
|
2949
|
+
if (v1) {
|
|
2950
|
+
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
|
|
2951
|
+
in_file >> int_status;
|
|
2952
|
+
basis.row_status[iRow] = (HighsBasisStatus)int_status;
|
|
2953
|
+
}
|
|
2954
|
+
} else {
|
|
2955
|
+
HighsInt iRow;
|
|
2956
|
+
for (HighsInt iX = 0; iX < num_row; iX++) {
|
|
2957
|
+
in_file >> name >> int_status;
|
|
2958
|
+
if (have_row_names) {
|
|
2959
|
+
// Use the row name if possible
|
|
2960
|
+
call_status =
|
|
2961
|
+
getIndexFromName(log_options, from_method, is_column, name,
|
|
2962
|
+
lp.row_hash_.name2index, iRow, lp.row_names_);
|
|
2963
|
+
if (call_status != HighsStatus::kOk) return call_status;
|
|
2964
|
+
} else {
|
|
2965
|
+
// Have to assume row solution values are in the right order
|
|
2966
|
+
iRow = iX;
|
|
2967
|
+
}
|
|
2968
|
+
basis.row_status[iRow] = HighsBasisStatus(int_status);
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
} else {
|
|
2972
|
+
highsLogUser(log_options, HighsLogType::kError,
|
|
2973
|
+
"readBasisFile: Cannot read basis file for HiGHS %s\n",
|
|
2974
|
+
string_version.c_str());
|
|
2975
|
+
return_status = HighsStatus::kError;
|
|
2976
|
+
}
|
|
2977
|
+
return return_status;
|
|
2978
|
+
}
|
|
2979
|
+
|
|
2980
|
+
HighsStatus calculateColDualsQuad(const HighsLp& lp, HighsSolution& solution) {
|
|
2981
|
+
const bool correct_size = int(solution.row_dual.size()) == lp.num_row_;
|
|
2982
|
+
const bool is_colwise = lp.a_matrix_.isColwise();
|
|
2983
|
+
const bool data_error = !correct_size || !is_colwise;
|
|
2984
|
+
assert(!data_error);
|
|
2985
|
+
if (data_error) return HighsStatus::kError;
|
|
2986
|
+
|
|
2987
|
+
std::vector<HighsCDouble> col_dual_quad;
|
|
2988
|
+
col_dual_quad.assign(lp.num_col_, HighsCDouble{0.0});
|
|
2989
|
+
|
|
2990
|
+
for (HighsInt col = 0; col < lp.num_col_; col++) {
|
|
2991
|
+
for (HighsInt i = lp.a_matrix_.start_[col];
|
|
2992
|
+
i < lp.a_matrix_.start_[col + 1]; i++) {
|
|
2993
|
+
const HighsInt row = lp.a_matrix_.index_[i];
|
|
2994
|
+
assert(row >= 0);
|
|
2995
|
+
assert(row < lp.num_row_);
|
|
2996
|
+
col_dual_quad[col] += solution.row_dual[row] * lp.a_matrix_.value_[i];
|
|
2997
|
+
}
|
|
2998
|
+
col_dual_quad[col] += lp.col_cost_[col];
|
|
2999
|
+
}
|
|
3000
|
+
|
|
3001
|
+
// assign quad values to double vector
|
|
3002
|
+
solution.col_dual.resize(lp.num_col_);
|
|
3003
|
+
std::transform(col_dual_quad.begin(), col_dual_quad.end(),
|
|
3004
|
+
solution.col_dual.begin(),
|
|
3005
|
+
[](HighsCDouble x) { return double(x); });
|
|
3006
|
+
|
|
3007
|
+
return HighsStatus::kOk;
|
|
3008
|
+
}
|
|
3009
|
+
|
|
3010
|
+
HighsStatus calculateRowValuesQuad(const HighsLp& lp,
|
|
3011
|
+
const std::vector<double>& col_value,
|
|
3012
|
+
std::vector<double>& row_value,
|
|
3013
|
+
const HighsInt report_row) {
|
|
3014
|
+
const bool correct_size = int(col_value.size()) == lp.num_col_;
|
|
3015
|
+
const bool is_colwise = lp.a_matrix_.isColwise();
|
|
3016
|
+
const bool data_error = !correct_size || !is_colwise;
|
|
3017
|
+
assert(!data_error);
|
|
3018
|
+
if (data_error) return HighsStatus::kError;
|
|
3019
|
+
|
|
3020
|
+
std::vector<HighsCDouble> row_value_quad;
|
|
3021
|
+
row_value_quad.assign(lp.num_row_, HighsCDouble{0.0});
|
|
3022
|
+
|
|
3023
|
+
for (HighsInt col = 0; col < lp.num_col_; col++) {
|
|
3024
|
+
for (HighsInt i = lp.a_matrix_.start_[col];
|
|
3025
|
+
i < lp.a_matrix_.start_[col + 1]; i++) {
|
|
3026
|
+
const HighsInt row = lp.a_matrix_.index_[i];
|
|
3027
|
+
assert(row >= 0);
|
|
3028
|
+
assert(row < lp.num_row_);
|
|
3029
|
+
row_value_quad[row] += col_value[col] * lp.a_matrix_.value_[i];
|
|
3030
|
+
if (row == report_row) {
|
|
3031
|
+
printf(
|
|
3032
|
+
"calculateRowValuesQuad: Row %d becomes %g due to contribution of "
|
|
3033
|
+
".col_value[%d] = %g\n",
|
|
3034
|
+
int(row), double(row_value_quad[row]), int(col), col_value[col]);
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
|
|
3039
|
+
// assign quad values to double vector
|
|
3040
|
+
row_value.resize(lp.num_row_);
|
|
3041
|
+
std::transform(row_value_quad.begin(), row_value_quad.end(),
|
|
3042
|
+
row_value.begin(), [](HighsCDouble x) { return double(x); });
|
|
3043
|
+
|
|
3044
|
+
return HighsStatus::kOk;
|
|
3045
|
+
}
|
|
3046
|
+
|
|
3047
|
+
HighsStatus calculateRowValuesQuad(const HighsLp& lp, HighsSolution& solution,
|
|
3048
|
+
const HighsInt report_row) {
|
|
3049
|
+
return calculateRowValuesQuad(lp, solution.col_value, solution.row_value,
|
|
3050
|
+
report_row);
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
bool isColDataNull(const HighsLogOptions& log_options,
|
|
3054
|
+
const double* usr_col_cost, const double* usr_col_lower,
|
|
3055
|
+
const double* usr_col_upper) {
|
|
3056
|
+
bool null_data = false;
|
|
3057
|
+
null_data =
|
|
3058
|
+
doubleUserDataNotNull(log_options, usr_col_cost, "column costs") ||
|
|
3059
|
+
null_data;
|
|
3060
|
+
null_data = doubleUserDataNotNull(log_options, usr_col_lower,
|
|
3061
|
+
"column lower bounds") ||
|
|
3062
|
+
null_data;
|
|
3063
|
+
null_data = doubleUserDataNotNull(log_options, usr_col_upper,
|
|
3064
|
+
"column upper bounds") ||
|
|
3065
|
+
null_data;
|
|
3066
|
+
return null_data;
|
|
3067
|
+
}
|
|
3068
|
+
|
|
3069
|
+
bool isRowDataNull(const HighsLogOptions& log_options,
|
|
3070
|
+
const double* usr_row_lower, const double* usr_row_upper) {
|
|
3071
|
+
bool null_data = false;
|
|
3072
|
+
null_data =
|
|
3073
|
+
doubleUserDataNotNull(log_options, usr_row_lower, "row lower bounds") ||
|
|
3074
|
+
null_data;
|
|
3075
|
+
null_data =
|
|
3076
|
+
doubleUserDataNotNull(log_options, usr_row_upper, "row upper bounds") ||
|
|
3077
|
+
null_data;
|
|
3078
|
+
return null_data;
|
|
3079
|
+
}
|
|
3080
|
+
|
|
3081
|
+
bool isMatrixDataNull(const HighsLogOptions& log_options,
|
|
3082
|
+
const HighsInt* usr_matrix_start,
|
|
3083
|
+
const HighsInt* usr_matrix_index,
|
|
3084
|
+
const double* usr_matrix_value) {
|
|
3085
|
+
bool null_data = false;
|
|
3086
|
+
null_data =
|
|
3087
|
+
intUserDataNotNull(log_options, usr_matrix_start, "matrix starts") ||
|
|
3088
|
+
null_data;
|
|
3089
|
+
null_data =
|
|
3090
|
+
intUserDataNotNull(log_options, usr_matrix_index, "matrix indices") ||
|
|
3091
|
+
null_data;
|
|
3092
|
+
null_data =
|
|
3093
|
+
doubleUserDataNotNull(log_options, usr_matrix_value, "matrix values") ||
|
|
3094
|
+
null_data;
|
|
3095
|
+
return null_data;
|
|
3096
|
+
}
|
|
3097
|
+
|
|
3098
|
+
void reportPresolveReductions(const HighsLogOptions& log_options,
|
|
3099
|
+
HighsPresolveStatus presolve_status,
|
|
3100
|
+
const HighsLp& lp, const HighsLp& presolved_lp) {
|
|
3101
|
+
const HighsInt num_col_from = lp.num_col_;
|
|
3102
|
+
const HighsInt num_row_from = lp.num_row_;
|
|
3103
|
+
const HighsInt num_nz_from = lp.a_matrix_.numNz();
|
|
3104
|
+
HighsInt num_col_to = 0;
|
|
3105
|
+
HighsInt num_row_to = 0;
|
|
3106
|
+
HighsInt num_nz_to = 0;
|
|
3107
|
+
std::string message = "";
|
|
3108
|
+
|
|
3109
|
+
switch (presolve_status) {
|
|
3110
|
+
case HighsPresolveStatus::kNotPresolved:
|
|
3111
|
+
case HighsPresolveStatus::kInfeasible:
|
|
3112
|
+
case HighsPresolveStatus::kUnboundedOrInfeasible:
|
|
3113
|
+
return;
|
|
3114
|
+
case HighsPresolveStatus::kNotReduced: {
|
|
3115
|
+
num_col_to = num_col_from;
|
|
3116
|
+
num_row_to = num_row_from;
|
|
3117
|
+
num_nz_to = num_nz_from;
|
|
3118
|
+
message = "- Not reduced";
|
|
3119
|
+
break;
|
|
3120
|
+
}
|
|
3121
|
+
case HighsPresolveStatus::kReduced:
|
|
3122
|
+
case HighsPresolveStatus::kTimeout: {
|
|
3123
|
+
num_col_to = presolved_lp.num_col_;
|
|
3124
|
+
num_row_to = presolved_lp.num_row_;
|
|
3125
|
+
num_nz_to = presolved_lp.a_matrix_.numNz();
|
|
3126
|
+
message =
|
|
3127
|
+
presolve_status == HighsPresolveStatus::kTimeout ? "- Timeout" : "";
|
|
3128
|
+
break;
|
|
3129
|
+
}
|
|
3130
|
+
case HighsPresolveStatus::kReducedToEmpty: {
|
|
3131
|
+
num_col_to = 0;
|
|
3132
|
+
num_row_to = 0;
|
|
3133
|
+
num_nz_to = 0;
|
|
3134
|
+
message = "- Reduced to empty";
|
|
3135
|
+
break;
|
|
3136
|
+
}
|
|
3137
|
+
default: {
|
|
3138
|
+
// case HighsPresolveStatus::kOutOfMemory
|
|
3139
|
+
assert(presolve_status == HighsPresolveStatus::kOutOfMemory);
|
|
3140
|
+
return;
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
char nz_sign_char = '-';
|
|
3144
|
+
HighsInt delta_nz = num_nz_from - num_nz_to;
|
|
3145
|
+
if (num_nz_to > num_nz_from) {
|
|
3146
|
+
delta_nz = -delta_nz;
|
|
3147
|
+
nz_sign_char = '+';
|
|
3148
|
+
}
|
|
3149
|
+
highsLogUser(log_options, HighsLogType::kInfo,
|
|
3150
|
+
"Presolve reductions: rows %" HIGHSINT_FORMAT
|
|
3151
|
+
"(-%" HIGHSINT_FORMAT "); columns %" HIGHSINT_FORMAT
|
|
3152
|
+
"(-%" HIGHSINT_FORMAT
|
|
3153
|
+
"); "
|
|
3154
|
+
"nonzeros %" HIGHSINT_FORMAT "(%c%" HIGHSINT_FORMAT ") %s\n",
|
|
3155
|
+
num_row_to, (num_row_from - num_row_to), num_col_to,
|
|
3156
|
+
(num_col_from - num_col_to), num_nz_to, nz_sign_char, delta_nz,
|
|
3157
|
+
message.c_str());
|
|
3158
|
+
}
|
|
3159
|
+
|
|
3160
|
+
bool isLessInfeasibleDSECandidate(const HighsLogOptions& log_options,
|
|
3161
|
+
const HighsLp& lp) {
|
|
3162
|
+
HighsInt max_col_num_en = -1;
|
|
3163
|
+
const HighsInt max_allowed_col_num_en = 24;
|
|
3164
|
+
const HighsInt max_assess_col_num_en =
|
|
3165
|
+
std::max(HighsInt{9}, max_allowed_col_num_en);
|
|
3166
|
+
const HighsInt max_average_col_num_en = 6;
|
|
3167
|
+
vector<HighsInt> col_length_k;
|
|
3168
|
+
col_length_k.resize(1 + max_assess_col_num_en, 0);
|
|
3169
|
+
bool LiDSE_candidate = true;
|
|
3170
|
+
for (HighsInt col = 0; col < lp.num_col_; col++) {
|
|
3171
|
+
// Check limit on number of entries in the column has not been breached
|
|
3172
|
+
HighsInt col_num_en =
|
|
3173
|
+
lp.a_matrix_.start_[col + 1] - lp.a_matrix_.start_[col];
|
|
3174
|
+
max_col_num_en = std::max(col_num_en, max_col_num_en);
|
|
3175
|
+
if (col_num_en > max_assess_col_num_en) return false;
|
|
3176
|
+
col_length_k[col_num_en]++;
|
|
3177
|
+
for (HighsInt en = lp.a_matrix_.start_[col];
|
|
3178
|
+
en < lp.a_matrix_.start_[col + 1]; en++) {
|
|
3179
|
+
double value = lp.a_matrix_.value_[en];
|
|
3180
|
+
// All nonzeros must be +1 or -1
|
|
3181
|
+
if (fabs(value) != 1) return false;
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
double average_col_num_en = lp.a_matrix_.start_[lp.num_col_];
|
|
3185
|
+
average_col_num_en = average_col_num_en / lp.num_col_;
|
|
3186
|
+
LiDSE_candidate =
|
|
3187
|
+
LiDSE_candidate && average_col_num_en <= max_average_col_num_en;
|
|
3188
|
+
highsLogDev(log_options, HighsLogType::kInfo,
|
|
3189
|
+
"LP %s has all |entries|=1; max column count = %" HIGHSINT_FORMAT
|
|
3190
|
+
" (limit %" HIGHSINT_FORMAT
|
|
3191
|
+
"); average "
|
|
3192
|
+
"column count = %0.2g (limit %" HIGHSINT_FORMAT
|
|
3193
|
+
"): LP is %s a candidate for LiDSE\n",
|
|
3194
|
+
lp.model_name_.c_str(), max_col_num_en, max_allowed_col_num_en,
|
|
3195
|
+
average_col_num_en, max_average_col_num_en,
|
|
3196
|
+
LiDSE_candidate ? "is" : "is not");
|
|
3197
|
+
return LiDSE_candidate;
|
|
3198
|
+
}
|
|
3199
|
+
|
|
3200
|
+
HighsLp withoutSemiVariables(const HighsLp& lp_, HighsSolution& solution,
|
|
3201
|
+
const double primal_feasibility_tolerance) {
|
|
3202
|
+
HighsLp lp = lp_;
|
|
3203
|
+
HighsInt num_col = lp.num_col_;
|
|
3204
|
+
HighsInt num_row = lp.num_row_;
|
|
3205
|
+
HighsInt num_semi_variables = 0;
|
|
3206
|
+
for (HighsInt iCol = 0; iCol < num_col; iCol++) {
|
|
3207
|
+
if (lp.integrality_[iCol] == HighsVarType::kSemiContinuous ||
|
|
3208
|
+
lp.integrality_[iCol] == HighsVarType::kSemiInteger)
|
|
3209
|
+
num_semi_variables++;
|
|
3210
|
+
}
|
|
3211
|
+
assert(num_semi_variables);
|
|
3212
|
+
// Insert spaces for index/value of new coefficients for
|
|
3213
|
+
// semi-variables
|
|
3214
|
+
vector<HighsInt>& start = lp.a_matrix_.start_;
|
|
3215
|
+
vector<HighsInt>& index = lp.a_matrix_.index_;
|
|
3216
|
+
vector<double>& value = lp.a_matrix_.value_;
|
|
3217
|
+
HighsInt num_nz = start[num_col];
|
|
3218
|
+
HighsInt new_num_nz = num_nz + 2 * num_semi_variables;
|
|
3219
|
+
HighsInt new_el = new_num_nz;
|
|
3220
|
+
index.resize(new_num_nz);
|
|
3221
|
+
value.resize(new_num_nz);
|
|
3222
|
+
for (HighsInt iCol = num_col - 1; iCol >= 0; iCol--) {
|
|
3223
|
+
HighsInt from_el = start[iCol + 1] - 1;
|
|
3224
|
+
start[iCol + 1] = new_el;
|
|
3225
|
+
if (lp.integrality_[iCol] == HighsVarType::kSemiContinuous ||
|
|
3226
|
+
lp.integrality_[iCol] == HighsVarType::kSemiInteger)
|
|
3227
|
+
new_el -= 2;
|
|
3228
|
+
for (HighsInt iEl = from_el; iEl >= start[iCol]; iEl--) {
|
|
3229
|
+
new_el--;
|
|
3230
|
+
index[new_el] = index[iEl];
|
|
3231
|
+
value[new_el] = value[iEl];
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
assert(new_el == 0);
|
|
3235
|
+
// Insert the new coefficients for semi-variables
|
|
3236
|
+
HighsInt row_num = num_row;
|
|
3237
|
+
for (HighsInt iCol = 0; iCol < num_col; iCol++) {
|
|
3238
|
+
if (lp.integrality_[iCol] == HighsVarType::kSemiContinuous ||
|
|
3239
|
+
lp.integrality_[iCol] == HighsVarType::kSemiInteger) {
|
|
3240
|
+
HighsInt iEl = start[iCol + 1] - 2;
|
|
3241
|
+
index[iEl] = row_num++;
|
|
3242
|
+
value[iEl] = 1;
|
|
3243
|
+
iEl++;
|
|
3244
|
+
index[iEl] = row_num++;
|
|
3245
|
+
value[iEl] = 1;
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
num_nz = start[num_col];
|
|
3249
|
+
new_num_nz = num_nz + 2 * num_semi_variables;
|
|
3250
|
+
row_num = num_row;
|
|
3251
|
+
HighsInt semi_col_num = 0;
|
|
3252
|
+
HighsInt semi_row_num = 0;
|
|
3253
|
+
// Insert the new variables and their coefficients
|
|
3254
|
+
std::stringstream ss;
|
|
3255
|
+
const bool have_col_names =
|
|
3256
|
+
lp.col_names_.size() == static_cast<size_t>(lp.num_col_);
|
|
3257
|
+
const bool have_row_names =
|
|
3258
|
+
lp.row_names_.size() == static_cast<size_t>(lp.num_row_);
|
|
3259
|
+
const bool have_solution = solution.value_valid;
|
|
3260
|
+
if (have_solution) {
|
|
3261
|
+
// Create zeroed row values for the new rows
|
|
3262
|
+
assert((HighsInt)solution.row_value.size() == lp_.num_row_);
|
|
3263
|
+
for (HighsInt iCol = 0; iCol < 2 * num_semi_variables; iCol++)
|
|
3264
|
+
solution.row_value.push_back(0);
|
|
3265
|
+
assert((HighsInt)solution.col_value.size() == lp_.num_col_);
|
|
3266
|
+
assert((HighsInt)solution.row_value.size() ==
|
|
3267
|
+
lp_.num_row_ + 2 * num_semi_variables);
|
|
3268
|
+
}
|
|
3269
|
+
for (HighsInt iCol = 0; iCol < num_col; iCol++) {
|
|
3270
|
+
if (lp.integrality_[iCol] == HighsVarType::kSemiContinuous ||
|
|
3271
|
+
lp.integrality_[iCol] == HighsVarType::kSemiInteger) {
|
|
3272
|
+
// Add a binary variable with zero cost
|
|
3273
|
+
lp.col_cost_.push_back(0);
|
|
3274
|
+
lp.col_lower_.push_back(0);
|
|
3275
|
+
lp.col_upper_.push_back(1);
|
|
3276
|
+
// Complete x - l*y >= 0
|
|
3277
|
+
lp.row_lower_.push_back(0);
|
|
3278
|
+
lp.row_upper_.push_back(kHighsInf);
|
|
3279
|
+
if (have_col_names) {
|
|
3280
|
+
// Create a column name
|
|
3281
|
+
ss.str(std::string());
|
|
3282
|
+
ss << "semi_binary_" << semi_col_num++;
|
|
3283
|
+
lp.col_names_.push_back(ss.str());
|
|
3284
|
+
}
|
|
3285
|
+
if (have_row_names) {
|
|
3286
|
+
// Create a row name
|
|
3287
|
+
ss.str(std::string());
|
|
3288
|
+
ss << "semi_lb_" << semi_row_num;
|
|
3289
|
+
lp.row_names_.push_back(ss.str());
|
|
3290
|
+
}
|
|
3291
|
+
index.push_back(row_num++);
|
|
3292
|
+
value.push_back(-lp.col_lower_[iCol]);
|
|
3293
|
+
// Accommodate any primal solution
|
|
3294
|
+
if (have_solution) {
|
|
3295
|
+
// Record the previous solution value so any change can be
|
|
3296
|
+
// determined
|
|
3297
|
+
const double prev_primal = solution.col_value[iCol];
|
|
3298
|
+
if (solution.col_value[iCol] <= primal_feasibility_tolerance) {
|
|
3299
|
+
// Currently at or below zero, so binary is 0
|
|
3300
|
+
solution.col_value[iCol] = 0;
|
|
3301
|
+
solution.col_value.push_back(0);
|
|
3302
|
+
} else {
|
|
3303
|
+
// Otherwise, solution is at least lower bound, and binary
|
|
3304
|
+
// is 1
|
|
3305
|
+
solution.col_value[iCol] =
|
|
3306
|
+
std::max(lp.col_lower_[iCol], solution.col_value[iCol]);
|
|
3307
|
+
solution.col_value.push_back(1);
|
|
3308
|
+
}
|
|
3309
|
+
const double dl_primal = solution.col_value[iCol] - prev_primal;
|
|
3310
|
+
if (dl_primal) {
|
|
3311
|
+
// Change in primal value, so update row values. NB start
|
|
3312
|
+
// has been extended to incorporate the values in this
|
|
3313
|
+
// column for the new rows. Their solution values are zero,
|
|
3314
|
+
// but will be set later
|
|
3315
|
+
for (HighsInt iEl = start[iCol]; iEl < start[iCol + 1]; iEl++)
|
|
3316
|
+
solution.row_value[index[iEl]] += dl_primal * value[iEl];
|
|
3317
|
+
}
|
|
3318
|
+
const HighsInt new_col = lp.col_cost_.size() - 1;
|
|
3319
|
+
const double binary_value = solution.col_value[new_col];
|
|
3320
|
+
solution.row_value[row_num - 1] =
|
|
3321
|
+
solution.col_value[iCol] - lp.col_lower_[iCol] * binary_value;
|
|
3322
|
+
solution.row_value[row_num] =
|
|
3323
|
+
solution.col_value[iCol] - lp.col_upper_[iCol] * binary_value;
|
|
3324
|
+
}
|
|
3325
|
+
// Complete x - u*y <= 0
|
|
3326
|
+
lp.row_lower_.push_back(-kHighsInf);
|
|
3327
|
+
lp.row_upper_.push_back(0);
|
|
3328
|
+
if (have_row_names) {
|
|
3329
|
+
// Create a row name
|
|
3330
|
+
ss.str(std::string());
|
|
3331
|
+
ss << "semi_ub_" << semi_row_num++;
|
|
3332
|
+
lp.row_names_.push_back(ss.str());
|
|
3333
|
+
}
|
|
3334
|
+
index.push_back(row_num++);
|
|
3335
|
+
value.push_back(-lp.col_upper_[iCol]);
|
|
3336
|
+
// Add the next start
|
|
3337
|
+
start.push_back(index.size());
|
|
3338
|
+
lp.integrality_.push_back(HighsVarType::kInteger);
|
|
3339
|
+
if (lp.integrality_[iCol] == HighsVarType::kSemiContinuous) {
|
|
3340
|
+
lp.integrality_[iCol] = HighsVarType::kContinuous;
|
|
3341
|
+
} else if (lp.integrality_[iCol] == HighsVarType::kSemiInteger) {
|
|
3342
|
+
lp.integrality_[iCol] = HighsVarType::kInteger;
|
|
3343
|
+
}
|
|
3344
|
+
// Change the lower bound on the semi-variable to zero. Cannot
|
|
3345
|
+
// do this earlier, as its original value is used in constraint
|
|
3346
|
+
// 0 <= x-l*y
|
|
3347
|
+
lp.col_lower_[iCol] = 0;
|
|
3348
|
+
}
|
|
3349
|
+
}
|
|
3350
|
+
num_col += num_semi_variables;
|
|
3351
|
+
lp.num_col_ += num_semi_variables;
|
|
3352
|
+
lp.num_row_ += 2 * num_semi_variables;
|
|
3353
|
+
assert((HighsInt)index.size() == new_num_nz);
|
|
3354
|
+
// Ensure that the matrix dimensions are consistent with the LP
|
|
3355
|
+
// dimensions
|
|
3356
|
+
lp.a_matrix_.num_col_ = lp.num_col_;
|
|
3357
|
+
lp.a_matrix_.num_row_ = lp.num_row_;
|
|
3358
|
+
// Clear any modifications inherited from lp_
|
|
3359
|
+
lp.mods_.clear();
|
|
3360
|
+
return lp;
|
|
3361
|
+
}
|
|
3362
|
+
|
|
3363
|
+
void removeRowsOfCountOne(const HighsLogOptions& log_options, HighsLp& lp) {
|
|
3364
|
+
HighsLp row_wise_lp = lp;
|
|
3365
|
+
vector<HighsInt>& a_start = lp.a_matrix_.start_;
|
|
3366
|
+
vector<HighsInt>& a_index = lp.a_matrix_.index_;
|
|
3367
|
+
vector<double>& a_value = lp.a_matrix_.value_;
|
|
3368
|
+
vector<HighsInt> a_count;
|
|
3369
|
+
vector<HighsInt> ar_count;
|
|
3370
|
+
vector<HighsInt> ar_start;
|
|
3371
|
+
vector<HighsInt> ar_index;
|
|
3372
|
+
vector<double> ar_value;
|
|
3373
|
+
const bool have_name = lp.row_names_.size() > 0;
|
|
3374
|
+
HighsInt num_nz = a_start[lp.num_col_];
|
|
3375
|
+
const HighsInt original_num_nz = num_nz;
|
|
3376
|
+
const HighsInt original_num_row = lp.num_row_;
|
|
3377
|
+
HighsInt num_row_count_1 = 0;
|
|
3378
|
+
ar_count.assign(lp.num_row_, 0);
|
|
3379
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
3380
|
+
for (HighsInt iEl = a_start[iCol]; iEl < a_start[iCol + 1]; iEl++)
|
|
3381
|
+
ar_count[a_index[iEl]]++;
|
|
3382
|
+
}
|
|
3383
|
+
ar_start.push_back(0);
|
|
3384
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
3385
|
+
ar_start.push_back(ar_start[iRow] + ar_count[iRow]);
|
|
3386
|
+
ar_count[iRow] = ar_start[iRow];
|
|
3387
|
+
}
|
|
3388
|
+
ar_index.resize(num_nz);
|
|
3389
|
+
ar_value.resize(num_nz);
|
|
3390
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
3391
|
+
for (HighsInt iEl = a_start[iCol]; iEl < a_start[iCol + 1]; iEl++) {
|
|
3392
|
+
HighsInt iRow = a_index[iEl];
|
|
3393
|
+
ar_index[ar_count[iRow]] = iCol;
|
|
3394
|
+
ar_value[ar_count[iRow]] = a_value[iEl];
|
|
3395
|
+
ar_count[iRow]++;
|
|
3396
|
+
}
|
|
3397
|
+
}
|
|
3398
|
+
HighsInt newRow = 0;
|
|
3399
|
+
HighsInt newEl = 0;
|
|
3400
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
3401
|
+
const HighsInt row_count = ar_start[iRow + 1] - ar_start[iRow];
|
|
3402
|
+
if (row_count == 1) {
|
|
3403
|
+
HighsInt iCol = ar_index[ar_start[iRow]];
|
|
3404
|
+
double value = ar_value[ar_start[iRow]];
|
|
3405
|
+
assert(value);
|
|
3406
|
+
if (value > 0) {
|
|
3407
|
+
if (lp.row_lower_[iRow] > -kHighsInf)
|
|
3408
|
+
lp.col_lower_[iCol] =
|
|
3409
|
+
std::max(lp.row_lower_[iRow] / value, lp.col_lower_[iCol]);
|
|
3410
|
+
if (lp.row_upper_[iRow] < kHighsInf)
|
|
3411
|
+
lp.col_upper_[iCol] =
|
|
3412
|
+
std::min(lp.row_upper_[iRow] / value, lp.col_upper_[iCol]);
|
|
3413
|
+
} else {
|
|
3414
|
+
if (lp.row_lower_[iRow] > -kHighsInf)
|
|
3415
|
+
lp.col_upper_[iCol] =
|
|
3416
|
+
std::min(lp.row_lower_[iRow] / value, lp.col_upper_[iCol]);
|
|
3417
|
+
if (lp.row_upper_[iRow] < kHighsInf)
|
|
3418
|
+
lp.col_lower_[iCol] =
|
|
3419
|
+
std::max(lp.row_upper_[iRow] / value, lp.col_lower_[iCol]);
|
|
3420
|
+
}
|
|
3421
|
+
num_row_count_1++;
|
|
3422
|
+
continue;
|
|
3423
|
+
}
|
|
3424
|
+
lp.row_lower_[newRow] = lp.row_lower_[iRow];
|
|
3425
|
+
lp.row_upper_[newRow] = lp.row_upper_[iRow];
|
|
3426
|
+
if (have_name) lp.row_names_[newRow] = lp.row_names_[iRow];
|
|
3427
|
+
ar_start[newRow] = newEl;
|
|
3428
|
+
for (HighsInt iEl = ar_start[iRow]; iEl < ar_start[iRow + 1]; iEl++) {
|
|
3429
|
+
ar_index[newEl] = ar_index[iEl];
|
|
3430
|
+
ar_value[newEl] = ar_value[iEl];
|
|
3431
|
+
newEl++;
|
|
3432
|
+
}
|
|
3433
|
+
newRow++;
|
|
3434
|
+
}
|
|
3435
|
+
ar_start[newRow] = newEl;
|
|
3436
|
+
lp.num_row_ = newRow;
|
|
3437
|
+
lp.row_lower_.resize(newRow);
|
|
3438
|
+
lp.row_upper_.resize(newRow);
|
|
3439
|
+
if (have_name) lp.row_names_.resize(newRow);
|
|
3440
|
+
|
|
3441
|
+
num_nz = ar_start[lp.num_row_];
|
|
3442
|
+
a_count.assign(lp.num_col_, 0);
|
|
3443
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
3444
|
+
for (HighsInt iEl = ar_start[iRow]; iEl < ar_start[iRow + 1]; iEl++)
|
|
3445
|
+
a_count[ar_index[iEl]]++;
|
|
3446
|
+
}
|
|
3447
|
+
a_start[0] = 0;
|
|
3448
|
+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
|
|
3449
|
+
a_start[iCol + 1] = a_start[iCol] + a_count[iCol];
|
|
3450
|
+
a_count[iCol] = a_start[iCol];
|
|
3451
|
+
}
|
|
3452
|
+
a_index.resize(num_nz);
|
|
3453
|
+
a_value.resize(num_nz);
|
|
3454
|
+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
|
|
3455
|
+
for (HighsInt iEl = ar_start[iRow]; iEl < ar_start[iRow + 1]; iEl++) {
|
|
3456
|
+
HighsInt iCol = ar_index[iEl];
|
|
3457
|
+
a_index[a_count[iCol]] = iRow;
|
|
3458
|
+
a_value[a_count[iCol]] = ar_value[iEl];
|
|
3459
|
+
a_count[iCol]++;
|
|
3460
|
+
}
|
|
3461
|
+
}
|
|
3462
|
+
assert(original_num_row - lp.num_row_ == num_row_count_1);
|
|
3463
|
+
assert(original_num_nz - num_nz == num_row_count_1);
|
|
3464
|
+
highsLogUser(log_options, HighsLogType::kWarning,
|
|
3465
|
+
"Removed %d rows of count 1\n", (int)num_row_count_1);
|
|
3466
|
+
}
|
|
3467
|
+
|
|
3468
|
+
void getSubVectors(const HighsIndexCollection& index_collection,
|
|
3469
|
+
const HighsInt data_dim, const double* data0,
|
|
3470
|
+
const double* data1, const double* data2,
|
|
3471
|
+
const HighsSparseMatrix& matrix, HighsInt& num_sub_vector,
|
|
3472
|
+
double* sub_vector_data0, double* sub_vector_data1,
|
|
3473
|
+
double* sub_vector_data2, HighsInt& sub_matrix_num_nz,
|
|
3474
|
+
HighsInt* sub_matrix_start, HighsInt* sub_matrix_index,
|
|
3475
|
+
double* sub_matrix_value) {
|
|
3476
|
+
// Ensure that if there's no data0 then it's not required in the
|
|
3477
|
+
// sub-vector
|
|
3478
|
+
if (data0 == nullptr) assert(sub_vector_data0 == nullptr);
|
|
3479
|
+
assert(ok(index_collection));
|
|
3480
|
+
HighsInt from_k;
|
|
3481
|
+
HighsInt to_k;
|
|
3482
|
+
limits(index_collection, from_k, to_k);
|
|
3483
|
+
// Surely this is checked elsewhere
|
|
3484
|
+
assert(0 <= from_k && to_k < data_dim);
|
|
3485
|
+
assert(from_k <= to_k);
|
|
3486
|
+
HighsInt out_from_vector;
|
|
3487
|
+
HighsInt out_to_vector;
|
|
3488
|
+
HighsInt in_from_vector;
|
|
3489
|
+
HighsInt in_to_vector = -1;
|
|
3490
|
+
HighsInt current_set_entry = 0;
|
|
3491
|
+
num_sub_vector = 0;
|
|
3492
|
+
sub_matrix_num_nz = 0;
|
|
3493
|
+
for (HighsInt k = from_k; k <= to_k; k++) {
|
|
3494
|
+
updateOutInIndex(index_collection, out_from_vector, out_to_vector,
|
|
3495
|
+
in_from_vector, in_to_vector, current_set_entry);
|
|
3496
|
+
assert(out_to_vector < data_dim);
|
|
3497
|
+
assert(in_to_vector < data_dim);
|
|
3498
|
+
for (HighsInt iVector = out_from_vector; iVector <= out_to_vector;
|
|
3499
|
+
iVector++) {
|
|
3500
|
+
if (sub_vector_data0 != nullptr)
|
|
3501
|
+
sub_vector_data0[num_sub_vector] = data0[iVector];
|
|
3502
|
+
if (sub_vector_data1 != nullptr)
|
|
3503
|
+
sub_vector_data1[num_sub_vector] = data1[iVector];
|
|
3504
|
+
if (sub_vector_data2 != nullptr)
|
|
3505
|
+
sub_vector_data2[num_sub_vector] = data2[iVector];
|
|
3506
|
+
if (sub_matrix_start != nullptr)
|
|
3507
|
+
sub_matrix_start[num_sub_vector] = sub_matrix_num_nz +
|
|
3508
|
+
matrix.start_[iVector] -
|
|
3509
|
+
matrix.start_[out_from_vector];
|
|
3510
|
+
num_sub_vector++;
|
|
3511
|
+
}
|
|
3512
|
+
for (HighsInt iEl = matrix.start_[out_from_vector];
|
|
3513
|
+
iEl < matrix.start_[out_to_vector + 1]; iEl++) {
|
|
3514
|
+
if (sub_matrix_index != nullptr)
|
|
3515
|
+
sub_matrix_index[sub_matrix_num_nz] = matrix.index_[iEl];
|
|
3516
|
+
if (sub_matrix_value != nullptr)
|
|
3517
|
+
sub_matrix_value[sub_matrix_num_nz] = matrix.value_[iEl];
|
|
3518
|
+
sub_matrix_num_nz++;
|
|
3519
|
+
}
|
|
3520
|
+
if (out_to_vector == data_dim - 1 || in_to_vector == data_dim - 1) break;
|
|
3521
|
+
}
|
|
3522
|
+
}
|
|
3523
|
+
|
|
3524
|
+
void getSubVectorsTranspose(const HighsIndexCollection& index_collection,
|
|
3525
|
+
const HighsInt data_dim, const double* data0,
|
|
3526
|
+
const double* data1, const double* data2,
|
|
3527
|
+
const HighsSparseMatrix& matrix,
|
|
3528
|
+
HighsInt& num_sub_vector, double* sub_vector_data0,
|
|
3529
|
+
double* sub_vector_data1, double* sub_vector_data2,
|
|
3530
|
+
HighsInt& sub_matrix_num_nz,
|
|
3531
|
+
HighsInt* sub_matrix_start,
|
|
3532
|
+
HighsInt* sub_matrix_index,
|
|
3533
|
+
double* sub_matrix_value) {
|
|
3534
|
+
// Ensure that if there's no data0 then it's not required in the
|
|
3535
|
+
// sub-vector
|
|
3536
|
+
if (data0 == nullptr) assert(sub_vector_data0 == nullptr);
|
|
3537
|
+
assert(ok(index_collection));
|
|
3538
|
+
HighsInt from_k;
|
|
3539
|
+
HighsInt to_k;
|
|
3540
|
+
limits(index_collection, from_k, to_k);
|
|
3541
|
+
// Surely this is checked elsewhere
|
|
3542
|
+
assert(0 <= from_k && to_k < data_dim);
|
|
3543
|
+
assert(from_k <= to_k);
|
|
3544
|
+
// "Out" means not in the set to be extracted
|
|
3545
|
+
// "In" means in the set to be extracted
|
|
3546
|
+
HighsInt out_from_vector;
|
|
3547
|
+
HighsInt out_to_vector;
|
|
3548
|
+
HighsInt in_from_vector;
|
|
3549
|
+
HighsInt in_to_vector = -1;
|
|
3550
|
+
HighsInt current_set_entry = 0;
|
|
3551
|
+
// Set up a mask so that entries to be got from the matrix can be
|
|
3552
|
+
// identified and have their correct index.
|
|
3553
|
+
vector<HighsInt> new_index;
|
|
3554
|
+
new_index.resize(data_dim);
|
|
3555
|
+
|
|
3556
|
+
num_sub_vector = 0;
|
|
3557
|
+
sub_matrix_num_nz = 0;
|
|
3558
|
+
if (!index_collection.is_mask_) {
|
|
3559
|
+
out_to_vector = -1;
|
|
3560
|
+
current_set_entry = 0;
|
|
3561
|
+
for (HighsInt k = from_k; k <= to_k; k++) {
|
|
3562
|
+
updateOutInIndex(index_collection, in_from_vector, in_to_vector,
|
|
3563
|
+
out_from_vector, out_to_vector, current_set_entry);
|
|
3564
|
+
if (k == from_k) {
|
|
3565
|
+
// Account for any initial vectors not being extracted
|
|
3566
|
+
for (HighsInt iVector = 0; iVector < in_from_vector; iVector++) {
|
|
3567
|
+
new_index[iVector] = -1;
|
|
3568
|
+
}
|
|
3569
|
+
}
|
|
3570
|
+
for (HighsInt iVector = in_from_vector; iVector <= in_to_vector;
|
|
3571
|
+
iVector++) {
|
|
3572
|
+
new_index[iVector] = num_sub_vector;
|
|
3573
|
+
num_sub_vector++;
|
|
3574
|
+
}
|
|
3575
|
+
for (HighsInt iVector = out_from_vector; iVector <= out_to_vector;
|
|
3576
|
+
iVector++) {
|
|
3577
|
+
new_index[iVector] = -1;
|
|
3578
|
+
}
|
|
3579
|
+
if (out_to_vector >= data_dim - 1) break;
|
|
3580
|
+
}
|
|
3581
|
+
} else {
|
|
3582
|
+
for (HighsInt iVector = 0; iVector < data_dim; iVector++) {
|
|
3583
|
+
if (index_collection.mask_[iVector]) {
|
|
3584
|
+
new_index[iVector] = num_sub_vector;
|
|
3585
|
+
num_sub_vector++;
|
|
3586
|
+
} else {
|
|
3587
|
+
new_index[iVector] = -1;
|
|
3588
|
+
}
|
|
3589
|
+
}
|
|
3590
|
+
}
|
|
3591
|
+
|
|
3592
|
+
// Bail out if no vectors are to be extracted
|
|
3593
|
+
if (num_sub_vector == 0) return;
|
|
3594
|
+
|
|
3595
|
+
for (HighsInt iVector = 0; iVector < data_dim; iVector++) {
|
|
3596
|
+
HighsInt new_iVector = new_index[iVector];
|
|
3597
|
+
if (new_iVector >= 0) {
|
|
3598
|
+
assert(new_iVector < num_sub_vector);
|
|
3599
|
+
if (sub_vector_data0 != NULL)
|
|
3600
|
+
sub_vector_data0[new_iVector] = data0[iVector];
|
|
3601
|
+
if (sub_vector_data1 != NULL)
|
|
3602
|
+
sub_vector_data1[new_iVector] = data1[iVector];
|
|
3603
|
+
if (sub_vector_data2 != NULL)
|
|
3604
|
+
sub_vector_data2[new_iVector] = data2[iVector];
|
|
3605
|
+
}
|
|
3606
|
+
}
|
|
3607
|
+
const bool extract_start = sub_matrix_start != NULL;
|
|
3608
|
+
const bool extract_index = sub_matrix_index != NULL;
|
|
3609
|
+
const bool extract_value = sub_matrix_value != NULL;
|
|
3610
|
+
const bool extract_matrix = extract_index || extract_value;
|
|
3611
|
+
// Allocate an array of lengths for the sub-matrix to be
|
|
3612
|
+
// extracted: necessary even if just the number of nonzeros is
|
|
3613
|
+
// required
|
|
3614
|
+
vector<HighsInt> sub_matrix_length;
|
|
3615
|
+
sub_matrix_length.assign(num_sub_vector, 0);
|
|
3616
|
+
// Identify the lengths of the vectors in the sub-matrix to be extracted
|
|
3617
|
+
HighsInt num_vector = matrix.start_.size() - 1;
|
|
3618
|
+
for (HighsInt vector = 0; vector < num_vector; vector++) {
|
|
3619
|
+
for (HighsInt iEl = matrix.start_[vector]; iEl < matrix.start_[vector + 1];
|
|
3620
|
+
iEl++) {
|
|
3621
|
+
HighsInt iVector = matrix.index_[iEl];
|
|
3622
|
+
HighsInt new_iVector = new_index[iVector];
|
|
3623
|
+
if (new_iVector >= 0) sub_matrix_length[new_iVector]++;
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
if (!extract_start) {
|
|
3627
|
+
// bail out if no matrix starts are to be extracted, but only after
|
|
3628
|
+
// computing the number of nonzeros
|
|
3629
|
+
for (HighsInt iVector = 0; iVector < num_sub_vector; iVector++)
|
|
3630
|
+
sub_matrix_num_nz += sub_matrix_length[iVector];
|
|
3631
|
+
return;
|
|
3632
|
+
}
|
|
3633
|
+
// Allocate an array of lengths for the sub-matrix to be extracted
|
|
3634
|
+
sub_matrix_start[0] = 0;
|
|
3635
|
+
for (HighsInt iVector = 0; iVector < num_sub_vector - 1; iVector++) {
|
|
3636
|
+
sub_matrix_start[iVector + 1] =
|
|
3637
|
+
sub_matrix_start[iVector] + sub_matrix_length[iVector];
|
|
3638
|
+
sub_matrix_length[iVector] = sub_matrix_start[iVector];
|
|
3639
|
+
}
|
|
3640
|
+
HighsInt iVector = num_sub_vector - 1;
|
|
3641
|
+
sub_matrix_num_nz = sub_matrix_start[iVector] + sub_matrix_length[iVector];
|
|
3642
|
+
// Bail out if matrix indices and values are not required
|
|
3643
|
+
if (!extract_matrix) return;
|
|
3644
|
+
sub_matrix_length[iVector] = sub_matrix_start[iVector];
|
|
3645
|
+
// Fill the row-wise matrix with indices and values
|
|
3646
|
+
for (HighsInt vector = 0; vector < num_vector; vector++) {
|
|
3647
|
+
for (HighsInt iEl = matrix.start_[vector]; iEl < matrix.start_[vector + 1];
|
|
3648
|
+
iEl++) {
|
|
3649
|
+
HighsInt iVector = matrix.index_[iEl];
|
|
3650
|
+
HighsInt new_iVector = new_index[iVector];
|
|
3651
|
+
if (new_iVector >= 0) {
|
|
3652
|
+
HighsInt row_iEl = sub_matrix_length[new_iVector];
|
|
3653
|
+
if (extract_index) sub_matrix_index[row_iEl] = vector;
|
|
3654
|
+
if (extract_value) sub_matrix_value[row_iEl] = matrix.value_[iEl];
|
|
3655
|
+
sub_matrix_length[new_iVector]++;
|
|
3656
|
+
}
|
|
3657
|
+
}
|
|
3658
|
+
}
|
|
3659
|
+
}
|
|
3660
|
+
|
|
3661
|
+
std::string highsVarTypeToString(const HighsVarType type) {
|
|
3662
|
+
switch (type) {
|
|
3663
|
+
case HighsVarType::kContinuous:
|
|
3664
|
+
return "continuous";
|
|
3665
|
+
case HighsVarType::kInteger:
|
|
3666
|
+
return "integer";
|
|
3667
|
+
case HighsVarType::kSemiContinuous:
|
|
3668
|
+
return "semi continuous";
|
|
3669
|
+
case HighsVarType::kSemiInteger:
|
|
3670
|
+
return "semi integer";
|
|
3671
|
+
case HighsVarType::kImplicitInteger:
|
|
3672
|
+
return "implicit integer";
|
|
3673
|
+
default:
|
|
3674
|
+
return "unknown";
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
|
|
3678
|
+
std::string highsVarTypeToString(const HighsInt type) {
|
|
3679
|
+
if (type < HighsInt(HighsVarType::kContinuous) ||
|
|
3680
|
+
type > HighsInt(HighsVarType::kImplicitInteger))
|
|
3681
|
+
return "unknown";
|
|
3682
|
+
HighsVarType type_ = HighsVarType(uint8_t(type));
|
|
3683
|
+
return highsVarTypeToString(type_);
|
|
3684
|
+
}
|
|
3685
|
+
|
|
3686
|
+
void initialiseUserScaleData(const HighsOptions& options,
|
|
3687
|
+
HighsUserScaleData& user_scale_data) {
|
|
3688
|
+
user_scale_data.initialise(options.user_objective_scale,
|
|
3689
|
+
options.user_bound_scale, options.infinite_cost,
|
|
3690
|
+
options.infinite_bound, options.small_matrix_value,
|
|
3691
|
+
options.large_matrix_value);
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
void HighsUserScaleData::initialise(const HighsInt& user_objective_scale_,
|
|
3695
|
+
const HighsInt& user_bound_scale_,
|
|
3696
|
+
const double& infinite_cost_,
|
|
3697
|
+
const double& infinite_bound_,
|
|
3698
|
+
const double& small_matrix_value_,
|
|
3699
|
+
const double& large_matrix_value_) {
|
|
3700
|
+
this->user_objective_scale = user_objective_scale_;
|
|
3701
|
+
this->user_bound_scale = user_bound_scale_;
|
|
3702
|
+
this->infinite_cost = infinite_cost_;
|
|
3703
|
+
this->infinite_bound = infinite_bound_;
|
|
3704
|
+
this->small_matrix_value = small_matrix_value_;
|
|
3705
|
+
this->large_matrix_value = large_matrix_value_;
|
|
3706
|
+
this->num_infinite_costs = 0;
|
|
3707
|
+
this->num_infinite_hessian_values = 0;
|
|
3708
|
+
this->num_infinite_col_bounds = 0;
|
|
3709
|
+
this->num_infinite_row_bounds = 0;
|
|
3710
|
+
this->num_small_matrix_values = 0;
|
|
3711
|
+
this->num_large_matrix_values = 0;
|
|
3712
|
+
this->suggested_user_objective_scale = 0;
|
|
3713
|
+
this->suggested_user_bound_scale = 0;
|
|
3714
|
+
this->applied = false;
|
|
3715
|
+
}
|
|
3716
|
+
|
|
3717
|
+
bool HighsUserScaleData::scaleError(std::string& message) const {
|
|
3718
|
+
if (this->num_infinite_costs + this->num_infinite_hessian_values +
|
|
3719
|
+
this->num_infinite_col_bounds + this->num_infinite_row_bounds +
|
|
3720
|
+
this->num_large_matrix_values ==
|
|
3721
|
+
0)
|
|
3722
|
+
return false;
|
|
3723
|
+
assert(this->user_objective_scale != 0 || this->user_bound_scale != 0);
|
|
3724
|
+
std::stringstream ss;
|
|
3725
|
+
ss.str(std::string());
|
|
3726
|
+
ss << "User scaling of";
|
|
3727
|
+
if (this->user_objective_scale != 0) {
|
|
3728
|
+
ss << " 2**(" << this->user_objective_scale << ") for costs";
|
|
3729
|
+
}
|
|
3730
|
+
if (this->user_bound_scale != 0) {
|
|
3731
|
+
if (this->user_objective_scale != 0) ss << " and";
|
|
3732
|
+
ss << " 2**(" << this->user_bound_scale << ") for bounds";
|
|
3733
|
+
}
|
|
3734
|
+
ss << " yields";
|
|
3735
|
+
if (this->num_infinite_costs) {
|
|
3736
|
+
ss << " " << this->num_infinite_costs << " infinite cost";
|
|
3737
|
+
if (this->num_infinite_costs > 1) ss << "s";
|
|
3738
|
+
}
|
|
3739
|
+
if (this->num_infinite_hessian_values) {
|
|
3740
|
+
if (this->num_infinite_costs) {
|
|
3741
|
+
if (this->num_infinite_col_bounds || this->num_infinite_row_bounds) {
|
|
3742
|
+
ss << ",";
|
|
3743
|
+
} else {
|
|
3744
|
+
ss << " and";
|
|
3745
|
+
}
|
|
3746
|
+
}
|
|
3747
|
+
ss << " " << this->num_infinite_hessian_values
|
|
3748
|
+
<< " infinite Hessian values";
|
|
3749
|
+
if (this->num_infinite_hessian_values > 1) ss << "s";
|
|
3750
|
+
}
|
|
3751
|
+
if (this->num_infinite_col_bounds) {
|
|
3752
|
+
if (this->num_infinite_costs || this->num_infinite_hessian_values) {
|
|
3753
|
+
if (this->num_infinite_row_bounds) {
|
|
3754
|
+
ss << ",";
|
|
3755
|
+
} else {
|
|
3756
|
+
ss << " and";
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
ss << " " << this->num_infinite_col_bounds << " infinite column bound";
|
|
3760
|
+
if (this->num_infinite_col_bounds > 1) ss << "s";
|
|
3761
|
+
}
|
|
3762
|
+
if (this->num_infinite_row_bounds) {
|
|
3763
|
+
if (this->num_infinite_costs || this->num_infinite_hessian_values ||
|
|
3764
|
+
this->num_infinite_col_bounds)
|
|
3765
|
+
ss << " and";
|
|
3766
|
+
ss << " " << this->num_infinite_row_bounds << " infinite row bound";
|
|
3767
|
+
if (this->num_infinite_row_bounds > 1) ss << "s";
|
|
3768
|
+
}
|
|
3769
|
+
if (this->num_large_matrix_values) {
|
|
3770
|
+
if (this->num_infinite_costs + this->num_infinite_hessian_values +
|
|
3771
|
+
this->num_infinite_col_bounds + this->num_infinite_row_bounds >
|
|
3772
|
+
0)
|
|
3773
|
+
ss << ", and";
|
|
3774
|
+
ss << " " << this->num_large_matrix_values << " large matrix value";
|
|
3775
|
+
if (this->num_large_matrix_values > 1) ss << "s";
|
|
3776
|
+
}
|
|
3777
|
+
ss << "\n";
|
|
3778
|
+
message = ss.str();
|
|
3779
|
+
return true;
|
|
3780
|
+
}
|
|
3781
|
+
|
|
3782
|
+
bool HighsUserScaleData::scaleWarning(std::string& message) const {
|
|
3783
|
+
if (this->num_small_matrix_values == 0) return false;
|
|
3784
|
+
assert(this->user_bound_scale != 0);
|
|
3785
|
+
std::stringstream ss;
|
|
3786
|
+
ss.str(std::string());
|
|
3787
|
+
ss << "User scaling of 2**(" << this->user_bound_scale
|
|
3788
|
+
<< ") for bounds yields " << this->num_small_matrix_values
|
|
3789
|
+
<< " small matrix value";
|
|
3790
|
+
if (this->num_small_matrix_values > 1) ss << "s";
|
|
3791
|
+
ss << "\n";
|
|
3792
|
+
message = ss.str();
|
|
3793
|
+
return true;
|
|
3794
|
+
}
|