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