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