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