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,3861 @@
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
+ #include "mip/HighsDomain.h"
9
+
10
+ #include <algorithm>
11
+ #include <cassert>
12
+ #include <numeric>
13
+ #include <queue>
14
+
15
+ #include "../extern/pdqsort/pdqsort.h"
16
+ #include "mip/HighsConflictPool.h"
17
+ #include "mip/HighsCutPool.h"
18
+ #include "mip/HighsMipSolverData.h"
19
+
20
+ static double activityContributionMin(double coef, const double& lb,
21
+ const double& ub) {
22
+ if (coef < 0) {
23
+ if (ub == kHighsInf) return -kHighsInf;
24
+
25
+ return coef * ub;
26
+ } else {
27
+ if (lb == -kHighsInf) return -kHighsInf;
28
+
29
+ return coef * lb;
30
+ }
31
+ }
32
+
33
+ static double activityContributionMax(double coef, const double& lb,
34
+ const double& ub) {
35
+ if (coef < 0) {
36
+ if (lb == -kHighsInf) return kHighsInf;
37
+
38
+ return coef * lb;
39
+ } else {
40
+ if (ub == kHighsInf) return kHighsInf;
41
+
42
+ return coef * ub;
43
+ }
44
+ }
45
+
46
+ static HighsCDouble computeDelta(double val, double oldbound, double newbound,
47
+ double inf, HighsInt& numinfs) {
48
+ if (oldbound == inf) {
49
+ --numinfs;
50
+ return static_cast<HighsCDouble>(newbound) * val;
51
+ } else if (newbound == inf) {
52
+ ++numinfs;
53
+ return static_cast<HighsCDouble>(-oldbound) * val;
54
+ } else {
55
+ return (static_cast<HighsCDouble>(newbound) -
56
+ static_cast<HighsCDouble>(oldbound)) *
57
+ val;
58
+ }
59
+ }
60
+
61
+ static inline double boundRange(double upper_bound, double lower_bound,
62
+ double tolerance, HighsVarType var_type) {
63
+ double range = upper_bound - lower_bound;
64
+ return range - (var_type == HighsVarType::kContinuous
65
+ ? std::max(0.3 * range, 1000.0 * tolerance)
66
+ : tolerance);
67
+ }
68
+
69
+ HighsDomain::HighsDomain(HighsMipSolver& mipsolver) : mipsolver(&mipsolver) {
70
+ col_lower_ = mipsolver.model_->col_lower_;
71
+ col_upper_ = mipsolver.model_->col_upper_;
72
+ colLowerPos_.assign(mipsolver.numCol(), -1);
73
+ colUpperPos_.assign(mipsolver.numCol(), -1);
74
+ changedcolsflags_.resize(mipsolver.numCol());
75
+ changedcols_.reserve(mipsolver.numCol());
76
+ infeasible_reason = Reason::unspecified();
77
+ infeasible_ = false;
78
+ }
79
+
80
+ void HighsDomain::addCutpool(HighsCutPool& cutpool) {
81
+ HighsInt cutpoolindex = cutpoolpropagation.size();
82
+ cutpoolpropagation.emplace_back(cutpoolindex, this, cutpool);
83
+ }
84
+
85
+ void HighsDomain::addConflictPool(HighsConflictPool& conflictPool) {
86
+ HighsInt conflictPoolIndex = conflictPoolPropagation.size();
87
+ conflictPoolPropagation.emplace_back(conflictPoolIndex, this, conflictPool);
88
+ }
89
+
90
+ void HighsDomain::ConflictPoolPropagation::linkWatchedLiteral(
91
+ HighsInt linkPos) {
92
+ assert(watchedLiterals_[linkPos].domchg.column != -1);
93
+ HighsInt& head =
94
+ watchedLiterals_[linkPos].domchg.boundtype == HighsBoundType::kLower
95
+ ? colLowerWatched_[watchedLiterals_[linkPos].domchg.column]
96
+ : colUpperWatched_[watchedLiterals_[linkPos].domchg.column];
97
+
98
+ watchedLiterals_[linkPos].prev = -1;
99
+ watchedLiterals_[linkPos].next = head;
100
+ if (head != -1) {
101
+ watchedLiterals_[head].prev = linkPos;
102
+ head = linkPos;
103
+ }
104
+ }
105
+
106
+ void HighsDomain::ConflictPoolPropagation::unlinkWatchedLiteral(
107
+ HighsInt linkPos) {
108
+ if (watchedLiterals_[linkPos].domchg.column == -1) return;
109
+
110
+ HighsInt& head =
111
+ watchedLiterals_[linkPos].domchg.boundtype == HighsBoundType::kLower
112
+ ? colLowerWatched_[watchedLiterals_[linkPos].domchg.column]
113
+ : colUpperWatched_[watchedLiterals_[linkPos].domchg.column];
114
+ watchedLiterals_[linkPos].domchg.column = -1;
115
+ HighsInt prev = watchedLiterals_[linkPos].prev;
116
+ HighsInt next = watchedLiterals_[linkPos].next;
117
+ if (prev != -1)
118
+ watchedLiterals_[prev].next = next;
119
+ else
120
+ head = next;
121
+
122
+ if (next != -1) watchedLiterals_[next].prev = prev;
123
+ }
124
+
125
+ HighsDomain::ConflictPoolPropagation::ConflictPoolPropagation(
126
+ HighsInt conflictpoolindex, HighsDomain* domain,
127
+ HighsConflictPool& conflictpool_)
128
+ : conflictpoolindex(conflictpoolindex),
129
+ domain(domain),
130
+ conflictpool_(&conflictpool_) {
131
+ colLowerWatched_.resize(domain->mipsolver->numCol(), -1);
132
+ colUpperWatched_.resize(domain->mipsolver->numCol(), -1);
133
+ conflictpool_.addPropagationDomain(this);
134
+ }
135
+
136
+ HighsDomain::ConflictPoolPropagation::ConflictPoolPropagation(
137
+ const ConflictPoolPropagation& other)
138
+ : conflictpoolindex(other.conflictpoolindex),
139
+ domain(other.domain),
140
+ conflictpool_(other.conflictpool_),
141
+ colLowerWatched_(other.colLowerWatched_),
142
+ colUpperWatched_(other.colUpperWatched_),
143
+ conflictFlag_(other.conflictFlag_),
144
+ propagateConflictInds_(other.propagateConflictInds_),
145
+ watchedLiterals_(other.watchedLiterals_) {
146
+ conflictpool_->addPropagationDomain(this);
147
+ }
148
+
149
+ HighsDomain::ConflictPoolPropagation::~ConflictPoolPropagation() {
150
+ conflictpool_->removePropagationDomain(this);
151
+ }
152
+
153
+ void HighsDomain::ConflictPoolPropagation::conflictDeleted(HighsInt conflict) {
154
+ conflictFlag_[conflict] |= 8;
155
+ unlinkWatchedLiteral(2 * conflict);
156
+ unlinkWatchedLiteral(2 * conflict + 1);
157
+ }
158
+
159
+ void HighsDomain::ConflictPoolPropagation::conflictAdded(HighsInt conflict) {
160
+ HighsInt start = conflictpool_->getConflictRanges()[conflict].first;
161
+ HighsInt end = conflictpool_->getConflictRanges()[conflict].second;
162
+ const std::vector<HighsDomainChange>& conflictEntries =
163
+ conflictpool_->getConflictEntryVector();
164
+
165
+ if (HighsInt(conflictFlag_.size()) <= conflict) {
166
+ watchedLiterals_.resize(2 * conflict + 2);
167
+ conflictFlag_.resize(conflict + 1);
168
+ }
169
+
170
+ HighsInt numWatched = 0;
171
+ for (HighsInt i = start; i != end; ++i) {
172
+ if (domain->isActive(conflictEntries[i])) continue;
173
+ HighsInt watchPos = 2 * conflict + numWatched;
174
+ watchedLiterals_[watchPos].domchg = conflictEntries[i];
175
+ linkWatchedLiteral(watchPos);
176
+ if (++numWatched == 2) break;
177
+ }
178
+ switch (numWatched) {
179
+ case 0: {
180
+ std::array<std::pair<HighsInt, HighsInt>, 2> latestActive;
181
+ HighsInt numActive = 0;
182
+ for (HighsInt i = start; i != end; ++i) {
183
+ HighsInt pos = conflictEntries[i].boundtype == HighsBoundType::kLower
184
+ ? domain->colLowerPos_[conflictEntries[i].column]
185
+ : domain->colUpperPos_[conflictEntries[i].column];
186
+ switch (numActive) {
187
+ case 0:
188
+ latestActive[0] = std::make_pair(pos, i);
189
+ numActive = 1;
190
+ break;
191
+ case 1:
192
+ latestActive[1] = std::make_pair(pos, i);
193
+ numActive = 2;
194
+ if (latestActive[0].first < latestActive[1].first)
195
+ std::swap(latestActive[0], latestActive[1]);
196
+ break;
197
+ case 2:
198
+ if (pos > latestActive[1].first) {
199
+ latestActive[1] = std::make_pair(pos, i);
200
+ if (latestActive[0].first < latestActive[1].first)
201
+ std::swap(latestActive[0], latestActive[1]);
202
+ }
203
+ }
204
+ }
205
+ for (HighsInt i = 0; i < numActive; ++i) {
206
+ HighsInt watchPos = 2 * conflict + i;
207
+ watchedLiterals_[watchPos].domchg =
208
+ conflictEntries[latestActive[i].second];
209
+ linkWatchedLiteral(watchPos);
210
+ }
211
+ break;
212
+ }
213
+ case 1: {
214
+ HighsInt latestActive = -1;
215
+ HighsInt latestPos = -1;
216
+
217
+ for (HighsInt i = start; i != end; ++i) {
218
+ HighsInt pos = conflictEntries[i].boundtype == HighsBoundType::kLower
219
+ ? domain->colLowerPos_[conflictEntries[i].column]
220
+ : domain->colUpperPos_[conflictEntries[i].column];
221
+ if (pos > latestPos) {
222
+ latestActive = i;
223
+ latestPos = pos;
224
+ }
225
+ }
226
+ if (latestActive != -1) {
227
+ HighsInt watchPos = 2 * conflict + 1;
228
+ watchedLiterals_[watchPos].domchg = conflictEntries[latestActive];
229
+ linkWatchedLiteral(watchPos);
230
+ }
231
+ break;
232
+ }
233
+ case 2:
234
+ break;
235
+ }
236
+
237
+ conflictFlag_[conflict] = numWatched | (conflictFlag_[conflict] & 4);
238
+ markPropagateConflict(conflict);
239
+ }
240
+
241
+ void HighsDomain::ConflictPoolPropagation::markPropagateConflict(
242
+ HighsInt conflict) {
243
+ if (conflictFlag_[conflict] < 2) {
244
+ propagateConflictInds_.push_back(conflict);
245
+ conflictFlag_[conflict] |= 4;
246
+ }
247
+ }
248
+
249
+ void HighsDomain::ConflictPoolPropagation::updateActivityLbChange(
250
+ HighsInt col, double oldbound, double newbound) {
251
+ assert(!domain->infeasible_);
252
+
253
+ for (HighsInt i = colLowerWatched_[col]; i != -1;
254
+ i = watchedLiterals_[i].next) {
255
+ HighsInt conflict = i >> 1;
256
+
257
+ const HighsDomainChange& domchg = watchedLiterals_[i].domchg;
258
+ uint8_t numInactiveDelta =
259
+ (domchg.boundval > newbound) - (domchg.boundval > oldbound);
260
+ if (numInactiveDelta != 0) {
261
+ conflictFlag_[conflict] += numInactiveDelta;
262
+ markPropagateConflict(conflict);
263
+ }
264
+ }
265
+ }
266
+
267
+ void HighsDomain::ConflictPoolPropagation::updateActivityUbChange(
268
+ HighsInt col, double oldbound, double newbound) {
269
+ assert(!domain->infeasible_);
270
+
271
+ for (HighsInt i = colUpperWatched_[col]; i != -1;
272
+ i = watchedLiterals_[i].next) {
273
+ HighsInt conflict = i >> 1;
274
+
275
+ const HighsDomainChange& domchg = watchedLiterals_[i].domchg;
276
+ uint8_t numInactiveDelta =
277
+ (domchg.boundval < newbound) - (domchg.boundval < oldbound);
278
+ if (numInactiveDelta != 0) {
279
+ conflictFlag_[conflict] += numInactiveDelta;
280
+ markPropagateConflict(conflict);
281
+ }
282
+ }
283
+ }
284
+
285
+ void HighsDomain::ConflictPoolPropagation::propagateConflict(
286
+ HighsInt conflict) {
287
+ // remove propagate flag, but keep watched and deleted information
288
+ conflictFlag_[conflict] &= (3 | 8);
289
+ // if two inactive literals are watched or conflict has been deleted skip
290
+ if (conflictFlag_[conflict] >= 2) return;
291
+
292
+ if (domain->infeasible_) return;
293
+
294
+ const std::vector<HighsDomainChange>& entries =
295
+ conflictpool_->getConflictEntryVector();
296
+ HighsInt start = conflictpool_->getConflictRanges()[conflict].first;
297
+ if (start == -1) {
298
+ unlinkWatchedLiteral(2 * conflict);
299
+ unlinkWatchedLiteral(2 * conflict + 1);
300
+ return;
301
+ }
302
+ HighsInt end = conflictpool_->getConflictRanges()[conflict].second;
303
+
304
+ WatchedLiteral* watched = watchedLiterals_.data() + 2 * conflict;
305
+
306
+ std::array<HighsInt, 2> inactive;
307
+ uint8_t numInactive = 0;
308
+ for (HighsInt i = start; i != end; ++i) {
309
+ if (domain->isActive(entries[i])) continue;
310
+
311
+ inactive[numInactive++] = i;
312
+ if (numInactive == 2) break;
313
+ }
314
+
315
+ conflictFlag_[conflict] = numInactive;
316
+
317
+ switch (numInactive) {
318
+ case 0:
319
+ assert(!domain->infeasible_);
320
+ domain->mipsolver->mipdata_->debugSolution.nodePruned(*domain);
321
+ domain->infeasible_ = true;
322
+ domain->infeasible_reason = Reason::cut(
323
+ domain->cutpoolpropagation.size() + conflictpoolindex, conflict);
324
+ domain->infeasible_pos = domain->domchgstack_.size();
325
+ conflictpool_->resetAge(conflict);
326
+ // printf("conflict propagation found infeasibility\n");
327
+ break;
328
+ case 1: {
329
+ HighsDomainChange domchg = domain->flip(entries[inactive[0]]);
330
+ if (!domain->isActive(domchg)) {
331
+ domain->changeBound(
332
+ domain->flip(entries[inactive[0]]),
333
+ Reason::cut(domain->cutpoolpropagation.size() + conflictpoolindex,
334
+ conflict));
335
+ conflictpool_->resetAge(conflict);
336
+ }
337
+ // printf("conflict propagation found bound change\n");
338
+ break;
339
+ }
340
+ case 2: {
341
+ if (watched[0].domchg != entries[inactive[0]]) {
342
+ unlinkWatchedLiteral(2 * conflict);
343
+ watched[0].domchg = entries[inactive[0]];
344
+ linkWatchedLiteral(2 * conflict);
345
+ }
346
+
347
+ if (watched[1].domchg != entries[inactive[1]]) {
348
+ unlinkWatchedLiteral(2 * conflict + 1);
349
+ watched[1].domchg = entries[inactive[1]];
350
+ linkWatchedLiteral(2 * conflict + 1);
351
+ }
352
+
353
+ return;
354
+ }
355
+ }
356
+ }
357
+
358
+ HighsDomain::CutpoolPropagation::CutpoolPropagation(HighsInt cutpoolindex,
359
+ HighsDomain* domain,
360
+ HighsCutPool& cutpool_)
361
+ : cutpoolindex(cutpoolindex), domain(domain), cutpool(&cutpool_) {
362
+ cutpool->addPropagationDomain(this);
363
+ }
364
+
365
+ HighsDomain::CutpoolPropagation::CutpoolPropagation(
366
+ const CutpoolPropagation& other)
367
+ : cutpoolindex(other.cutpoolindex),
368
+ domain(other.domain),
369
+ cutpool(other.cutpool),
370
+ activitycuts_(other.activitycuts_),
371
+ activitycutsinf_(other.activitycutsinf_),
372
+ propagatecutflags_(other.propagatecutflags_),
373
+ propagatecutinds_(other.propagatecutinds_),
374
+ capacityThreshold_(other.capacityThreshold_) {
375
+ cutpool->addPropagationDomain(this);
376
+ }
377
+
378
+ HighsDomain::CutpoolPropagation::~CutpoolPropagation() {
379
+ cutpool->removePropagationDomain(this);
380
+ }
381
+
382
+ void HighsDomain::CutpoolPropagation::recomputeCapacityThreshold(HighsInt cut) {
383
+ HighsInt start = cutpool->getMatrix().getRowStart(cut);
384
+ HighsInt end = cutpool->getMatrix().getRowEnd(cut);
385
+ const HighsInt* arindex = cutpool->getMatrix().getARindex();
386
+ const double* arvalue = cutpool->getMatrix().getARvalue();
387
+ capacityThreshold_[cut] = -domain->feastol();
388
+ for (HighsInt i = start; i < end; ++i) {
389
+ if (domain->col_upper_[arindex[i]] == domain->col_lower_[arindex[i]])
390
+ continue;
391
+
392
+ double threshold =
393
+ std::fabs(arvalue[i]) * boundRange(domain->col_upper_[arindex[i]],
394
+ domain->col_lower_[arindex[i]],
395
+ domain->feastol(),
396
+ domain->variableType(arindex[i]));
397
+
398
+ capacityThreshold_[cut] =
399
+ std::max({capacityThreshold_[cut], threshold, domain->feastol()});
400
+ }
401
+ }
402
+
403
+ void HighsDomain::CutpoolPropagation::cutAdded(HighsInt cut, bool propagate) {
404
+ if (!propagate) {
405
+ if (domain != &domain->mipsolver->mipdata_->domain) return;
406
+ HighsInt start = cutpool->getMatrix().getRowStart(cut);
407
+ HighsInt end = cutpool->getMatrix().getRowEnd(cut);
408
+ const HighsInt* arindex = cutpool->getMatrix().getARindex();
409
+ const double* arvalue = cutpool->getMatrix().getARvalue();
410
+
411
+ if (HighsInt(activitycuts_.size()) <= cut) {
412
+ activitycuts_.resize(cut + 1);
413
+ activitycutsinf_.resize(cut + 1);
414
+ propagatecutflags_.resize(cut + 1, 2);
415
+ capacityThreshold_.resize(cut + 1);
416
+ }
417
+
418
+ propagatecutflags_[cut] &= ~uint8_t{2};
419
+ domain->computeMinActivity(start, end, arindex, arvalue,
420
+ activitycutsinf_[cut], activitycuts_[cut]);
421
+ } else {
422
+ HighsInt start = cutpool->getMatrix().getRowStart(cut);
423
+ HighsInt end = cutpool->getMatrix().getRowEnd(cut);
424
+ const HighsInt* arindex = cutpool->getMatrix().getARindex();
425
+ const double* arvalue = cutpool->getMatrix().getARvalue();
426
+
427
+ if (HighsInt(activitycuts_.size()) <= cut) {
428
+ activitycuts_.resize(cut + 1);
429
+ activitycutsinf_.resize(cut + 1);
430
+ propagatecutflags_.resize(cut + 1, 2);
431
+ capacityThreshold_.resize(cut + 1);
432
+ }
433
+
434
+ propagatecutflags_[cut] &= ~uint8_t{2};
435
+ domain->computeMinActivity(start, end, arindex, arvalue,
436
+ activitycutsinf_[cut], activitycuts_[cut]);
437
+
438
+ recomputeCapacityThreshold(cut);
439
+ markPropagateCut(cut);
440
+ }
441
+ }
442
+
443
+ void HighsDomain::CutpoolPropagation::cutDeleted(
444
+ HighsInt cut, bool deletedOnlyForPropagation) {
445
+ if (deletedOnlyForPropagation &&
446
+ domain == &domain->mipsolver->mipdata_->domain) {
447
+ assert(domain->branchPos_.empty());
448
+ return;
449
+ }
450
+
451
+ if (cut < (HighsInt)propagatecutflags_.size()) propagatecutflags_[cut] |= 2;
452
+ }
453
+
454
+ void HighsDomain::CutpoolPropagation::markPropagateCut(HighsInt cut) {
455
+ if (!propagatecutflags_[cut] &&
456
+ (activitycutsinf_[cut] == 1 ||
457
+ (cutpool->getRhs()[cut] - double(activitycuts_[cut]) <=
458
+ capacityThreshold_[cut]))) {
459
+ propagatecutinds_.push_back(cut);
460
+ propagatecutflags_[cut] |= 1;
461
+ }
462
+ }
463
+
464
+ void HighsDomain::CutpoolPropagation::updateActivityLbChange(HighsInt col,
465
+ double oldbound,
466
+ double newbound) {
467
+ assert(!domain->infeasible_);
468
+
469
+ if (newbound < oldbound) {
470
+ cutpool->getMatrix().forEachNegativeColumnEntry(
471
+ col, [&](HighsInt row, double val) {
472
+ domain->updateThresholdLbChange(col, newbound, val,
473
+ capacityThreshold_[row]);
474
+ return true;
475
+ });
476
+ }
477
+
478
+ cutpool->getMatrix().forEachPositiveColumnEntry(
479
+ col, [&](HighsInt row, double val) {
480
+ assert(val > 0);
481
+ HighsCDouble deltamin = computeDelta(val, oldbound, newbound,
482
+ -kHighsInf, activitycutsinf_[row]);
483
+ activitycuts_[row] += deltamin;
484
+
485
+ if (deltamin <= 0) {
486
+ domain->updateThresholdLbChange(col, newbound, val,
487
+ capacityThreshold_[row]);
488
+ return true;
489
+ }
490
+
491
+ if (activitycutsinf_[row] == 0 &&
492
+ activitycuts_[row] - cutpool->getRhs()[row] >
493
+ domain->mipsolver->mipdata_->feastol) {
494
+ // todo, now that multiple cutpools are possible the index needs to be
495
+ // encoded differently
496
+ domain->mipsolver->mipdata_->debugSolution.nodePruned(*domain);
497
+ domain->infeasible_ = true;
498
+ domain->infeasible_pos = domain->domchgstack_.size();
499
+ domain->infeasible_reason = Reason::cut(cutpoolindex, row);
500
+ return false;
501
+ }
502
+
503
+ markPropagateCut(row);
504
+
505
+ return true;
506
+ });
507
+
508
+ if (domain->infeasible_) {
509
+ assert(domain->infeasible_reason.type == cutpoolindex);
510
+ assert(domain->infeasible_reason.index >= 0);
511
+ std::swap(oldbound, newbound);
512
+ cutpool->getMatrix().forEachPositiveColumnEntry(
513
+ col, [&](HighsInt row, double val) {
514
+ assert(val > 0);
515
+ activitycuts_[row] += computeDelta(val, oldbound, newbound,
516
+ -kHighsInf, activitycutsinf_[row]);
517
+
518
+ if (domain->infeasible_reason.index == row) return false;
519
+
520
+ return true;
521
+ });
522
+ }
523
+ }
524
+
525
+ void HighsDomain::CutpoolPropagation::updateActivityUbChange(HighsInt col,
526
+ double oldbound,
527
+ double newbound) {
528
+ assert(!domain->infeasible_);
529
+
530
+ if (newbound > oldbound) {
531
+ cutpool->getMatrix().forEachPositiveColumnEntry(
532
+ col, [&](HighsInt row, double val) {
533
+ domain->updateThresholdUbChange(col, newbound, val,
534
+ capacityThreshold_[row]);
535
+ return true;
536
+ });
537
+ }
538
+
539
+ cutpool->getMatrix().forEachNegativeColumnEntry(
540
+ col, [&](HighsInt row, double val) {
541
+ assert(val < 0);
542
+ HighsCDouble deltamin = computeDelta(val, oldbound, newbound, kHighsInf,
543
+ activitycutsinf_[row]);
544
+ activitycuts_[row] += deltamin;
545
+
546
+ if (deltamin <= 0) {
547
+ domain->updateThresholdUbChange(col, newbound, val,
548
+ capacityThreshold_[row]);
549
+ return true;
550
+ }
551
+
552
+ if (activitycutsinf_[row] == 0 &&
553
+ activitycuts_[row] - cutpool->getRhs()[row] >
554
+ domain->mipsolver->mipdata_->feastol) {
555
+ domain->mipsolver->mipdata_->debugSolution.nodePruned(*domain);
556
+ domain->infeasible_ = true;
557
+ domain->infeasible_pos = domain->domchgstack_.size();
558
+ domain->infeasible_reason = Reason::cut(cutpoolindex, row);
559
+ return false;
560
+ }
561
+
562
+ markPropagateCut(row);
563
+
564
+ return true;
565
+ });
566
+
567
+ if (domain->infeasible_) {
568
+ assert(domain->infeasible_reason.type == cutpoolindex);
569
+ assert(domain->infeasible_reason.index >= 0);
570
+ std::swap(oldbound, newbound);
571
+ cutpool->getMatrix().forEachNegativeColumnEntry(
572
+ col, [&](HighsInt row, double val) {
573
+ assert(val < 0);
574
+ activitycuts_[row] += computeDelta(val, oldbound, newbound, kHighsInf,
575
+ activitycutsinf_[row]);
576
+
577
+ if (domain->infeasible_reason.index == row) return false;
578
+
579
+ return true;
580
+ });
581
+ }
582
+ }
583
+
584
+ namespace highs {
585
+ template <>
586
+ struct RbTreeTraits<
587
+ HighsDomain::ObjectivePropagation::ObjectiveContributionTree> {
588
+ using KeyType = std::pair<double, HighsInt>;
589
+ using LinkType = HighsInt;
590
+ };
591
+ } // namespace highs
592
+
593
+ class HighsDomain::ObjectivePropagation::ObjectiveContributionTree
594
+ : public highs::CacheMinRbTree<ObjectiveContributionTree> {
595
+ std::vector<ObjectiveContribution>& nodes;
596
+
597
+ public:
598
+ ObjectiveContributionTree(ObjectivePropagation* objProp, HighsInt partition)
599
+ : highs::CacheMinRbTree<ObjectiveContributionTree>(
600
+ objProp->contributionPartitionSets[partition].first,
601
+ objProp->contributionPartitionSets[partition].second),
602
+ nodes(objProp->objectiveLowerContributions) {}
603
+
604
+ highs::RbTreeLinks<HighsInt>& getRbTreeLinks(HighsInt node) {
605
+ return nodes[node].links;
606
+ }
607
+
608
+ const highs::RbTreeLinks<HighsInt>& getRbTreeLinks(HighsInt node) const {
609
+ return nodes[node].links;
610
+ }
611
+
612
+ std::pair<double, HighsInt> getKey(HighsInt node) const {
613
+ return std::make_pair(-nodes[node].contribution, nodes[node].col);
614
+ }
615
+ };
616
+
617
+ HighsDomain::ObjectivePropagation::ObjectivePropagation(HighsDomain* domain)
618
+ : domain(domain),
619
+ objFunc(&domain->mipsolver->mipdata_->objectiveFunction),
620
+ cost(domain->mipsolver->model_->col_cost_.data()) {
621
+ const auto& objNonzeros = objFunc->getObjectiveNonzeros();
622
+ const auto& partitionStarts = objFunc->getCliquePartitionStarts();
623
+
624
+ HighsInt numPartitions = objFunc->getNumCliquePartitions();
625
+
626
+ if (numPartitions != 0) {
627
+ propagationConsBuffer = objFunc->getObjectiveValuesPacked();
628
+ partitionCliqueData.resize(objFunc->getNumCliquePartitions());
629
+ }
630
+
631
+ isPropagated = false;
632
+ capacityThreshold = kHighsInf;
633
+ objectiveLower = 0.0;
634
+ numInfObjLower = 0;
635
+ objectiveLowerContributions.resize(partitionStarts[numPartitions]);
636
+ contributionPartitionSets.resize(numPartitions,
637
+ std::make_pair(HighsInt{-1}, HighsInt{-1}));
638
+
639
+ // for each clique partition first set up all columns as contributing with
640
+ // their largest possible value and then remove the largest contribution of
641
+ // each clique partition. For these columns we do not need to check for finite
642
+ // bounds as they must be binary. We do not assume, however, that they must be
643
+ // unfixed but could be fixed to 0 or 1. We maintain a heap that fulfills the
644
+ // invariant that the largest column may be not fixed to its value with the
645
+ // larger contribution.
646
+ for (HighsInt i = 0; i < numPartitions; ++i) {
647
+ ObjectiveContributionTree contributionTree(this, i);
648
+ partitionCliqueData[i].rhs = 1;
649
+ for (HighsInt j = partitionStarts[i]; j < partitionStarts[i + 1]; ++j) {
650
+ HighsInt col = objNonzeros[j];
651
+ objectiveLowerContributions[j].col = col;
652
+ objectiveLowerContributions[j].partition = i;
653
+ if (cost[col] > 0.0) {
654
+ objectiveLower += cost[col];
655
+ objectiveLowerContributions[j].contribution = cost[col];
656
+ partitionCliqueData[i].rhs -= 1;
657
+ if (domain->col_lower_[col] == 0.0) contributionTree.link(j);
658
+ } else {
659
+ objectiveLowerContributions[j].contribution = -cost[col];
660
+ if (domain->col_upper_[col] == 1.0) contributionTree.link(j);
661
+ }
662
+ }
663
+
664
+ HighsInt worstPos = contributionTree.first();
665
+ if (worstPos != -1)
666
+ objectiveLower -= objectiveLowerContributions[worstPos].contribution;
667
+ }
668
+
669
+ // add contribution of remaining objective nonzeros
670
+ const HighsInt numObjNz = objNonzeros.size();
671
+ for (HighsInt i = partitionStarts[numPartitions]; i < numObjNz; ++i) {
672
+ HighsInt col = objNonzeros[i];
673
+ if (cost[col] > 0.0) {
674
+ if (domain->col_lower_[col] == -kHighsInf)
675
+ ++numInfObjLower;
676
+ else
677
+ objectiveLower += domain->col_lower_[col] * cost[col];
678
+ } else {
679
+ if (domain->col_upper_[col] == kHighsInf)
680
+ ++numInfObjLower;
681
+ else
682
+ objectiveLower += domain->col_upper_[col] * cost[col];
683
+ }
684
+ }
685
+
686
+ recomputeCapacityThreshold();
687
+ debugCheckObjectiveLower();
688
+ }
689
+
690
+ void HighsDomain::ObjectivePropagation::getPropagationConstraint(
691
+ HighsInt domchgStackSize, const double*& vals, const HighsInt*& inds,
692
+ HighsInt& len, double& rhs, HighsInt domchgCol) {
693
+ const HighsInt numPartitions = objFunc->getNumCliquePartitions();
694
+ inds = objFunc->getObjectiveNonzeros().data();
695
+ len = objFunc->getObjectiveNonzeros().size();
696
+ if (numPartitions == 0) {
697
+ vals = objFunc->getObjectiveValuesPacked().data();
698
+ rhs = domain->mipsolver->mipdata_->upper_limit;
699
+ return;
700
+ }
701
+ const auto& partitionStarts = objFunc->getCliquePartitionStarts();
702
+
703
+ HighsCDouble tmpRhs = domain->mipsolver->mipdata_->upper_limit;
704
+ for (HighsInt i = 0; i < numPartitions; ++i) {
705
+ HighsInt start = partitionStarts[i];
706
+ HighsInt end = partitionStarts[i + 1];
707
+ double largest = 0.0;
708
+ for (HighsInt j = start; j < end; ++j) {
709
+ HighsInt c = inds[j];
710
+ HighsInt pos;
711
+ // skip the column we might want to explain a bound change for and take
712
+ // the second largest column instead.
713
+ if (c == domchgCol) continue;
714
+ if (cost[c] > 0) {
715
+ double lb = domain->getColLowerPos(c, domchgStackSize, pos);
716
+ if (lb < 1) largest = std::max(largest, cost[c]);
717
+ } else {
718
+ double ub = domain->getColUpperPos(c, domchgStackSize, pos);
719
+ if (ub > 0) largest = std::max(largest, -cost[c]);
720
+ }
721
+ }
722
+
723
+ tmpRhs += largest * partitionCliqueData[i].rhs;
724
+ if (partitionCliqueData[i].multiplier != largest) {
725
+ partitionCliqueData[i].multiplier = largest;
726
+ const auto& packedObjVals = objFunc->getObjectiveValuesPacked();
727
+ for (HighsInt j = start; j < end; ++j)
728
+ propagationConsBuffer[j] =
729
+ packedObjVals[j] - std::copysign(largest, packedObjVals[j]);
730
+ }
731
+ }
732
+
733
+ vals = propagationConsBuffer.data();
734
+ rhs = double(tmpRhs);
735
+ }
736
+
737
+ void HighsDomain::ObjectivePropagation::recomputeCapacityThreshold() {
738
+ const auto& partitionStarts = objFunc->getCliquePartitionStarts();
739
+ HighsInt numPartitions = objFunc->getNumCliquePartitions();
740
+
741
+ capacityThreshold = -domain->feastol();
742
+ for (HighsInt i = 0; i < numPartitions; ++i) {
743
+ ObjectiveContributionTree contributionTree(this, i);
744
+ HighsInt worstPos = contributionTree.first();
745
+ if (worstPos == -1) continue;
746
+ if (domain->isFixed(objectiveLowerContributions[worstPos].col)) continue;
747
+
748
+ double contribution = objectiveLowerContributions[worstPos].contribution;
749
+ HighsInt bestPos = contributionTree.last();
750
+ if (bestPos != worstPos)
751
+ contribution -= objectiveLowerContributions[bestPos].contribution;
752
+
753
+ capacityThreshold =
754
+ std::max(capacityThreshold, contribution * (1.0 - domain->feastol()));
755
+ }
756
+
757
+ const auto& objNonzeros = objFunc->getObjectiveNonzeros();
758
+ const HighsInt numObjNzs = objNonzeros.size();
759
+ for (HighsInt i = partitionStarts[numPartitions]; i < numObjNzs; ++i) {
760
+ HighsInt col = objNonzeros[i];
761
+
762
+ capacityThreshold = std::max(
763
+ capacityThreshold,
764
+ std::fabs(cost[col]) *
765
+ boundRange(domain->col_upper_[col], domain->col_lower_[col],
766
+ domain->feastol(), domain->variableType(col)));
767
+ }
768
+ }
769
+
770
+ void HighsDomain::ObjectivePropagation::updateActivityLbChange(
771
+ HighsInt col, double oldbound, double newbound) {
772
+ if (cost[col] <= 0.0) {
773
+ if (cost[col] != 0.0 && newbound < oldbound) {
774
+ capacityThreshold =
775
+ std::max(capacityThreshold,
776
+ -cost[col] * boundRange(domain->col_upper_[col], newbound,
777
+ domain->feastol(),
778
+ domain->variableType(col)));
779
+ isPropagated = false;
780
+ }
781
+ debugCheckObjectiveLower();
782
+ return;
783
+ }
784
+
785
+ isPropagated = false;
786
+
787
+ HighsInt partitionPos = objFunc->getColCliquePartition(col);
788
+ if (partitionPos == -1) {
789
+ if (oldbound == -kHighsInf)
790
+ --numInfObjLower;
791
+ else
792
+ objectiveLower -= oldbound * cost[col];
793
+
794
+ if (newbound == -kHighsInf)
795
+ ++numInfObjLower;
796
+ else
797
+ objectiveLower += newbound * cost[col];
798
+
799
+ debugCheckObjectiveLower();
800
+
801
+ if (newbound < oldbound) {
802
+ capacityThreshold = std::max(
803
+ capacityThreshold,
804
+ cost[col] * boundRange(domain->col_upper_[col],
805
+ domain->col_lower_[col], domain->feastol(),
806
+ domain->variableType(col)));
807
+ } else if (numInfObjLower == 0 &&
808
+ objectiveLower > domain->mipsolver->mipdata_->upper_limit) {
809
+ domain->infeasible_ = true;
810
+ domain->infeasible_pos = domain->domchgstack_.size();
811
+ domain->infeasible_reason = Reason::objective();
812
+ updateActivityLbChange(col, newbound, oldbound);
813
+ }
814
+ } else {
815
+ if (newbound == 0.0) {
816
+ assert(oldbound == 1.0);
817
+ // binary lower bound of variable in clique partition is relaxed to 0
818
+ HighsInt partition = objectiveLowerContributions[partitionPos].partition;
819
+ ObjectiveContributionTree contributionTree(this, partition);
820
+ HighsInt currFirst = contributionTree.first();
821
+
822
+ contributionTree.link(partitionPos);
823
+
824
+ double oldContribution = 0.0;
825
+ if (currFirst != -1)
826
+ oldContribution = objectiveLowerContributions[currFirst].contribution;
827
+
828
+ if (partitionPos == contributionTree.first() &&
829
+ objectiveLowerContributions[partitionPos].contribution !=
830
+ oldContribution) {
831
+ objectiveLower += oldContribution;
832
+ objectiveLower -=
833
+ objectiveLowerContributions[partitionPos].contribution;
834
+
835
+ // update the capacity threshold with the difference of the new highest
836
+ // contribution position to the lowest contribution as the column with
837
+ // the lowest contribution can be fixed to its bound that yields the
838
+ // highest objective value.
839
+ HighsInt bestPos = contributionTree.last();
840
+ double delta = objectiveLowerContributions[partitionPos].contribution;
841
+ if (bestPos != partitionPos)
842
+ delta -= objectiveLowerContributions[bestPos].contribution;
843
+ capacityThreshold =
844
+ std::max(delta * (1.0 - domain->feastol()), capacityThreshold);
845
+ } else {
846
+ // the new linked column could be the one with the new lowest
847
+ // contribution so update the capacity threshold to ensure propagation
848
+ // runs when it can be fixed to the bound that yields the highest
849
+ // objective value
850
+ capacityThreshold =
851
+ std::max((oldContribution -
852
+ objectiveLowerContributions[partitionPos].contribution) *
853
+ (1.0 - domain->feastol()),
854
+ capacityThreshold);
855
+ }
856
+
857
+ debugCheckObjectiveLower();
858
+ } else {
859
+ // binary lower bound of variable in clique partition is tightened to 1
860
+ assert(oldbound == 0.0);
861
+ assert(newbound == 1.0);
862
+
863
+ HighsInt partition = objectiveLowerContributions[partitionPos].partition;
864
+ ObjectiveContributionTree contributionTree(this, partition);
865
+ bool wasFirst = contributionTree.first() == partitionPos;
866
+ if (wasFirst)
867
+ objectiveLower +=
868
+ objectiveLowerContributions[partitionPos].contribution;
869
+
870
+ contributionTree.unlink(partitionPos);
871
+
872
+ if (wasFirst) {
873
+ HighsInt newWorst = contributionTree.first();
874
+ if (newWorst != -1)
875
+ objectiveLower -= objectiveLowerContributions[newWorst].contribution;
876
+ }
877
+
878
+ debugCheckObjectiveLower();
879
+
880
+ if (numInfObjLower == 0 &&
881
+ objectiveLower > domain->mipsolver->mipdata_->upper_limit) {
882
+ domain->infeasible_ = true;
883
+ domain->infeasible_pos = domain->domchgstack_.size();
884
+ domain->infeasible_reason = Reason::objective();
885
+ updateActivityLbChange(col, newbound, oldbound);
886
+ }
887
+ }
888
+ }
889
+ }
890
+
891
+ void HighsDomain::ObjectivePropagation::updateActivityUbChange(
892
+ HighsInt col, double oldbound, double newbound) {
893
+ if (cost[col] >= 0.0) {
894
+ if (cost[col] != 0.0 && newbound > oldbound) {
895
+ capacityThreshold = std::max(
896
+ capacityThreshold,
897
+ cost[col] * boundRange(newbound, domain->col_lower_[col],
898
+ domain->feastol(), domain->variableType(col)));
899
+ isPropagated = false;
900
+ }
901
+ debugCheckObjectiveLower();
902
+ return;
903
+ }
904
+
905
+ isPropagated = false;
906
+
907
+ HighsInt partitionPos = objFunc->getColCliquePartition(col);
908
+ if (partitionPos == -1) {
909
+ if (oldbound == kHighsInf)
910
+ --numInfObjLower;
911
+ else
912
+ objectiveLower -= oldbound * cost[col];
913
+
914
+ if (newbound == kHighsInf)
915
+ ++numInfObjLower;
916
+ else
917
+ objectiveLower += newbound * cost[col];
918
+
919
+ debugCheckObjectiveLower();
920
+
921
+ if (newbound > oldbound) {
922
+ capacityThreshold = std::max(
923
+ capacityThreshold,
924
+ -cost[col] * boundRange(domain->col_upper_[col],
925
+ domain->col_lower_[col], domain->feastol(),
926
+ domain->variableType(col)));
927
+ } else if (numInfObjLower == 0 &&
928
+ objectiveLower > domain->mipsolver->mipdata_->upper_limit) {
929
+ domain->infeasible_ = true;
930
+ domain->infeasible_pos = domain->domchgstack_.size();
931
+ domain->infeasible_reason = Reason::objective();
932
+ updateActivityUbChange(col, newbound, oldbound);
933
+ }
934
+ } else {
935
+ if (newbound == 1.0) {
936
+ assert(oldbound == 0.0);
937
+ // binary upper bound of variable in clique partition is relaxed to 1
938
+ HighsInt partition = objectiveLowerContributions[partitionPos].partition;
939
+ ObjectiveContributionTree contributionTree(this, partition);
940
+ HighsInt currFirst = contributionTree.first();
941
+
942
+ contributionTree.link(partitionPos);
943
+
944
+ double oldContribution = 0.0;
945
+ if (currFirst != -1)
946
+ oldContribution = objectiveLowerContributions[currFirst].contribution;
947
+
948
+ if (partitionPos == contributionTree.first() &&
949
+ objectiveLowerContributions[partitionPos].contribution !=
950
+ oldContribution) {
951
+ objectiveLower += oldContribution;
952
+ objectiveLower -=
953
+ objectiveLowerContributions[partitionPos].contribution;
954
+
955
+ // update the capacity threshold with the difference of the new highest
956
+ // contribution position to the lowest contribution as the column with
957
+ // the lowest contribution can be fixed to its bound that yields the
958
+ // highest objective value.
959
+ HighsInt bestPos = contributionTree.last();
960
+ double delta = objectiveLowerContributions[partitionPos].contribution;
961
+ if (bestPos != partitionPos)
962
+ delta -= objectiveLowerContributions[bestPos].contribution;
963
+ capacityThreshold =
964
+ std::max(delta * (1.0 - domain->feastol()), capacityThreshold);
965
+ } else {
966
+ // the new linked column could be the one with the new lowest
967
+ // contribution so update the capacity threshold to ensure propagation
968
+ // runs when it can be fixed to the bound that yields the highest
969
+ // objective value
970
+ capacityThreshold =
971
+ std::max((oldContribution -
972
+ objectiveLowerContributions[partitionPos].contribution) *
973
+ (1.0 - domain->feastol()),
974
+ capacityThreshold);
975
+ }
976
+
977
+ debugCheckObjectiveLower();
978
+ } else {
979
+ // binary upper bound of variable in clique partition is tightened to 0
980
+ assert(oldbound == 1.0);
981
+ assert(newbound == 0.0);
982
+ HighsInt partition = objectiveLowerContributions[partitionPos].partition;
983
+ ObjectiveContributionTree contributionTree(this, partition);
984
+ bool wasFirst = contributionTree.first() == partitionPos;
985
+ if (wasFirst)
986
+ objectiveLower +=
987
+ objectiveLowerContributions[partitionPos].contribution;
988
+
989
+ contributionTree.unlink(partitionPos);
990
+
991
+ if (wasFirst) {
992
+ HighsInt newWorst = contributionTree.first();
993
+ if (newWorst != -1)
994
+ objectiveLower -= objectiveLowerContributions[newWorst].contribution;
995
+ }
996
+
997
+ debugCheckObjectiveLower();
998
+
999
+ if (numInfObjLower == 0 &&
1000
+ objectiveLower > domain->mipsolver->mipdata_->upper_limit) {
1001
+ domain->infeasible_ = true;
1002
+ domain->infeasible_pos = domain->domchgstack_.size();
1003
+ domain->infeasible_reason = Reason::objective();
1004
+ updateActivityUbChange(col, newbound, oldbound);
1005
+ }
1006
+ }
1007
+ }
1008
+ }
1009
+
1010
+ bool HighsDomain::ObjectivePropagation::shouldBePropagated() const {
1011
+ if (isPropagated) return false;
1012
+ if (numInfObjLower > 1) return false;
1013
+ if (domain->infeasible_) return false;
1014
+ double upperLimit = domain->mipsolver->mipdata_->upper_limit;
1015
+ if (upperLimit == kHighsInf) return false;
1016
+ if (upperLimit - double(objectiveLower) > capacityThreshold) return false;
1017
+
1018
+ return true;
1019
+ }
1020
+
1021
+ void HighsDomain::ObjectivePropagation::debugCheckObjectiveLower() const {
1022
+ #ifndef NDEBUG
1023
+ if (domain->infeasible_) return;
1024
+ HighsCDouble lowerFromScratch = 0.0;
1025
+ HighsInt numInf = 0;
1026
+ const HighsInt numPartitions = objFunc->getNumCliquePartitions();
1027
+ const auto& partitionStarts = objFunc->getCliquePartitionStarts();
1028
+ const auto& objNonzeros = objFunc->getObjectiveNonzeros();
1029
+
1030
+ const HighsInt numObjNzs = objNonzeros.size();
1031
+ for (HighsInt i = 0; i < numPartitions; ++i) {
1032
+ HighsInt start = partitionStarts[i];
1033
+ HighsInt end = partitionStarts[i + 1];
1034
+ double largest = 0.0;
1035
+ for (HighsInt j = start; j < end; ++j) {
1036
+ HighsInt c = objNonzeros[j];
1037
+ if (cost[c] > 0) {
1038
+ lowerFromScratch += cost[c];
1039
+
1040
+ if (domain->col_lower_[c] < 1) largest = std::max(largest, cost[c]);
1041
+ } else {
1042
+ if (domain->col_upper_[c] > 0) largest = std::max(largest, -cost[c]);
1043
+ }
1044
+ }
1045
+ lowerFromScratch -= largest;
1046
+ }
1047
+
1048
+ for (HighsInt i = partitionStarts[numPartitions]; i < numObjNzs; ++i) {
1049
+ HighsInt col = objNonzeros[i];
1050
+ if (cost[col] > 0) {
1051
+ if (domain->col_lower_[col] > -kHighsInf)
1052
+ lowerFromScratch += domain->col_lower_[col] * cost[col];
1053
+ else
1054
+ ++numInf;
1055
+ } else {
1056
+ if (domain->col_upper_[col] < kHighsInf)
1057
+ lowerFromScratch += domain->col_upper_[col] * cost[col];
1058
+ else
1059
+ ++numInf;
1060
+ }
1061
+ }
1062
+ assert(std::fabs(double(lowerFromScratch - objectiveLower)) <=
1063
+ domain->feastol());
1064
+ assert(numInf == numInfObjLower);
1065
+ #endif
1066
+ }
1067
+
1068
+ void HighsDomain::ObjectivePropagation::propagate() {
1069
+ if (!shouldBePropagated()) return;
1070
+
1071
+ debugCheckObjectiveLower();
1072
+
1073
+ const double upperLimit = domain->mipsolver->mipdata_->upper_limit;
1074
+ if (numInfObjLower == 0 && objectiveLower > upperLimit) {
1075
+ domain->infeasible_ = true;
1076
+ domain->infeasible_pos = domain->domchgstack_.size();
1077
+ domain->infeasible_reason = Reason::objective();
1078
+ return;
1079
+ }
1080
+
1081
+ const auto& objNonzeros = objFunc->getObjectiveNonzeros();
1082
+
1083
+ HighsCDouble capacity = upperLimit - objectiveLower;
1084
+ if (numInfObjLower == 1) {
1085
+ // Scan non-binary columns for infinite bound contribution until the one
1086
+ // column that contributes with an infinite bound is found which is the only
1087
+ // column that can be propagated
1088
+ HighsInt numCol = objNonzeros.size();
1089
+ for (HighsInt i = objFunc->getNumBinariesInObjective(); i < numCol; ++i) {
1090
+ HighsInt col = objNonzeros[i];
1091
+ if ((cost[col] > 0 && domain->col_lower_[col] != -kHighsInf) ||
1092
+ (cost[col] < 0 && domain->col_upper_[col] != kHighsInf))
1093
+ continue;
1094
+ domain->checkChangeBound(
1095
+ cost[col] > 0 ? HighsBoundType::kUpper : HighsBoundType::kLower, col,
1096
+ capacity / cost[col], Reason::objective());
1097
+ break;
1098
+ }
1099
+ } else {
1100
+ HighsInt numPartitions = objFunc->getNumCliquePartitions();
1101
+ while (true) {
1102
+ HighsInt numBoundChanges = 0;
1103
+ for (HighsInt i = 0; i < numPartitions; ++i) {
1104
+ ObjectiveContributionTree contributionTree(this, i);
1105
+ HighsInt worst = contributionTree.first();
1106
+ if (worst == -1) continue;
1107
+
1108
+ double contribution = objectiveLowerContributions[worst].contribution;
1109
+
1110
+ HighsInt secondWorst = contributionTree.successor(worst);
1111
+ if (secondWorst != -1)
1112
+ contribution -= objectiveLowerContributions[secondWorst].contribution;
1113
+
1114
+ // the upper limit already uses a tolerance, so we can do a hard cutoff
1115
+ if (contribution > capacity) {
1116
+ HighsInt col = objectiveLowerContributions[worst].col;
1117
+ if (cost[col] > 0) {
1118
+ if (domain->col_upper_[col] > 0.0) {
1119
+ numBoundChanges++;
1120
+ domain->changeBound(HighsBoundType::kUpper, col, 0.0,
1121
+ Reason::objective());
1122
+ if (domain->infeasible_) break;
1123
+ }
1124
+ } else {
1125
+ if (domain->col_lower_[col] < 1.0) {
1126
+ numBoundChanges++;
1127
+ domain->changeBound(HighsBoundType::kLower, col, 1.0,
1128
+ Reason::objective());
1129
+ if (domain->infeasible_) break;
1130
+ }
1131
+ }
1132
+ } else if (secondWorst != -1) {
1133
+ // it might be that we can the column with the lowest possible
1134
+ // contribution to its bound value that yields the highest objective
1135
+ // contribution.
1136
+ HighsInt best = contributionTree.last();
1137
+ while (best != contributionTree.first()) {
1138
+ // difference to the column with the highest contribution is the
1139
+ // objective increase when fixing the column to its bound with the
1140
+ // lowest objective contribution. Due to the clique information that
1141
+ // means the current column with the highest contribution will
1142
+ // contribute with its worst bound.
1143
+ if (objectiveLowerContributions[contributionTree.first()]
1144
+ .contribution -
1145
+ objectiveLowerContributions[best].contribution >
1146
+ capacity) {
1147
+ HighsInt col = objectiveLowerContributions[best].col;
1148
+ if (cost[col] > 0) {
1149
+ assert(domain->col_lower_[col] < 1.0);
1150
+ numBoundChanges++;
1151
+ domain->changeBound(HighsBoundType::kLower, col, 1.0,
1152
+ Reason::objective());
1153
+ if (domain->infeasible_) break;
1154
+ } else {
1155
+ assert(domain->col_upper_[col] > 0.0);
1156
+ numBoundChanges++;
1157
+ domain->changeBound(HighsBoundType::kUpper, col, 0.0,
1158
+ Reason::objective());
1159
+ if (domain->infeasible_) break;
1160
+ }
1161
+ } else
1162
+ break;
1163
+
1164
+ best = contributionTree.last();
1165
+ }
1166
+
1167
+ if (domain->infeasible_) break;
1168
+ }
1169
+ }
1170
+
1171
+ if (domain->infeasible_) break;
1172
+
1173
+ const HighsInt numObjNzs = objNonzeros.size();
1174
+ for (HighsInt i = objFunc->getCliquePartitionStarts()[numPartitions];
1175
+ i < numObjNzs; ++i) {
1176
+ HighsInt col = objNonzeros[i];
1177
+
1178
+ if (cost[col] > 0) {
1179
+ if (domain->checkChangeBound(
1180
+ HighsBoundType::kUpper, col,
1181
+ (capacity + domain->col_lower_[col] * cost[col]) / cost[col],
1182
+ Reason::objective()))
1183
+ numBoundChanges++;
1184
+ } else {
1185
+ if (domain->checkChangeBound(
1186
+ HighsBoundType::kLower, col,
1187
+ (capacity + domain->col_upper_[col] * cost[col]) / cost[col],
1188
+ Reason::objective()))
1189
+ numBoundChanges++;
1190
+ }
1191
+ if (domain->infeasible_) break;
1192
+ }
1193
+ if (domain->infeasible_) break;
1194
+
1195
+ if (numBoundChanges == 0) break;
1196
+ capacity = upperLimit - objectiveLower;
1197
+ }
1198
+ }
1199
+
1200
+ recomputeCapacityThreshold();
1201
+ isPropagated = true;
1202
+ }
1203
+
1204
+ void HighsDomain::computeMinActivity(HighsInt start, HighsInt end,
1205
+ const HighsInt* ARindex,
1206
+ const double* ARvalue, HighsInt& ninfmin,
1207
+ HighsCDouble& activitymin) const {
1208
+ if (infeasible_) {
1209
+ activitymin = 0.0;
1210
+ ninfmin = 0;
1211
+ for (HighsInt j = start; j != end; ++j) {
1212
+ HighsInt col = ARindex[j];
1213
+ double val = ARvalue[j];
1214
+
1215
+ assert(col < int(col_lower_.size()));
1216
+
1217
+ HighsInt tmp;
1218
+ double lb = getColLowerPos(col, infeasible_pos - 1, tmp);
1219
+ double ub = getColUpperPos(col, infeasible_pos - 1, tmp);
1220
+ double contributionmin = activityContributionMin(val, lb, ub);
1221
+
1222
+ if (contributionmin == -kHighsInf)
1223
+ ++ninfmin;
1224
+ else
1225
+ activitymin += contributionmin;
1226
+ }
1227
+
1228
+ } else {
1229
+ activitymin = 0.0;
1230
+ ninfmin = 0;
1231
+ for (HighsInt j = start; j != end; ++j) {
1232
+ HighsInt col = ARindex[j];
1233
+ double val = ARvalue[j];
1234
+
1235
+ assert(col < int(col_lower_.size()));
1236
+
1237
+ double contributionmin =
1238
+ activityContributionMin(val, col_lower_[col], col_upper_[col]);
1239
+
1240
+ if (contributionmin == -kHighsInf)
1241
+ ++ninfmin;
1242
+ else
1243
+ activitymin += contributionmin;
1244
+ }
1245
+ }
1246
+ activitymin.renormalize();
1247
+ }
1248
+
1249
+ void HighsDomain::computeMaxActivity(HighsInt start, HighsInt end,
1250
+ const HighsInt* ARindex,
1251
+ const double* ARvalue, HighsInt& ninfmax,
1252
+ HighsCDouble& activitymax) const {
1253
+ if (infeasible_) {
1254
+ activitymax = 0.0;
1255
+ ninfmax = 0;
1256
+ for (HighsInt j = start; j != end; ++j) {
1257
+ HighsInt col = ARindex[j];
1258
+ double val = ARvalue[j];
1259
+
1260
+ assert(col < int(col_lower_.size()));
1261
+
1262
+ HighsInt tmp;
1263
+ double lb = getColLowerPos(col, infeasible_pos - 1, tmp);
1264
+ double ub = getColUpperPos(col, infeasible_pos - 1, tmp);
1265
+ double contributionmin = activityContributionMax(val, lb, ub);
1266
+
1267
+ if (contributionmin == kHighsInf)
1268
+ ++ninfmax;
1269
+ else
1270
+ activitymax += contributionmin;
1271
+ }
1272
+ } else {
1273
+ activitymax = 0.0;
1274
+ ninfmax = 0;
1275
+ for (HighsInt j = start; j != end; ++j) {
1276
+ HighsInt col = ARindex[j];
1277
+ double val = ARvalue[j];
1278
+
1279
+ assert(col < int(col_lower_.size()));
1280
+
1281
+ double contributionmin =
1282
+ activityContributionMax(val, col_lower_[col], col_upper_[col]);
1283
+
1284
+ if (contributionmin == kHighsInf)
1285
+ ++ninfmax;
1286
+ else
1287
+ activitymax += contributionmin;
1288
+ }
1289
+ }
1290
+ activitymax.renormalize();
1291
+ }
1292
+
1293
+ double HighsDomain::adjustedUb(HighsInt col, HighsCDouble boundVal,
1294
+ bool& accept) const {
1295
+ double bound;
1296
+
1297
+ if (mipsolver->isColIntegral(col)) {
1298
+ bound = static_cast<double>(floor(boundVal + mipsolver->mipdata_->feastol));
1299
+ accept = bound < col_upper_[col] &&
1300
+ col_upper_[col] - bound >
1301
+ 1000.0 * mipsolver->mipdata_->feastol * std::fabs(bound);
1302
+ } else {
1303
+ if (std::fabs(double(boundVal) - col_lower_[col]) <=
1304
+ mipsolver->mipdata_->epsilon)
1305
+ bound = col_lower_[col];
1306
+ else
1307
+ bound = double(boundVal);
1308
+ if (col_upper_[col] == kHighsInf)
1309
+ accept = true;
1310
+ else if (bound + 1000.0 * mipsolver->mipdata_->feastol < col_upper_[col]) {
1311
+ double relativeImprove = col_upper_[col] - bound;
1312
+ if (col_lower_[col] != -kHighsInf)
1313
+ relativeImprove /= col_upper_[col] - col_lower_[col];
1314
+ else
1315
+ relativeImprove /=
1316
+ std::max(std::fabs(col_upper_[col]), std::fabs(bound));
1317
+ accept = relativeImprove >= 0.3;
1318
+ } else
1319
+ accept = false;
1320
+ }
1321
+
1322
+ return bound;
1323
+ }
1324
+
1325
+ double HighsDomain::adjustedLb(HighsInt col, HighsCDouble boundVal,
1326
+ bool& accept) const {
1327
+ double bound;
1328
+
1329
+ if (mipsolver->isColIntegral(col)) {
1330
+ bound = static_cast<double>(ceil(boundVal - mipsolver->mipdata_->feastol));
1331
+ accept = bound > col_lower_[col] &&
1332
+ bound - col_lower_[col] >
1333
+ 1000.0 * mipsolver->mipdata_->feastol * std::fabs(bound);
1334
+ } else {
1335
+ if (std::fabs(col_upper_[col] - double(boundVal)) <=
1336
+ mipsolver->mipdata_->epsilon)
1337
+ bound = col_upper_[col];
1338
+ else
1339
+ bound = double(boundVal);
1340
+ if (col_lower_[col] == -kHighsInf)
1341
+ accept = true;
1342
+ else if (bound - 1000.0 * mipsolver->mipdata_->feastol > col_lower_[col]) {
1343
+ double relativeImprove = bound - col_lower_[col];
1344
+ if (col_upper_[col] != kHighsInf)
1345
+ relativeImprove /= col_upper_[col] - col_lower_[col];
1346
+ else
1347
+ relativeImprove /=
1348
+ std::max(std::fabs(col_lower_[col]), std::fabs(bound));
1349
+ accept = relativeImprove >= 0.3;
1350
+ } else
1351
+ accept = false;
1352
+ }
1353
+
1354
+ return bound;
1355
+ }
1356
+
1357
+ HighsInt HighsDomain::propagateRowUpper(const HighsInt* Rindex,
1358
+ const double* Rvalue, HighsInt Rlen,
1359
+ double Rupper,
1360
+ const HighsCDouble& minactivity,
1361
+ HighsInt ninfmin,
1362
+ HighsDomainChange* boundchgs) const {
1363
+ assert(std::isfinite(double(minactivity)));
1364
+ if (ninfmin > 1) return 0;
1365
+ HighsInt numchgs = 0;
1366
+ for (HighsInt i = 0; i != Rlen; ++i) {
1367
+ HighsCDouble minresact;
1368
+ double actcontribution = activityContributionMin(
1369
+ Rvalue[i], col_lower_[Rindex[i]], col_upper_[Rindex[i]]);
1370
+ if (ninfmin == 1) {
1371
+ if (actcontribution != -kHighsInf) continue;
1372
+
1373
+ minresact = minactivity;
1374
+ } else {
1375
+ minresact = minactivity - actcontribution;
1376
+ }
1377
+
1378
+ HighsCDouble boundVal = (Rupper - minresact) / Rvalue[i];
1379
+ if (std::fabs(double(boundVal) * kHighsTiny) > mipsolver->mipdata_->feastol)
1380
+ continue;
1381
+
1382
+ if (Rvalue[i] > 0) {
1383
+ bool accept;
1384
+
1385
+ double bound = adjustedUb(Rindex[i], boundVal, accept);
1386
+ if (accept)
1387
+ boundchgs[numchgs++] = {bound, Rindex[i], HighsBoundType::kUpper};
1388
+
1389
+ } else {
1390
+ bool accept;
1391
+
1392
+ double bound = adjustedLb(Rindex[i], boundVal, accept);
1393
+ if (accept)
1394
+ boundchgs[numchgs++] = {bound, Rindex[i], HighsBoundType::kLower};
1395
+ }
1396
+ }
1397
+
1398
+ return numchgs;
1399
+ }
1400
+
1401
+ HighsInt HighsDomain::propagateRowLower(const HighsInt* Rindex,
1402
+ const double* Rvalue, HighsInt Rlen,
1403
+ double Rlower,
1404
+ const HighsCDouble& maxactivity,
1405
+ HighsInt ninfmax,
1406
+ HighsDomainChange* boundchgs) const {
1407
+ assert(std::isfinite(double(maxactivity)));
1408
+ if (ninfmax > 1) return 0;
1409
+ HighsInt numchgs = 0;
1410
+ for (HighsInt i = 0; i != Rlen; ++i) {
1411
+ HighsCDouble maxresact;
1412
+ double actcontribution = activityContributionMax(
1413
+ Rvalue[i], col_lower_[Rindex[i]], col_upper_[Rindex[i]]);
1414
+ if (ninfmax == 1) {
1415
+ if (actcontribution != kHighsInf) continue;
1416
+
1417
+ maxresact = maxactivity;
1418
+ } else {
1419
+ maxresact = maxactivity - actcontribution;
1420
+ }
1421
+
1422
+ HighsCDouble boundVal = (Rlower - maxresact) / Rvalue[i];
1423
+ if (std::fabs(double(boundVal) * kHighsTiny) > mipsolver->mipdata_->feastol)
1424
+ continue;
1425
+
1426
+ if (Rvalue[i] < 0) {
1427
+ bool accept;
1428
+
1429
+ double bound = adjustedUb(Rindex[i], boundVal, accept);
1430
+ if (accept)
1431
+ boundchgs[numchgs++] = {bound, Rindex[i], HighsBoundType::kUpper};
1432
+ } else {
1433
+ bool accept;
1434
+
1435
+ double bound = adjustedLb(Rindex[i], boundVal, accept);
1436
+ if (accept)
1437
+ boundchgs[numchgs++] = {bound, Rindex[i], HighsBoundType::kLower};
1438
+ }
1439
+ }
1440
+
1441
+ return numchgs;
1442
+ }
1443
+
1444
+ void HighsDomain::updateThresholdLbChange(HighsInt col, double newbound,
1445
+ double val, double& threshold) const {
1446
+ if (newbound != col_upper_[col]) {
1447
+ double thresholdNew =
1448
+ std::fabs(val) * boundRange(col_upper_[col], newbound,
1449
+ mipsolver->mipdata_->feastol,
1450
+ variableType(col));
1451
+
1452
+ // the new threshold is now the maximum of the new threshold and the current
1453
+ // one
1454
+ threshold =
1455
+ std::max({threshold, thresholdNew, mipsolver->mipdata_->feastol});
1456
+ }
1457
+ }
1458
+
1459
+ void HighsDomain::updateThresholdUbChange(HighsInt col, double newbound,
1460
+ double val, double& threshold) const {
1461
+ if (newbound != col_lower_[col]) {
1462
+ double thresholdNew =
1463
+ std::fabs(val) * boundRange(newbound, col_lower_[col],
1464
+ mipsolver->mipdata_->feastol,
1465
+ variableType(col));
1466
+
1467
+ // the new threshold is now the maximum of the new threshold and the current
1468
+ // one
1469
+ threshold =
1470
+ std::max({threshold, thresholdNew, mipsolver->mipdata_->feastol});
1471
+ }
1472
+ }
1473
+
1474
+ void HighsDomain::updateActivityLbChange(HighsInt col, double oldbound,
1475
+ double newbound) {
1476
+ auto mip = mipsolver->model_;
1477
+ HighsInt start = mip->a_matrix_.start_[col];
1478
+ HighsInt end = mip->a_matrix_.start_[col + 1];
1479
+
1480
+ assert(!infeasible_);
1481
+
1482
+ if (objProp_.isActive()) {
1483
+ objProp_.updateActivityLbChange(col, oldbound, newbound);
1484
+ if (infeasible_) return;
1485
+ }
1486
+
1487
+ for (HighsInt i = start; i != end; ++i) {
1488
+ if (mip->a_matrix_.value_[i] > 0) {
1489
+ HighsCDouble deltamin =
1490
+ computeDelta(mip->a_matrix_.value_[i], oldbound, newbound, -kHighsInf,
1491
+ activitymininf_[mip->a_matrix_.index_[i]]);
1492
+ activitymin_[mip->a_matrix_.index_[i]] += deltamin;
1493
+
1494
+ #ifndef NDEBUG
1495
+ {
1496
+ HighsInt tmpinf;
1497
+ HighsCDouble tmpminact;
1498
+ computeMinActivity(
1499
+ mipsolver->mipdata_->ARstart_[mip->a_matrix_.index_[i]],
1500
+ mipsolver->mipdata_->ARstart_[mip->a_matrix_.index_[i] + 1],
1501
+ mipsolver->mipdata_->ARindex_.data(),
1502
+ mipsolver->mipdata_->ARvalue_.data(), tmpinf, tmpminact);
1503
+ assert(std::fabs(double(activitymin_[mip->a_matrix_.index_[i]] -
1504
+ tmpminact)) <= mipsolver->mipdata_->feastol);
1505
+ assert(tmpinf == activitymininf_[mip->a_matrix_.index_[i]]);
1506
+ }
1507
+ #endif
1508
+
1509
+ if (recordRedundantRows_ &&
1510
+ mip->row_lower_[mip->a_matrix_.index_[i]] != -kHighsInf &&
1511
+ mip->row_upper_[mip->a_matrix_.index_[i]] == kHighsInf)
1512
+ updateRedundantRows(mip->a_matrix_.index_[i]);
1513
+
1514
+ if (deltamin <= 0) {
1515
+ updateThresholdLbChange(col, newbound, mip->a_matrix_.value_[i],
1516
+ capacityThreshold_[mip->a_matrix_.index_[i]]);
1517
+ continue;
1518
+ }
1519
+
1520
+ if (mip->row_upper_[mip->a_matrix_.index_[i]] != kHighsInf &&
1521
+ activitymininf_[mip->a_matrix_.index_[i]] == 0 &&
1522
+ activitymin_[mip->a_matrix_.index_[i]] -
1523
+ mip->row_upper_[mip->a_matrix_.index_[i]] >
1524
+ mipsolver->mipdata_->feastol) {
1525
+ mipsolver->mipdata_->debugSolution.nodePruned(*this);
1526
+ infeasible_ = true;
1527
+ infeasible_pos = domchgstack_.size();
1528
+ infeasible_reason = Reason::modelRowUpper(mip->a_matrix_.index_[i]);
1529
+ end = i + 1;
1530
+ break;
1531
+ }
1532
+
1533
+ if (activitymininf_[mip->a_matrix_.index_[i]] <= 1 &&
1534
+ !propagateflags_[mip->a_matrix_.index_[i]] &&
1535
+ mip->row_upper_[mip->a_matrix_.index_[i]] != kHighsInf)
1536
+ markPropagate(mip->a_matrix_.index_[i]);
1537
+ } else {
1538
+ HighsCDouble deltamax =
1539
+ computeDelta(mip->a_matrix_.value_[i], oldbound, newbound, -kHighsInf,
1540
+ activitymaxinf_[mip->a_matrix_.index_[i]]);
1541
+ activitymax_[mip->a_matrix_.index_[i]] += deltamax;
1542
+
1543
+ #ifndef NDEBUG
1544
+ {
1545
+ HighsInt tmpinf;
1546
+ HighsCDouble tmpmaxact;
1547
+ computeMaxActivity(
1548
+ mipsolver->mipdata_->ARstart_[mip->a_matrix_.index_[i]],
1549
+ mipsolver->mipdata_->ARstart_[mip->a_matrix_.index_[i] + 1],
1550
+ mipsolver->mipdata_->ARindex_.data(),
1551
+ mipsolver->mipdata_->ARvalue_.data(), tmpinf, tmpmaxact);
1552
+ assert(std::fabs(double(activitymax_[mip->a_matrix_.index_[i]] -
1553
+ tmpmaxact)) <= mipsolver->mipdata_->feastol);
1554
+ assert(tmpinf == activitymaxinf_[mip->a_matrix_.index_[i]]);
1555
+ }
1556
+ #endif
1557
+
1558
+ if (recordRedundantRows_ &&
1559
+ mip->row_lower_[mip->a_matrix_.index_[i]] == -kHighsInf &&
1560
+ mip->row_upper_[mip->a_matrix_.index_[i]] != kHighsInf)
1561
+ updateRedundantRows(mip->a_matrix_.index_[i]);
1562
+
1563
+ if (deltamax >= 0) {
1564
+ updateThresholdLbChange(col, newbound, mip->a_matrix_.value_[i],
1565
+ capacityThreshold_[mip->a_matrix_.index_[i]]);
1566
+ continue;
1567
+ }
1568
+
1569
+ if (mip->row_lower_[mip->a_matrix_.index_[i]] != -kHighsInf &&
1570
+ activitymaxinf_[mip->a_matrix_.index_[i]] == 0 &&
1571
+ mip->row_lower_[mip->a_matrix_.index_[i]] -
1572
+ activitymax_[mip->a_matrix_.index_[i]] >
1573
+ mipsolver->mipdata_->feastol) {
1574
+ mipsolver->mipdata_->debugSolution.nodePruned(*this);
1575
+ infeasible_ = true;
1576
+ infeasible_pos = domchgstack_.size();
1577
+ infeasible_reason = Reason::modelRowLower(mip->a_matrix_.index_[i]);
1578
+ end = i + 1;
1579
+ break;
1580
+ }
1581
+
1582
+ if (activitymaxinf_[mip->a_matrix_.index_[i]] <= 1 &&
1583
+ !propagateflags_[mip->a_matrix_.index_[i]] &&
1584
+ mip->row_lower_[mip->a_matrix_.index_[i]] != -kHighsInf)
1585
+ markPropagate(mip->a_matrix_.index_[i]);
1586
+ }
1587
+ }
1588
+
1589
+ if (!infeasible_) {
1590
+ for (CutpoolPropagation& cutpoolprop : cutpoolpropagation)
1591
+ cutpoolprop.updateActivityLbChange(col, oldbound, newbound);
1592
+ } else {
1593
+ assert(infeasible_reason.type == Reason::kModelRowLower ||
1594
+ infeasible_reason.type == Reason::kModelRowUpper);
1595
+ assert(infeasible_reason.index == mip->a_matrix_.index_[end - 1]);
1596
+ }
1597
+
1598
+ if (infeasible_) {
1599
+ std::swap(oldbound, newbound);
1600
+ for (HighsInt i = start; i != end; ++i) {
1601
+ if (mip->a_matrix_.value_[i] > 0) {
1602
+ activitymin_[mip->a_matrix_.index_[i]] +=
1603
+ computeDelta(mip->a_matrix_.value_[i], oldbound, newbound,
1604
+ -kHighsInf, activitymininf_[mip->a_matrix_.index_[i]]);
1605
+ } else {
1606
+ activitymax_[mip->a_matrix_.index_[i]] +=
1607
+ computeDelta(mip->a_matrix_.value_[i], oldbound, newbound,
1608
+ -kHighsInf, activitymaxinf_[mip->a_matrix_.index_[i]]);
1609
+ }
1610
+ }
1611
+
1612
+ if (objProp_.isActive()) {
1613
+ objProp_.updateActivityLbChange(col, oldbound, newbound);
1614
+ }
1615
+
1616
+ return;
1617
+ } else {
1618
+ for (ConflictPoolPropagation& conflictprop : conflictPoolPropagation)
1619
+ conflictprop.updateActivityLbChange(col, oldbound, newbound);
1620
+ }
1621
+ }
1622
+
1623
+ void HighsDomain::updateActivityUbChange(HighsInt col, double oldbound,
1624
+ double newbound) {
1625
+ auto mip = mipsolver->model_;
1626
+ HighsInt start = mip->a_matrix_.start_[col];
1627
+ HighsInt end = mip->a_matrix_.start_[col + 1];
1628
+
1629
+ assert(!infeasible_);
1630
+
1631
+ if (objProp_.isActive()) {
1632
+ objProp_.updateActivityUbChange(col, oldbound, newbound);
1633
+ if (infeasible_) return;
1634
+ }
1635
+
1636
+ for (HighsInt i = start; i != end; ++i) {
1637
+ if (mip->a_matrix_.value_[i] > 0) {
1638
+ HighsCDouble deltamax =
1639
+ computeDelta(mip->a_matrix_.value_[i], oldbound, newbound, kHighsInf,
1640
+ activitymaxinf_[mip->a_matrix_.index_[i]]);
1641
+ activitymax_[mip->a_matrix_.index_[i]] += deltamax;
1642
+
1643
+ #ifndef NDEBUG
1644
+ {
1645
+ HighsInt tmpinf;
1646
+ HighsCDouble tmpmaxact;
1647
+ computeMaxActivity(
1648
+ mipsolver->mipdata_->ARstart_[mip->a_matrix_.index_[i]],
1649
+ mipsolver->mipdata_->ARstart_[mip->a_matrix_.index_[i] + 1],
1650
+ mipsolver->mipdata_->ARindex_.data(),
1651
+ mipsolver->mipdata_->ARvalue_.data(), tmpinf, tmpmaxact);
1652
+ assert(std::fabs(double(activitymax_[mip->a_matrix_.index_[i]] -
1653
+ tmpmaxact)) <= mipsolver->mipdata_->feastol);
1654
+ assert(tmpinf == activitymaxinf_[mip->a_matrix_.index_[i]]);
1655
+ }
1656
+ #endif
1657
+
1658
+ if (recordRedundantRows_ &&
1659
+ mip->row_lower_[mip->a_matrix_.index_[i]] == -kHighsInf &&
1660
+ mip->row_upper_[mip->a_matrix_.index_[i]] != kHighsInf)
1661
+ updateRedundantRows(mip->a_matrix_.index_[i]);
1662
+
1663
+ if (deltamax >= 0) {
1664
+ updateThresholdUbChange(col, newbound, mip->a_matrix_.value_[i],
1665
+ capacityThreshold_[mip->a_matrix_.index_[i]]);
1666
+ continue;
1667
+ }
1668
+
1669
+ if (mip->row_lower_[mip->a_matrix_.index_[i]] != -kHighsInf &&
1670
+ activitymaxinf_[mip->a_matrix_.index_[i]] == 0 &&
1671
+ mip->row_lower_[mip->a_matrix_.index_[i]] -
1672
+ activitymax_[mip->a_matrix_.index_[i]] >
1673
+ mipsolver->mipdata_->feastol) {
1674
+ mipsolver->mipdata_->debugSolution.nodePruned(*this);
1675
+ infeasible_ = true;
1676
+ infeasible_pos = domchgstack_.size();
1677
+ infeasible_reason = Reason::modelRowLower(mip->a_matrix_.index_[i]);
1678
+ end = i + 1;
1679
+ break;
1680
+ }
1681
+
1682
+ if (activitymaxinf_[mip->a_matrix_.index_[i]] <= 1 &&
1683
+ !propagateflags_[mip->a_matrix_.index_[i]] &&
1684
+ mip->row_lower_[mip->a_matrix_.index_[i]] != -kHighsInf) {
1685
+ markPropagate(mip->a_matrix_.index_[i]);
1686
+ // propagateflags_[mip->a_matrix_.index_[i]] = 1;
1687
+ // propagateinds_.push_back(mip->a_matrix_.index_[i]);
1688
+ }
1689
+ } else {
1690
+ HighsCDouble deltamin =
1691
+ computeDelta(mip->a_matrix_.value_[i], oldbound, newbound, kHighsInf,
1692
+ activitymininf_[mip->a_matrix_.index_[i]]);
1693
+ activitymin_[mip->a_matrix_.index_[i]] += deltamin;
1694
+
1695
+ #ifndef NDEBUG
1696
+ {
1697
+ HighsInt tmpinf;
1698
+ HighsCDouble tmpminact;
1699
+ computeMinActivity(
1700
+ mipsolver->mipdata_->ARstart_[mip->a_matrix_.index_[i]],
1701
+ mipsolver->mipdata_->ARstart_[mip->a_matrix_.index_[i] + 1],
1702
+ mipsolver->mipdata_->ARindex_.data(),
1703
+ mipsolver->mipdata_->ARvalue_.data(), tmpinf, tmpminact);
1704
+ assert(std::fabs(double(activitymin_[mip->a_matrix_.index_[i]] -
1705
+ tmpminact)) <= mipsolver->mipdata_->feastol);
1706
+ assert(tmpinf == activitymininf_[mip->a_matrix_.index_[i]]);
1707
+ }
1708
+ #endif
1709
+
1710
+ if (recordRedundantRows_ &&
1711
+ mip->row_lower_[mip->a_matrix_.index_[i]] != -kHighsInf &&
1712
+ mip->row_upper_[mip->a_matrix_.index_[i]] == kHighsInf)
1713
+ updateRedundantRows(mip->a_matrix_.index_[i]);
1714
+
1715
+ if (deltamin <= 0) {
1716
+ updateThresholdUbChange(col, newbound, mip->a_matrix_.value_[i],
1717
+ capacityThreshold_[mip->a_matrix_.index_[i]]);
1718
+ continue;
1719
+ }
1720
+
1721
+ if (mip->row_upper_[mip->a_matrix_.index_[i]] != kHighsInf &&
1722
+ activitymininf_[mip->a_matrix_.index_[i]] == 0 &&
1723
+ activitymin_[mip->a_matrix_.index_[i]] -
1724
+ mip->row_upper_[mip->a_matrix_.index_[i]] >
1725
+ mipsolver->mipdata_->feastol) {
1726
+ mipsolver->mipdata_->debugSolution.nodePruned(*this);
1727
+ infeasible_ = true;
1728
+ infeasible_pos = domchgstack_.size();
1729
+ infeasible_reason = Reason::modelRowUpper(mip->a_matrix_.index_[i]);
1730
+ end = i + 1;
1731
+ break;
1732
+ }
1733
+
1734
+ if (activitymininf_[mip->a_matrix_.index_[i]] <= 1 &&
1735
+ !propagateflags_[mip->a_matrix_.index_[i]] &&
1736
+ mip->row_upper_[mip->a_matrix_.index_[i]] != kHighsInf) {
1737
+ markPropagate(mip->a_matrix_.index_[i]);
1738
+ // propagateflags_[mip->a_matrix_.index_[i]] = 1;
1739
+ // propagateinds_.push_back(mip->a_matrix_.index_[i]);
1740
+ }
1741
+ }
1742
+ }
1743
+
1744
+ if (!infeasible_) {
1745
+ for (CutpoolPropagation& cutpoolprop : cutpoolpropagation)
1746
+ cutpoolprop.updateActivityUbChange(col, oldbound, newbound);
1747
+ } else {
1748
+ assert(infeasible_reason.type == Reason::kModelRowLower ||
1749
+ infeasible_reason.type == Reason::kModelRowUpper);
1750
+ assert(infeasible_reason.index == mip->a_matrix_.index_[end - 1]);
1751
+ }
1752
+
1753
+ if (infeasible_) {
1754
+ std::swap(oldbound, newbound);
1755
+ for (HighsInt i = start; i != end; ++i) {
1756
+ if (mip->a_matrix_.value_[i] > 0) {
1757
+ activitymax_[mip->a_matrix_.index_[i]] +=
1758
+ computeDelta(mip->a_matrix_.value_[i], oldbound, newbound,
1759
+ kHighsInf, activitymaxinf_[mip->a_matrix_.index_[i]]);
1760
+ } else {
1761
+ activitymin_[mip->a_matrix_.index_[i]] +=
1762
+ computeDelta(mip->a_matrix_.value_[i], oldbound, newbound,
1763
+ kHighsInf, activitymininf_[mip->a_matrix_.index_[i]]);
1764
+ }
1765
+ }
1766
+
1767
+ if (objProp_.isActive()) {
1768
+ objProp_.updateActivityUbChange(col, oldbound, newbound);
1769
+ }
1770
+
1771
+ return;
1772
+ } else {
1773
+ for (ConflictPoolPropagation& conflictprop : conflictPoolPropagation)
1774
+ conflictprop.updateActivityUbChange(col, oldbound, newbound);
1775
+ }
1776
+ }
1777
+
1778
+ void HighsDomain::recomputeCapacityThreshold(HighsInt row) {
1779
+ HighsInt start = mipsolver->mipdata_->ARstart_[row];
1780
+ HighsInt end = mipsolver->mipdata_->ARstart_[row + 1];
1781
+
1782
+ capacityThreshold_[row] = -feastol();
1783
+ for (HighsInt i = start; i < end; ++i) {
1784
+ HighsInt col = mipsolver->mipdata_->ARindex_[i];
1785
+
1786
+ if (col_upper_[col] == col_lower_[col]) continue;
1787
+
1788
+ double threshold = std::fabs(mipsolver->mipdata_->ARvalue_[i]) *
1789
+ boundRange(col_upper_[col], col_lower_[col], feastol(),
1790
+ variableType(col));
1791
+
1792
+ capacityThreshold_[row] =
1793
+ std::max({capacityThreshold_[row], threshold, feastol()});
1794
+ }
1795
+ }
1796
+
1797
+ void HighsDomain::updateRedundantRows(HighsInt row) {
1798
+ if (!isRedundantRow(row)) {
1799
+ // row that was found to be redundant should not be non-redundant
1800
+ assert(redundantRows_.find(row) == nullptr);
1801
+ return;
1802
+ }
1803
+ // row is redundant
1804
+ redundantRows_.insert(row);
1805
+ }
1806
+
1807
+ double HighsDomain::getRedundantRowValue(HighsInt row) const {
1808
+ if (mipsolver->rowLower(row) != -kHighsInf) {
1809
+ assert(mipsolver->rowUpper(row) == kHighsInf);
1810
+ return static_cast<double>(activitymin_[row] - mipsolver->rowLower(row));
1811
+ } else {
1812
+ assert(mipsolver->rowUpper(row) != kHighsInf);
1813
+ return static_cast<double>(activitymax_[row] - mipsolver->rowUpper(row));
1814
+ }
1815
+ }
1816
+
1817
+ bool HighsDomain::isRedundantRow(HighsInt row) const {
1818
+ return (getMinActivity(row) >= mipsolver->rowLower(row) - feastol() &&
1819
+ getMaxActivity(row) <= mipsolver->rowUpper(row) + feastol());
1820
+ }
1821
+
1822
+ void HighsDomain::markPropagateCut(Reason reason) {
1823
+ switch (reason.type) {
1824
+ case Reason::kUnknown:
1825
+ case Reason::kCliqueTable:
1826
+ case Reason::kBranching:
1827
+ case Reason::kModelRowLower:
1828
+ case Reason::kModelRowUpper:
1829
+ case Reason::kConflictingBounds:
1830
+ case Reason::kObjective:
1831
+ break;
1832
+ default:
1833
+ assert(reason.type >= 0 &&
1834
+ reason.type < HighsInt(cutpoolpropagation.size() +
1835
+ conflictPoolPropagation.size()));
1836
+ if (reason.type < (HighsInt)cutpoolpropagation.size())
1837
+ cutpoolpropagation[reason.type].markPropagateCut(reason.index);
1838
+ else
1839
+ conflictPoolPropagation[reason.type - cutpoolpropagation.size()]
1840
+ .markPropagateConflict(reason.index);
1841
+ }
1842
+ }
1843
+
1844
+ void HighsDomain::markPropagate(HighsInt row) {
1845
+ if (!propagateflags_[row]) {
1846
+ bool proplower = mipsolver->rowLower(row) != -kHighsInf &&
1847
+ (activitymininf_[row] != 0 ||
1848
+ activitymin_[row] < mipsolver->rowLower(row) -
1849
+ mipsolver->mipdata_->feastol) &&
1850
+ (activitymaxinf_[row] == 1 ||
1851
+ (double(activitymax_[row]) - mipsolver->rowLower(row)) <=
1852
+ capacityThreshold_[row]);
1853
+ bool propupper = mipsolver->rowUpper(row) != kHighsInf &&
1854
+ (activitymaxinf_[row] != 0 ||
1855
+ activitymax_[row] > mipsolver->rowUpper(row) +
1856
+ mipsolver->mipdata_->feastol) &&
1857
+ (activitymininf_[row] == 1 ||
1858
+ (mipsolver->rowUpper(row) - double(activitymin_[row])) <=
1859
+ capacityThreshold_[row]);
1860
+
1861
+ if (proplower || propupper) {
1862
+ propagateinds_.push_back(row);
1863
+ propagateflags_[row] = 1;
1864
+ }
1865
+ }
1866
+ }
1867
+
1868
+ void HighsDomain::computeRowActivities() {
1869
+ activitymin_.resize(mipsolver->numRow());
1870
+ activitymininf_.resize(mipsolver->numRow());
1871
+ activitymax_.resize(mipsolver->numRow());
1872
+ activitymaxinf_.resize(mipsolver->numRow());
1873
+ capacityThreshold_.resize(mipsolver->numRow());
1874
+ propagateflags_.resize(mipsolver->numRow());
1875
+ propagateinds_.reserve(mipsolver->numRow());
1876
+
1877
+ for (HighsInt i = 0; i != mipsolver->numRow(); ++i) {
1878
+ HighsInt start = mipsolver->mipdata_->ARstart_[i];
1879
+ HighsInt end = mipsolver->mipdata_->ARstart_[i + 1];
1880
+
1881
+ computeMinActivity(start, end, mipsolver->mipdata_->ARindex_.data(),
1882
+ mipsolver->mipdata_->ARvalue_.data(), activitymininf_[i],
1883
+ activitymin_[i]);
1884
+ computeMaxActivity(start, end, mipsolver->mipdata_->ARindex_.data(),
1885
+ mipsolver->mipdata_->ARvalue_.data(), activitymaxinf_[i],
1886
+ activitymax_[i]);
1887
+
1888
+ recomputeCapacityThreshold(i);
1889
+
1890
+ if ((activitymininf_[i] <= 1 && mipsolver->rowUpper(i) != kHighsInf) ||
1891
+ (activitymaxinf_[i] <= 1 && mipsolver->rowLower(i) != -kHighsInf)) {
1892
+ markPropagate(i);
1893
+ // propagateflags_[i] = 1;
1894
+ // propagateinds_.push_back(i);
1895
+ }
1896
+ }
1897
+ }
1898
+
1899
+ double HighsDomain::doChangeBound(const HighsDomainChange& boundchg) {
1900
+ double oldbound;
1901
+
1902
+ if (boundchg.boundtype == HighsBoundType::kLower) {
1903
+ oldbound = col_lower_[boundchg.column];
1904
+ col_lower_[boundchg.column] = boundchg.boundval;
1905
+ if (oldbound != boundchg.boundval) {
1906
+ if (!infeasible_)
1907
+ updateActivityLbChange(boundchg.column, oldbound, boundchg.boundval);
1908
+
1909
+ if (!isChangedCol(boundchg.column)) {
1910
+ changedcolsflags_[boundchg.column] = 1;
1911
+ changedcols_.push_back(boundchg.column);
1912
+ }
1913
+ }
1914
+ } else {
1915
+ oldbound = col_upper_[boundchg.column];
1916
+ col_upper_[boundchg.column] = boundchg.boundval;
1917
+ if (oldbound != boundchg.boundval) {
1918
+ if (!infeasible_)
1919
+ updateActivityUbChange(boundchg.column, oldbound, boundchg.boundval);
1920
+
1921
+ if (!isChangedCol(boundchg.column)) {
1922
+ changedcolsflags_[boundchg.column] = 1;
1923
+ changedcols_.push_back(boundchg.column);
1924
+ }
1925
+ }
1926
+ }
1927
+
1928
+ return oldbound;
1929
+ }
1930
+
1931
+ void HighsDomain::changeBound(HighsDomainChange boundchg, Reason reason) {
1932
+ assert(boundchg.column >= 0);
1933
+ assert(boundchg.column < (HighsInt)col_upper_.size());
1934
+ // assert(infeasible_ == 0);
1935
+ // if (reason.type == Reason::kObjective) {
1936
+ // if (!mipsolver->submip)
1937
+ // printf("objective propagator changed %s bound of column %d to %g\n",
1938
+ // boundchg.boundtype == HighsBoundType::kLower ? "lower" :
1939
+ // "upper", boundchg.column, boundchg.boundval);
1940
+ // }
1941
+
1942
+ HighsInt prevPos;
1943
+ if (boundchg.boundtype == HighsBoundType::kLower) {
1944
+ if (boundchg.boundval <= col_lower_[boundchg.column]) {
1945
+ if (reason.type != Reason::kBranching) return;
1946
+ boundchg.boundval = col_lower_[boundchg.column];
1947
+ }
1948
+ if (boundchg.boundval > col_upper_[boundchg.column]) {
1949
+ if (boundchg.boundval - col_upper_[boundchg.column] >
1950
+ mipsolver->mipdata_->feastol) {
1951
+ mipsolver->mipdata_->debugSolution.nodePruned(*this);
1952
+ if (!infeasible_) {
1953
+ infeasible_pos = domchgstack_.size();
1954
+ infeasible_ = true;
1955
+ infeasible_reason = Reason::conflictingBounds(domchgstack_.size());
1956
+ }
1957
+ } else {
1958
+ boundchg.boundval = col_upper_[boundchg.column];
1959
+ if (boundchg.boundval == col_lower_[boundchg.column]) return;
1960
+ }
1961
+ }
1962
+
1963
+ prevPos = colLowerPos_[boundchg.column];
1964
+ colLowerPos_[boundchg.column] = domchgstack_.size();
1965
+ } else {
1966
+ if (boundchg.boundval >= col_upper_[boundchg.column]) {
1967
+ if (reason.type != Reason::kBranching) return;
1968
+ boundchg.boundval = col_upper_[boundchg.column];
1969
+ }
1970
+ if (boundchg.boundval < col_lower_[boundchg.column]) {
1971
+ if (col_lower_[boundchg.column] - boundchg.boundval >
1972
+ mipsolver->mipdata_->feastol) {
1973
+ mipsolver->mipdata_->debugSolution.nodePruned(*this);
1974
+ if (!infeasible_) {
1975
+ infeasible_pos = domchgstack_.size();
1976
+ infeasible_ = true;
1977
+ infeasible_reason = Reason::conflictingBounds(domchgstack_.size());
1978
+ }
1979
+ } else {
1980
+ boundchg.boundval = col_lower_[boundchg.column];
1981
+ if (boundchg.boundval == col_upper_[boundchg.column]) return;
1982
+ }
1983
+ }
1984
+
1985
+ prevPos = colUpperPos_[boundchg.column];
1986
+ colUpperPos_[boundchg.column] = domchgstack_.size();
1987
+ }
1988
+
1989
+ mipsolver->mipdata_->debugSolution.boundChangeAdded(
1990
+ *this, boundchg, reason.type == Reason::kBranching);
1991
+
1992
+ if (reason.type == Reason::kBranching)
1993
+ branchPos_.push_back(domchgstack_.size());
1994
+
1995
+ assert(prevPos < (HighsInt)domchgstack_.size());
1996
+
1997
+ bool binary = isBinary(boundchg.column);
1998
+
1999
+ double oldbound = doChangeBound(boundchg);
2000
+
2001
+ prevboundval_.emplace_back(oldbound, prevPos);
2002
+ domchgstack_.push_back(boundchg);
2003
+ domchgreason_.push_back(reason);
2004
+
2005
+ if (binary && !infeasible_ && isFixed(boundchg.column)) {
2006
+ mipsolver->mipdata_->cliquetable.addImplications(
2007
+ *this, boundchg.column, col_lower_[boundchg.column] > 0.5);
2008
+ if (!infeasible_) {
2009
+ mipsolver->mipdata_->implications.applyImplications(
2010
+ *this, boundchg.column, col_lower_[boundchg.column] > 0.5);
2011
+ }
2012
+ }
2013
+ }
2014
+
2015
+ bool HighsDomain::checkChangeBound(HighsBoundType boundtype, HighsInt col,
2016
+ HighsCDouble boundval, Reason reason) {
2017
+ if (std::abs(static_cast<double>(boundval * kHighsTiny)) > feastol())
2018
+ return false;
2019
+ bool accept;
2020
+ double bound = boundtype == HighsBoundType::kLower
2021
+ ? adjustedLb(col, boundval, accept)
2022
+ : adjustedUb(col, boundval, accept);
2023
+ if (!accept) return false;
2024
+ changeBound(boundtype, col, bound, reason);
2025
+ return true;
2026
+ }
2027
+
2028
+ void HighsDomain::setDomainChangeStack(
2029
+ const std::vector<HighsDomainChange>& domchgstack) {
2030
+ infeasible_ = false;
2031
+ mipsolver->mipdata_->debugSolution.resetDomain(*this);
2032
+
2033
+ if (!domchgstack_.empty()) {
2034
+ for (const HighsDomainChange& domchg : domchgstack_) {
2035
+ if (domchg.boundtype == HighsBoundType::kLower)
2036
+ colLowerPos_[domchg.column] = -1;
2037
+ else
2038
+ colUpperPos_[domchg.column] = -1;
2039
+ }
2040
+ }
2041
+
2042
+ prevboundval_.clear();
2043
+ domchgstack_.clear();
2044
+ domchgreason_.clear();
2045
+ branchPos_.clear();
2046
+ HighsInt stacksize = domchgstack.size();
2047
+ for (HighsInt k = 0; k != stacksize; ++k) {
2048
+ if (domchgstack[k].boundtype == HighsBoundType::kLower &&
2049
+ domchgstack[k].boundval <= col_lower_[domchgstack[k].column])
2050
+ continue;
2051
+ if (domchgstack[k].boundtype == HighsBoundType::kUpper &&
2052
+ domchgstack[k].boundval >= col_upper_[domchgstack[k].column])
2053
+ continue;
2054
+
2055
+ changeBound(domchgstack[k], Reason::unspecified());
2056
+
2057
+ if (infeasible_) break;
2058
+ }
2059
+ }
2060
+
2061
+ void HighsDomain::setDomainChangeStack(
2062
+ const std::vector<HighsDomainChange>& domchgstack,
2063
+ const std::vector<HighsInt>& branchingPositions) {
2064
+ infeasible_ = false;
2065
+ mipsolver->mipdata_->debugSolution.resetDomain(*this);
2066
+
2067
+ if (!domchgstack_.empty()) {
2068
+ for (const HighsDomainChange& domchg : domchgstack_) {
2069
+ if (domchg.boundtype == HighsBoundType::kLower)
2070
+ colLowerPos_[domchg.column] = -1;
2071
+ else
2072
+ colUpperPos_[domchg.column] = -1;
2073
+ }
2074
+ }
2075
+
2076
+ prevboundval_.clear();
2077
+ domchgstack_.clear();
2078
+ domchgreason_.clear();
2079
+ branchPos_.clear();
2080
+ HighsInt stacksize = domchgstack.size();
2081
+ HighsInt k = 0;
2082
+ for (HighsInt branchPos : branchingPositions) {
2083
+ for (; k < branchPos; ++k) {
2084
+ if (domchgstack[k].boundtype == HighsBoundType::kLower &&
2085
+ domchgstack[k].boundval <= col_lower_[domchgstack[k].column])
2086
+ continue;
2087
+ if (domchgstack[k].boundtype == HighsBoundType::kUpper &&
2088
+ domchgstack[k].boundval >= col_upper_[domchgstack[k].column])
2089
+ continue;
2090
+
2091
+ changeBound(domchgstack[k], Reason::unspecified());
2092
+ if (!infeasible_) propagate();
2093
+ if (infeasible_) return;
2094
+ }
2095
+
2096
+ if (k == stacksize) return;
2097
+
2098
+ // For redundant branching bound changes we need to be more careful due to
2099
+ // symmetry handling. If these bound changes are redundant simply because
2100
+ // the corresponding subtree was enumerated and hence the global bound
2101
+ // updated, then we still need to keep their status as branching variables
2102
+ // for computing correct stabilizers. They can, however, be safely dropped
2103
+ // if they are either strictly redundant in the global domain, or if there
2104
+ // is already a local bound change that makes the branching change
2105
+ // redundant.
2106
+ if (domchgstack[k].boundtype == HighsBoundType::kLower) {
2107
+ if (domchgstack[k].boundval <= col_lower_[domchgstack[k].column]) {
2108
+ if (domchgstack[k].boundval < col_lower_[domchgstack[k].column])
2109
+ continue;
2110
+ if (colLowerPos_[domchgstack[k].column] != -1) continue;
2111
+ }
2112
+ } else {
2113
+ if (domchgstack[k].boundval >= col_upper_[domchgstack[k].column]) {
2114
+ if (domchgstack[k].boundval > col_upper_[domchgstack[k].column])
2115
+ continue;
2116
+ if (colUpperPos_[domchgstack[k].column] != -1) continue;
2117
+ }
2118
+ }
2119
+
2120
+ changeBound(domchgstack[k], Reason::branching());
2121
+ if (!infeasible_) propagate();
2122
+ if (infeasible_) return;
2123
+ }
2124
+
2125
+ for (; k < stacksize; ++k) {
2126
+ if (domchgstack[k].boundtype == HighsBoundType::kLower &&
2127
+ domchgstack[k].boundval <= col_lower_[domchgstack[k].column])
2128
+ continue;
2129
+ if (domchgstack[k].boundtype == HighsBoundType::kUpper &&
2130
+ domchgstack[k].boundval >= col_upper_[domchgstack[k].column])
2131
+ continue;
2132
+
2133
+ mipsolver->mipdata_->debugSolution.boundChangeAdded(*this, domchgstack[k],
2134
+ true);
2135
+
2136
+ changeBound(domchgstack[k], Reason::unspecified());
2137
+ if (!infeasible_) propagate();
2138
+ if (infeasible_) break;
2139
+ }
2140
+ }
2141
+
2142
+ void HighsDomain::backtrackToGlobal() {
2143
+ HighsInt k = HighsInt(domchgstack_.size()) - 1;
2144
+ bool old_infeasible = infeasible_;
2145
+ Reason old_reason = infeasible_reason;
2146
+
2147
+ if (infeasible_ && infeasible_pos == HighsInt(domchgstack_.size())) {
2148
+ assert(old_infeasible);
2149
+ assert(k == HighsInt(domchgstack_.size()) - 1);
2150
+ infeasible_ = false;
2151
+ infeasible_reason = Reason::unspecified();
2152
+ }
2153
+
2154
+ while (k >= 0) {
2155
+ double prevbound = prevboundval_[k].first;
2156
+ HighsInt prevpos = prevboundval_[k].second;
2157
+ assert(prevpos < k);
2158
+
2159
+ mipsolver->mipdata_->debugSolution.boundChangeRemoved(*this,
2160
+ domchgstack_[k]);
2161
+
2162
+ if (domchgstack_[k].boundtype == HighsBoundType::kLower) {
2163
+ assert(colLowerPos_[domchgstack_[k].column] == k);
2164
+ colLowerPos_[domchgstack_[k].column] = prevpos;
2165
+ } else {
2166
+ assert(colUpperPos_[domchgstack_[k].column] == k);
2167
+ colUpperPos_[domchgstack_[k].column] = prevpos;
2168
+ }
2169
+
2170
+ if (prevbound != domchgstack_[k].boundval) {
2171
+ // change back to global bound
2172
+ doChangeBound(
2173
+ {prevbound, domchgstack_[k].column, domchgstack_[k].boundtype});
2174
+ }
2175
+
2176
+ if (infeasible_ && infeasible_pos == k) {
2177
+ assert(old_infeasible);
2178
+ assert(k == HighsInt(domchgstack_.size()) - 1);
2179
+ infeasible_ = false;
2180
+ infeasible_reason = Reason::unspecified();
2181
+ }
2182
+
2183
+ --k;
2184
+ }
2185
+
2186
+ if (old_infeasible) {
2187
+ markPropagateCut(old_reason);
2188
+ infeasible_reason = Reason::unspecified();
2189
+ infeasible_ = false;
2190
+ }
2191
+
2192
+ HighsInt numreason = domchgreason_.size();
2193
+ for (HighsInt i = k + 1; i < numreason; ++i)
2194
+ markPropagateCut(domchgreason_[i]);
2195
+
2196
+ domchgstack_.clear();
2197
+ prevboundval_.clear();
2198
+ domchgreason_.clear();
2199
+ branchPos_.clear();
2200
+ }
2201
+
2202
+ HighsDomainChange HighsDomain::backtrack() {
2203
+ HighsInt k = HighsInt(domchgstack_.size()) - 1;
2204
+ bool old_infeasible = infeasible_;
2205
+ Reason old_reason = infeasible_reason;
2206
+
2207
+ if (infeasible_ && infeasible_pos == HighsInt(domchgstack_.size())) {
2208
+ assert(old_infeasible);
2209
+ assert(k == HighsInt(domchgstack_.size()) - 1);
2210
+ infeasible_ = false;
2211
+ infeasible_reason = Reason::unspecified();
2212
+ }
2213
+ while (k >= 0) {
2214
+ double prevbound = prevboundval_[k].first;
2215
+ HighsInt prevpos = prevboundval_[k].second;
2216
+ assert(prevpos < k);
2217
+
2218
+ mipsolver->mipdata_->debugSolution.boundChangeRemoved(*this,
2219
+ domchgstack_[k]);
2220
+
2221
+ if (domchgstack_[k].boundtype == HighsBoundType::kLower) {
2222
+ assert(colLowerPos_[domchgstack_[k].column] == k);
2223
+ colLowerPos_[domchgstack_[k].column] = prevpos;
2224
+ } else {
2225
+ assert(colUpperPos_[domchgstack_[k].column] == k);
2226
+ colUpperPos_[domchgstack_[k].column] = prevpos;
2227
+ }
2228
+
2229
+ // change back to global bound
2230
+ doChangeBound(
2231
+ {prevbound, domchgstack_[k].column, domchgstack_[k].boundtype});
2232
+
2233
+ if (infeasible_ && infeasible_pos == k) {
2234
+ assert(old_infeasible);
2235
+ assert(k == HighsInt(domchgstack_.size()) - 1);
2236
+ infeasible_ = false;
2237
+ infeasible_reason = Reason::unspecified();
2238
+ }
2239
+
2240
+ if (domchgreason_[k].type == Reason::kBranching) {
2241
+ branchPos_.pop_back();
2242
+ break;
2243
+ }
2244
+
2245
+ --k;
2246
+ }
2247
+
2248
+ if (old_infeasible) {
2249
+ markPropagateCut(old_reason);
2250
+ infeasible_reason = Reason::unspecified();
2251
+ infeasible_ = false;
2252
+ }
2253
+
2254
+ HighsInt numreason = domchgreason_.size();
2255
+ for (HighsInt i = k + 1; i < numreason; ++i)
2256
+ markPropagateCut(domchgreason_[i]);
2257
+
2258
+ if (k < 0) {
2259
+ domchgstack_.clear();
2260
+ prevboundval_.clear();
2261
+ domchgreason_.clear();
2262
+ branchPos_.clear();
2263
+ return HighsDomainChange({0.0, -1, HighsBoundType::kLower});
2264
+ }
2265
+
2266
+ HighsDomainChange backtrackboundchg = domchgstack_[k];
2267
+ domchgstack_.erase(domchgstack_.begin() + k, domchgstack_.end());
2268
+ domchgreason_.resize(k);
2269
+ prevboundval_.resize(k);
2270
+
2271
+ return backtrackboundchg;
2272
+ }
2273
+
2274
+ bool HighsDomain::propagate() {
2275
+ std::vector<HighsInt> propagateinds;
2276
+
2277
+ auto havePropagationRows = [&]() {
2278
+ if (!propagateinds_.empty()) return true;
2279
+
2280
+ if (objProp_.isActive() && objProp_.shouldBePropagated()) return true;
2281
+
2282
+ for (const auto& cutpoolprop : cutpoolpropagation) {
2283
+ if (!cutpoolprop.propagatecutinds_.empty()) return true;
2284
+ }
2285
+
2286
+ for (const auto& conflictprop : conflictPoolPropagation) {
2287
+ if (!conflictprop.propagateConflictInds_.empty()) return true;
2288
+ }
2289
+
2290
+ return false;
2291
+ };
2292
+
2293
+ if (!havePropagationRows()) return false;
2294
+
2295
+ size_t changedboundsize = 2 * mipsolver->mipdata_->ARvalue_.size();
2296
+
2297
+ for (const auto& cutpoolprop : cutpoolpropagation)
2298
+ changedboundsize = std::max(
2299
+ changedboundsize, cutpoolprop.cutpool->getMatrix().nonzeroCapacity());
2300
+
2301
+ std::unique_ptr<HighsDomainChange[]> changedbounds(
2302
+ new HighsDomainChange[changedboundsize]);
2303
+
2304
+ while (havePropagationRows()) {
2305
+ if (objProp_.isActive()) objProp_.propagate();
2306
+
2307
+ const HighsInt numConflictPools = conflictPoolPropagation.size();
2308
+ for (HighsInt conflictPool = 0; conflictPool < numConflictPools;
2309
+ ++conflictPool) {
2310
+ auto& conflictprop = conflictPoolPropagation[conflictPool];
2311
+ while (!conflictprop.propagateConflictInds_.empty()) {
2312
+ propagateinds.swap(conflictprop.propagateConflictInds_);
2313
+
2314
+ for (HighsInt conflict : propagateinds)
2315
+ conflictprop.propagateConflict(conflict);
2316
+
2317
+ propagateinds.clear();
2318
+ }
2319
+ }
2320
+
2321
+ if (!propagateinds_.empty()) {
2322
+ propagateinds.swap(propagateinds_);
2323
+
2324
+ HighsInt numproprows = propagateinds.size();
2325
+ for (HighsInt i = 0; i != numproprows; ++i) {
2326
+ HighsInt row = propagateinds[i];
2327
+ propagateflags_[row] = 0;
2328
+ }
2329
+
2330
+ if (!infeasible_) {
2331
+ propRowNumChangedBounds_.assign(
2332
+ numproprows, std::make_pair(HighsInt{0}, HighsInt{0}));
2333
+
2334
+ auto propagateIndex = [&](HighsInt k) {
2335
+ // for (HighsInt k = 0; k != numproprows; ++k) {
2336
+ HighsInt i = propagateinds[k];
2337
+ HighsInt start = mipsolver->mipdata_->ARstart_[i];
2338
+ HighsInt end = mipsolver->mipdata_->ARstart_[i + 1];
2339
+ HighsInt Rlen = end - start;
2340
+ const HighsInt* Rindex = mipsolver->mipdata_->ARindex_.data() + start;
2341
+ const double* Rvalue = mipsolver->mipdata_->ARvalue_.data() + start;
2342
+ bool recomputeCapThreshold = false;
2343
+
2344
+ if (mipsolver->rowUpper(i) != kHighsInf &&
2345
+ (activitymaxinf_[i] != 0 ||
2346
+ activitymax_[i] >
2347
+ mipsolver->rowUpper(i) + mipsolver->mipdata_->feastol)) {
2348
+ // computeMinActivity(start, end, mipsolver->ARstart_.data(),
2349
+ // mipsolver->ARvalue_.data(), activitymininf_[i],
2350
+ // activitymin_[i]);
2351
+ activitymin_[i].renormalize();
2352
+ propRowNumChangedBounds_[k].first = propagateRowUpper(
2353
+ Rindex, Rvalue, Rlen, mipsolver->rowUpper(i), activitymin_[i],
2354
+ activitymininf_[i], &changedbounds[2 * start]);
2355
+
2356
+ recomputeCapThreshold = true;
2357
+ }
2358
+
2359
+ if (mipsolver->rowLower(i) != -kHighsInf &&
2360
+ (activitymininf_[i] != 0 ||
2361
+ activitymin_[i] <
2362
+ mipsolver->rowLower(i) - mipsolver->mipdata_->feastol)) {
2363
+ // computeMaxActivity(start, end, mipsolver->ARstart_.data(),
2364
+ // mipsolver->ARvalue_.data(), activitymaxinf_[i],
2365
+ // activitymax_[i]);
2366
+ activitymax_[i].renormalize();
2367
+ propRowNumChangedBounds_[k].second = propagateRowLower(
2368
+ Rindex, Rvalue, Rlen, mipsolver->rowLower(i), activitymax_[i],
2369
+ activitymaxinf_[i],
2370
+ &changedbounds[2 * start + propRowNumChangedBounds_[k].first]);
2371
+
2372
+ recomputeCapThreshold = true;
2373
+ }
2374
+
2375
+ if (recomputeCapThreshold) recomputeCapacityThreshold(i);
2376
+ };
2377
+
2378
+ // printf("numproprows (model): %" HIGHSINT_FORMAT "\n", numproprows);
2379
+
2380
+ for (HighsInt k = 0; k != numproprows; ++k) propagateIndex(k);
2381
+
2382
+ for (HighsInt k = 0; k != numproprows; ++k) {
2383
+ HighsInt i = propagateinds[k];
2384
+
2385
+ if (propRowNumChangedBounds_[k].first != 0) {
2386
+ HighsInt start = 2 * mipsolver->mipdata_->ARstart_[i];
2387
+ HighsInt end = start + propRowNumChangedBounds_[k].first;
2388
+ for (HighsInt j = start; j != end && !infeasible_; ++j)
2389
+ changeBound(changedbounds[j], Reason::modelRowUpper(i));
2390
+
2391
+ if (infeasible_) break;
2392
+ }
2393
+ if (propRowNumChangedBounds_[k].second != 0) {
2394
+ HighsInt start = 2 * mipsolver->mipdata_->ARstart_[i] +
2395
+ propRowNumChangedBounds_[k].first;
2396
+ HighsInt end = start + propRowNumChangedBounds_[k].second;
2397
+ for (HighsInt j = start; j != end && !infeasible_; ++j)
2398
+ changeBound(changedbounds[j], Reason::modelRowLower(i));
2399
+
2400
+ if (infeasible_) break;
2401
+ }
2402
+ }
2403
+ }
2404
+
2405
+ propagateinds.clear();
2406
+ }
2407
+
2408
+ const HighsInt numpools = cutpoolpropagation.size();
2409
+ for (HighsInt cutpool = 0; cutpool != numpools; ++cutpool) {
2410
+ auto& cutpoolprop = cutpoolpropagation[cutpool];
2411
+ if (!cutpoolprop.propagatecutinds_.empty()) {
2412
+ propagateinds.swap(cutpoolprop.propagatecutinds_);
2413
+
2414
+ HighsInt numproprows = propagateinds.size();
2415
+ for (HighsInt i = 0; i != numproprows; ++i) {
2416
+ HighsInt cut = propagateinds[i];
2417
+ cutpoolprop.propagatecutflags_[cut] &= 2;
2418
+ }
2419
+
2420
+ if (!infeasible_) {
2421
+ propRowNumChangedBounds_.assign(
2422
+ numproprows, std::make_pair(HighsInt{0}, HighsInt{0}));
2423
+
2424
+ auto propagateIndex = [&](HighsInt k) {
2425
+ HighsInt i = propagateinds[k];
2426
+ // first check if cut is marked as deleted
2427
+ if (cutpoolprop.propagatecutflags_[i] & 2) return;
2428
+
2429
+ HighsInt Rlen;
2430
+ const HighsInt* Rindex;
2431
+ const double* Rvalue;
2432
+ cutpoolprop.cutpool->getCut(i, Rlen, Rindex, Rvalue);
2433
+ cutpoolprop.activitycuts_[i].renormalize();
2434
+
2435
+ propRowNumChangedBounds_[k].first = propagateRowUpper(
2436
+ Rindex, Rvalue, Rlen, cutpoolprop.cutpool->getRhs()[i],
2437
+ cutpoolprop.activitycuts_[i], cutpoolprop.activitycutsinf_[i],
2438
+ &changedbounds[cutpoolprop.cutpool->getMatrix().getRowStart(
2439
+ i)]);
2440
+
2441
+ cutpoolprop.recomputeCapacityThreshold(i);
2442
+ };
2443
+
2444
+ // printf("numproprows (cuts): %" HIGHSINT_FORMAT "\n", numproprows);
2445
+
2446
+ for (HighsInt k = 0; k != numproprows; ++k) propagateIndex(k);
2447
+
2448
+ for (HighsInt k = 0; k != numproprows; ++k) {
2449
+ HighsInt i = propagateinds[k];
2450
+ if (propRowNumChangedBounds_[k].first != 0) {
2451
+ cutpoolprop.cutpool->resetAge(i);
2452
+ HighsInt start = cutpoolprop.cutpool->getMatrix().getRowStart(i);
2453
+ HighsInt end = start + propRowNumChangedBounds_[k].first;
2454
+ for (HighsInt j = start; j != end && !infeasible_; ++j)
2455
+ changeBound(changedbounds[j], Reason::cut(cutpool, i));
2456
+ }
2457
+
2458
+ if (infeasible_) break;
2459
+ }
2460
+ }
2461
+
2462
+ propagateinds.clear();
2463
+ }
2464
+ }
2465
+ }
2466
+
2467
+ return true;
2468
+ }
2469
+
2470
+ double HighsDomain::getColLowerPos(HighsInt col, HighsInt stackpos,
2471
+ HighsInt& pos) const {
2472
+ double lb = col_lower_[col];
2473
+ pos = colLowerPos_[col];
2474
+ while (pos > stackpos || (pos != -1 && prevboundval_[pos].first == lb)) {
2475
+ lb = prevboundval_[pos].first;
2476
+ pos = prevboundval_[pos].second;
2477
+ }
2478
+ return lb;
2479
+ }
2480
+
2481
+ double HighsDomain::getColUpperPos(HighsInt col, HighsInt stackpos,
2482
+ HighsInt& pos) const {
2483
+ double ub = col_upper_[col];
2484
+ pos = colUpperPos_[col];
2485
+ while (pos > stackpos || (pos != -1 && prevboundval_[pos].first == ub)) {
2486
+ ub = prevboundval_[pos].first;
2487
+ pos = prevboundval_[pos].second;
2488
+ }
2489
+ return ub;
2490
+ }
2491
+
2492
+ void HighsDomain::conflictAnalysis(HighsConflictPool& conflictPool) {
2493
+ if (&mipsolver->mipdata_->domain == this) return;
2494
+ if (mipsolver->mipdata_->domain.infeasible() || !infeasible_) return;
2495
+
2496
+ mipsolver->mipdata_->domain.propagate();
2497
+ if (mipsolver->mipdata_->domain.infeasible()) return;
2498
+
2499
+ ConflictSet conflictSet(*this);
2500
+
2501
+ conflictSet.conflictAnalysis(conflictPool);
2502
+ }
2503
+
2504
+ void HighsDomain::conflictAnalysis(const HighsInt* proofinds,
2505
+ const double* proofvals, HighsInt prooflen,
2506
+ double proofrhs,
2507
+ HighsConflictPool& conflictPool) {
2508
+ if (&mipsolver->mipdata_->domain == this) return;
2509
+
2510
+ if (mipsolver->mipdata_->domain.infeasible()) return;
2511
+
2512
+ mipsolver->mipdata_->domain.propagate();
2513
+ if (mipsolver->mipdata_->domain.infeasible()) return;
2514
+
2515
+ ConflictSet conflictSet(*this);
2516
+ conflictSet.conflictAnalysis(proofinds, proofvals, prooflen, proofrhs,
2517
+ conflictPool);
2518
+ }
2519
+
2520
+ void HighsDomain::conflictAnalyzeReconvergence(
2521
+ const HighsDomainChange& domchg, const HighsInt* proofinds,
2522
+ const double* proofvals, HighsInt prooflen, double proofrhs,
2523
+ HighsConflictPool& conflictPool) {
2524
+ if (&mipsolver->mipdata_->domain == this) return;
2525
+
2526
+ if (mipsolver->mipdata_->domain.infeasible()) return;
2527
+
2528
+ mipsolver->mipdata_->domain.propagate();
2529
+ if (mipsolver->mipdata_->domain.infeasible()) return;
2530
+
2531
+ ConflictSet conflictSet(*this);
2532
+
2533
+ HighsInt ninfmin;
2534
+ HighsCDouble activitymin;
2535
+ mipsolver->mipdata_->domain.computeMinActivity(
2536
+ 0, prooflen, proofinds, proofvals, ninfmin, activitymin);
2537
+ if (ninfmin != 0) return;
2538
+
2539
+ if (!conflictSet.explainBoundChangeLeq(
2540
+ conflictSet.reconvergenceFrontier,
2541
+ ConflictSet::LocalDomChg{HighsInt(domchgstack_.size()), domchg},
2542
+ proofinds, proofvals, prooflen, proofrhs, double(activitymin)))
2543
+ return;
2544
+
2545
+ if (10 * conflictSet.resolvedDomainChanges.size() >
2546
+ 1000 + 3 * mipsolver->mipdata_->integral_cols.size())
2547
+ return;
2548
+
2549
+ conflictSet.reconvergenceFrontier.insert(
2550
+ conflictSet.resolvedDomainChanges.begin(),
2551
+ conflictSet.resolvedDomainChanges.end());
2552
+
2553
+ HighsInt depth = branchPos_.size();
2554
+
2555
+ while (depth > 0) {
2556
+ HighsInt branchPos = branchPos_[depth - 1];
2557
+ if (domchgstack_[branchPos].boundval != prevboundval_[branchPos].first)
2558
+ break;
2559
+
2560
+ --depth;
2561
+ }
2562
+
2563
+ conflictSet.resolveDepth(conflictSet.reconvergenceFrontier, depth, 0);
2564
+ conflictPool.addReconvergenceCut(*this, conflictSet.reconvergenceFrontier,
2565
+ domchg);
2566
+ }
2567
+
2568
+ void HighsDomain::tightenCoefficients(HighsInt* inds, double* vals,
2569
+ HighsInt len, double& rhs) const {
2570
+ HighsCDouble maxactivity = 0;
2571
+
2572
+ for (HighsInt i = 0; i != len; ++i) {
2573
+ if (vals[i] > 0) {
2574
+ if (col_upper_[inds[i]] == kHighsInf) return;
2575
+
2576
+ maxactivity += col_upper_[inds[i]] * vals[i];
2577
+ } else {
2578
+ if (col_lower_[inds[i]] == -kHighsInf) return;
2579
+
2580
+ maxactivity += col_lower_[inds[i]] * vals[i];
2581
+ }
2582
+ }
2583
+
2584
+ HighsCDouble maxabscoef = maxactivity - rhs;
2585
+ if (maxabscoef > mipsolver->mipdata_->feastol) {
2586
+ HighsCDouble upper = rhs;
2587
+ HighsInt tightened = 0;
2588
+ for (HighsInt i = 0; i != len; ++i) {
2589
+ if (mipsolver->isColContinuous(inds[i])) continue;
2590
+ if (vals[i] > maxabscoef) {
2591
+ HighsCDouble delta = vals[i] - maxabscoef;
2592
+ upper -= delta * col_upper_[inds[i]];
2593
+ vals[i] = double(maxabscoef);
2594
+ ++tightened;
2595
+ } else if (vals[i] < -maxabscoef) {
2596
+ HighsCDouble delta = -vals[i] - maxabscoef;
2597
+ upper += delta * col_lower_[inds[i]];
2598
+ vals[i] = -double(maxabscoef);
2599
+ ++tightened;
2600
+ }
2601
+ }
2602
+
2603
+ if (tightened != 0) {
2604
+ // printf("tightened %" HIGHSINT_FORMAT " coefficients, rhs changed from
2605
+ // %g to %g\n",
2606
+ // tightened, rhs, double(upper));
2607
+ rhs = double(upper);
2608
+ }
2609
+ }
2610
+ }
2611
+
2612
+ double HighsDomain::getMinCutActivity(const HighsCutPool& cutpool,
2613
+ HighsInt cut) const {
2614
+ for (auto& cutpoolprop : cutpoolpropagation) {
2615
+ if (cutpoolprop.cutpool == &cutpool) {
2616
+ // assert((cutpoolprop.propagatecutflags_[cut] & 2) == 0);
2617
+
2618
+ return cut < (HighsInt)cutpoolprop.propagatecutflags_.size() &&
2619
+ (cutpoolprop.propagatecutflags_[cut] & 2) == 0 &&
2620
+ cutpoolprop.activitycutsinf_[cut] == 0
2621
+ ? double(cutpoolprop.activitycuts_[cut])
2622
+ : -kHighsInf;
2623
+ }
2624
+ }
2625
+
2626
+ return -kHighsInf;
2627
+ }
2628
+
2629
+ bool HighsDomain::isFixing(const HighsDomainChange& domchg) const {
2630
+ double otherbound = domchg.boundtype == HighsBoundType::kUpper
2631
+ ? col_lower_[domchg.column]
2632
+ : col_upper_[domchg.column];
2633
+ return std::fabs(domchg.boundval - otherbound) <=
2634
+ mipsolver->mipdata_->epsilon;
2635
+ }
2636
+
2637
+ HighsDomainChange HighsDomain::flip(const HighsDomainChange& domchg) const {
2638
+ if (domchg.boundtype == HighsBoundType::kLower) {
2639
+ HighsDomainChange flipped{domchg.boundval - mipsolver->mipdata_->feastol,
2640
+ domchg.column, HighsBoundType::kUpper};
2641
+ if (mipsolver->isColIntegral(domchg.column))
2642
+ flipped.boundval = std::floor(flipped.boundval);
2643
+ return flipped;
2644
+ } else {
2645
+ HighsDomainChange flipped{domchg.boundval + mipsolver->mipdata_->feastol,
2646
+ domchg.column, HighsBoundType::kLower};
2647
+ if (mipsolver->isColIntegral(domchg.column))
2648
+ flipped.boundval = std::ceil(flipped.boundval);
2649
+ return flipped;
2650
+ }
2651
+ }
2652
+
2653
+ double HighsDomain::feastol() const { return mipsolver->mipdata_->feastol; }
2654
+
2655
+ HighsDomain::ConflictSet::ConflictSet(HighsDomain& localdom_)
2656
+ : localdom(localdom_),
2657
+ globaldom(localdom.mipsolver->mipdata_->domain),
2658
+ reasonSideFrontier(),
2659
+ reconvergenceFrontier(),
2660
+ resolveQueue(),
2661
+ resolvedDomainChanges() {}
2662
+
2663
+ static inline double computePrio(double val, double bound, double globalbound,
2664
+ int64_t numnodes) {
2665
+ return std::fabs(val * (bound - globalbound) *
2666
+ static_cast<double>(1 + numnodes));
2667
+ }
2668
+
2669
+ bool HighsDomain::ConflictSet::explainBoundChangeGeq(
2670
+ const std::set<LocalDomChg>& currentFrontier, const LocalDomChg& domchg,
2671
+ const HighsInt* inds, const double* vals, HighsInt len, double rhs,
2672
+ double maxAct) {
2673
+ if (maxAct == kHighsInf) return false;
2674
+
2675
+ // get the coefficient value of the column for which we want to explain
2676
+ // the bound change
2677
+ double domchgVal = 0;
2678
+
2679
+ resolveBuffer.reserve(len);
2680
+ resolveBuffer.clear();
2681
+ const auto& nodequeue = localdom.mipsolver->mipdata_->nodequeue;
2682
+ HighsCDouble M = maxAct;
2683
+ for (HighsInt i = 0; i < len; ++i) {
2684
+ HighsInt col = inds[i];
2685
+
2686
+ if (col == domchg.domchg.column) {
2687
+ domchgVal = vals[i];
2688
+ continue;
2689
+ }
2690
+
2691
+ ResolveCandidate cand;
2692
+ cand.valuePos = i;
2693
+
2694
+ if (vals[i] > 0) {
2695
+ double ub = localdom.getColUpperPos(col, domchg.pos, cand.boundPos);
2696
+ if (globaldom.col_upper_[col] <= ub || cand.boundPos == -1) continue;
2697
+ auto it =
2698
+ currentFrontier.find(LocalDomChg{cand.boundPos, HighsDomainChange()});
2699
+ if (it != currentFrontier.end()) {
2700
+ cand.baseBound = it->domchg.boundval;
2701
+ if (cand.baseBound != globaldom.col_upper_[col])
2702
+ M += vals[i] * (cand.baseBound - globaldom.col_upper_[col]);
2703
+ if (cand.baseBound <= ub) continue;
2704
+ } else
2705
+ cand.baseBound = globaldom.col_upper_[col];
2706
+
2707
+ cand.delta = vals[i] * (ub - cand.baseBound);
2708
+ cand.prio = computePrio(vals[i], ub, globaldom.col_upper_[col],
2709
+ nodequeue.numNodesDown(col));
2710
+ } else {
2711
+ double lb = localdom.getColLowerPos(col, domchg.pos, cand.boundPos);
2712
+ if (globaldom.col_lower_[col] >= lb || cand.boundPos == -1) continue;
2713
+ auto it =
2714
+ currentFrontier.find(LocalDomChg{cand.boundPos, HighsDomainChange()});
2715
+
2716
+ if (it != currentFrontier.end()) {
2717
+ cand.baseBound = it->domchg.boundval;
2718
+ if (cand.baseBound != globaldom.col_lower_[col])
2719
+ M += vals[i] * (cand.baseBound - globaldom.col_lower_[col]);
2720
+ if (cand.baseBound >= lb) continue;
2721
+ } else
2722
+ cand.baseBound = globaldom.col_lower_[col];
2723
+
2724
+ cand.delta = vals[i] * (lb - cand.baseBound);
2725
+ cand.prio = computePrio(vals[i], lb, globaldom.col_lower_[col],
2726
+ nodequeue.numNodesUp(col));
2727
+ }
2728
+
2729
+ resolveBuffer.push_back(cand);
2730
+ }
2731
+
2732
+ if (domchgVal == 0) return false;
2733
+
2734
+ pdqsort(resolveBuffer.begin(), resolveBuffer.end());
2735
+
2736
+ // to explain the bound change we start from the bound constraint,
2737
+ // multiply it by the columns coefficient in the constraint. Then the
2738
+ // bound constraint is a0 * x0 >= b0 and the constraint
2739
+ // a0 * x0 + \sum ai * xi >= b. Let the max activity of \sum ai xi be M,
2740
+ // then the constraint yields the bound a0 * x0 >= b - M. If M is
2741
+ // sufficiently small the bound constraint is implied. Therefore we
2742
+ // decrease M by updating it with the stronger local bounds until
2743
+ // M <= b - b0 holds.
2744
+ double b0 = domchg.domchg.boundval;
2745
+ if (!localdom.mipsolver->isColContinuous(domchg.domchg.column)) {
2746
+ // in case of an integral variable the bound was rounded and can be
2747
+ // relaxed by 1-feastol. We use 1 - 10 * feastol for numerical safety.
2748
+ if (domchg.domchg.boundtype == HighsBoundType::kLower)
2749
+ b0 -= (1.0 - 10 * localdom.mipsolver->mipdata_->feastol);
2750
+ else
2751
+ b0 += (1.0 - 10 * localdom.mipsolver->mipdata_->feastol);
2752
+ } else {
2753
+ // for a continuous variable we relax the bound by epsilon to
2754
+ // accommodate for tiny rounding errors
2755
+ if (domchg.domchg.boundtype == HighsBoundType::kLower)
2756
+ b0 -= localdom.mipsolver->mipdata_->epsilon;
2757
+ else
2758
+ b0 += localdom.mipsolver->mipdata_->epsilon;
2759
+ }
2760
+
2761
+ // now multiply the bound constraint with the coefficient value in the
2762
+ // constraint to obtain b0
2763
+ b0 *= domchgVal;
2764
+
2765
+ // compute the lower bound of M that is necessary
2766
+ double Mupper = rhs - b0;
2767
+
2768
+ // M is the current residual activity initially
2769
+ if (domchgVal < 0)
2770
+ M -= domchgVal * globaldom.col_lower_[domchg.domchg.column];
2771
+ else
2772
+ M -= domchgVal * globaldom.col_upper_[domchg.domchg.column];
2773
+
2774
+ return resolveLinearGeq(M, Mupper, vals);
2775
+ }
2776
+
2777
+ bool HighsDomain::ConflictSet::explainBoundChangeLeq(
2778
+ const std::set<LocalDomChg>& currentFrontier, const LocalDomChg& domchg,
2779
+ const HighsInt* inds, const double* vals, HighsInt len, double rhs,
2780
+ double minAct) {
2781
+ if (minAct == -kHighsInf) return false;
2782
+ // get the coefficient value of the column for which we want to explain
2783
+ // the bound change
2784
+ double domchgVal = 0;
2785
+
2786
+ resolveBuffer.reserve(len);
2787
+ resolveBuffer.clear();
2788
+ const auto& nodequeue = localdom.mipsolver->mipdata_->nodequeue;
2789
+ HighsCDouble M = minAct;
2790
+ for (HighsInt i = 0; i < len; ++i) {
2791
+ HighsInt col = inds[i];
2792
+
2793
+ if (col == domchg.domchg.column) {
2794
+ domchgVal = vals[i];
2795
+ continue;
2796
+ }
2797
+
2798
+ ResolveCandidate cand;
2799
+ cand.valuePos = i;
2800
+
2801
+ if (vals[i] > 0) {
2802
+ double lb = localdom.getColLowerPos(col, domchg.pos, cand.boundPos);
2803
+ if (globaldom.col_lower_[col] >= lb || cand.boundPos == -1) continue;
2804
+ auto it =
2805
+ currentFrontier.find(LocalDomChg{cand.boundPos, HighsDomainChange()});
2806
+
2807
+ if (it != currentFrontier.end()) {
2808
+ cand.baseBound = it->domchg.boundval;
2809
+ if (cand.baseBound != globaldom.col_lower_[col])
2810
+ M += vals[i] * (cand.baseBound - globaldom.col_lower_[col]);
2811
+ if (cand.baseBound >= lb) continue;
2812
+ } else
2813
+ cand.baseBound = globaldom.col_lower_[col];
2814
+
2815
+ cand.delta = vals[i] * (lb - cand.baseBound);
2816
+ cand.prio = computePrio(vals[i], lb, globaldom.col_lower_[col],
2817
+ nodequeue.numNodesUp(col));
2818
+ } else {
2819
+ double ub = localdom.getColUpperPos(col, domchg.pos, cand.boundPos);
2820
+ if (globaldom.col_upper_[col] <= ub || cand.boundPos == -1) continue;
2821
+ auto it =
2822
+ currentFrontier.find(LocalDomChg{cand.boundPos, HighsDomainChange()});
2823
+ if (it != currentFrontier.end()) {
2824
+ cand.baseBound = it->domchg.boundval;
2825
+ if (cand.baseBound != globaldom.col_upper_[col])
2826
+ M += vals[i] * (cand.baseBound - globaldom.col_upper_[col]);
2827
+ if (cand.baseBound <= ub) continue;
2828
+ } else
2829
+ cand.baseBound = globaldom.col_upper_[col];
2830
+
2831
+ cand.delta = vals[i] * (ub - cand.baseBound);
2832
+ cand.prio = computePrio(vals[i], ub, globaldom.col_upper_[col],
2833
+ nodequeue.numNodesDown(col));
2834
+ }
2835
+
2836
+ resolveBuffer.push_back(cand);
2837
+ }
2838
+
2839
+ if (domchgVal == 0) return false;
2840
+
2841
+ pdqsort(resolveBuffer.begin(), resolveBuffer.end());
2842
+
2843
+ assert(domchgVal != 0);
2844
+
2845
+ // to explain the bound change we start from the bound constraint,
2846
+ // multiply it by the columns coefficient in the constraint. Then the
2847
+ // bound constraint is a0 * x0 <= b0 and the constraint
2848
+ // a0 * x0 + \sum ai * xi <= b. Let the min activity of \sum ai xi be M,
2849
+ // then the constraint yields the bound a0 * x0 <= b - M. If M is
2850
+ // sufficiently large the bound constraint is implied. Therefore we
2851
+ // increase M by updating it with the stronger local bounds until
2852
+ // M >= b - b0 holds.
2853
+ double b0 = domchg.domchg.boundval;
2854
+ if (!localdom.mipsolver->isColContinuous(domchg.domchg.column)) {
2855
+ // in case of an integral variable the bound was rounded and can be
2856
+ // relaxed by 1-feastol. We use 1 - 10 * feastol for numerical safety
2857
+ if (domchg.domchg.boundtype == HighsBoundType::kLower)
2858
+ b0 -= (1.0 - 10 * localdom.mipsolver->mipdata_->feastol);
2859
+ else
2860
+ b0 += (1.0 - 10 * localdom.mipsolver->mipdata_->feastol);
2861
+ } else {
2862
+ // for a continuous variable we relax the bound by epsilon to
2863
+ // accommodate for tiny rounding errors
2864
+ if (domchg.domchg.boundtype == HighsBoundType::kLower)
2865
+ b0 -= localdom.mipsolver->mipdata_->epsilon;
2866
+ else
2867
+ b0 += localdom.mipsolver->mipdata_->epsilon;
2868
+ }
2869
+
2870
+ // now multiply the bound constraint with the coefficient value in the
2871
+ // constraint to obtain b0
2872
+ b0 *= domchgVal;
2873
+
2874
+ // compute the lower bound of M that is necessary
2875
+ double Mlower = rhs - b0;
2876
+
2877
+ // M is the global residual activity initially
2878
+ if (domchgVal < 0)
2879
+ M -= domchgVal * globaldom.col_upper_[domchg.domchg.column];
2880
+ else
2881
+ M -= domchgVal * globaldom.col_lower_[domchg.domchg.column];
2882
+
2883
+ return resolveLinearLeq(M, Mlower, vals);
2884
+ }
2885
+
2886
+ bool HighsDomain::ConflictSet::resolveLinearGeq(HighsCDouble M, double Mupper,
2887
+ const double* vals) {
2888
+ resolvedDomainChanges.clear();
2889
+ double covered = double(M - Mupper);
2890
+ if (covered > 0) {
2891
+ for (const auto& reasonDomchg : resolveBuffer) {
2892
+ LocalDomChg locdomchg;
2893
+ locdomchg.pos = reasonDomchg.boundPos;
2894
+ locdomchg.domchg = localdom.domchgstack_[reasonDomchg.boundPos];
2895
+ M += reasonDomchg.delta;
2896
+ resolvedDomainChanges.push_back(locdomchg);
2897
+ assert(resolvedDomainChanges.back().pos >= 0);
2898
+ assert(resolvedDomainChanges.back().pos <
2899
+ (HighsInt)localdom.domchgstack_.size());
2900
+ covered = double(M - Mupper);
2901
+ if (covered <= 0) break;
2902
+ }
2903
+
2904
+ if (covered > 0) return false;
2905
+
2906
+ if (covered < -localdom.feastol()) {
2907
+ // there is room for relaxing bounds / dropping unneeded bound changes
2908
+ // from the explanation
2909
+ // HighsInt numRelaxed = 0;
2910
+ // HighsInt numDropped = 0;
2911
+ for (HighsInt k = resolvedDomainChanges.size() - 1; k >= 0; --k) {
2912
+ ResolveCandidate& reasonDomchg = resolveBuffer[k];
2913
+ LocalDomChg& locdomchg = resolvedDomainChanges[k];
2914
+ HighsInt i = reasonDomchg.valuePos;
2915
+ HighsInt col = locdomchg.domchg.column;
2916
+ if (locdomchg.domchg.boundtype == HighsBoundType::kLower) {
2917
+ double lb = locdomchg.domchg.boundval;
2918
+ double glb = reasonDomchg.baseBound;
2919
+ double relaxLb =
2920
+ double(((Mupper - (M - reasonDomchg.delta)) / vals[i]) + glb);
2921
+ if (!localdom.mipsolver->isColContinuous(col))
2922
+ relaxLb = std::ceil(relaxLb);
2923
+
2924
+ if (relaxLb - lb >= -localdom.feastol()) continue;
2925
+
2926
+ locdomchg.domchg.boundval = relaxLb;
2927
+
2928
+ if (relaxLb - glb <= localdom.mipsolver->mipdata_->epsilon) {
2929
+ // domain change can be fully removed from conflict
2930
+ HighsInt last = resolvedDomainChanges.size() - 1;
2931
+ std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]);
2932
+ resolvedDomainChanges.resize(last);
2933
+
2934
+ M -= reasonDomchg.delta;
2935
+ // ++numDropped;
2936
+ } else {
2937
+ while (relaxLb <= localdom.prevboundval_[locdomchg.pos].first)
2938
+ locdomchg.pos = localdom.prevboundval_[locdomchg.pos].second;
2939
+
2940
+ // bound can be relaxed
2941
+ M += vals[i] * (relaxLb - lb);
2942
+ // ++numRelaxed;
2943
+ }
2944
+
2945
+ covered = double(M - Mupper);
2946
+ if (covered >= -localdom.feastol()) break;
2947
+ } else {
2948
+ double ub = locdomchg.domchg.boundval;
2949
+ double gub = reasonDomchg.baseBound;
2950
+ double relaxUb =
2951
+ double(((Mupper - (M - reasonDomchg.delta)) / vals[i]) + gub);
2952
+ if (!localdom.mipsolver->isColContinuous(col))
2953
+ relaxUb = std::floor(relaxUb);
2954
+
2955
+ if (relaxUb - ub <= localdom.feastol()) continue;
2956
+
2957
+ locdomchg.domchg.boundval = relaxUb;
2958
+
2959
+ if (relaxUb - gub >= -localdom.mipsolver->mipdata_->epsilon) {
2960
+ // domain change can be fully removed from conflict
2961
+ HighsInt last = resolvedDomainChanges.size() - 1;
2962
+ std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]);
2963
+ resolvedDomainChanges.resize(last);
2964
+
2965
+ M -= reasonDomchg.delta;
2966
+ // ++numDropped;
2967
+ } else {
2968
+ // bound can be relaxed
2969
+ while (relaxUb >= localdom.prevboundval_[locdomchg.pos].first)
2970
+ locdomchg.pos = localdom.prevboundval_[locdomchg.pos].second;
2971
+
2972
+ M += vals[i] * (relaxUb - ub);
2973
+ // ++numRelaxed;
2974
+ }
2975
+
2976
+ covered = double(M - Mupper);
2977
+ if (covered >= -localdom.feastol()) break;
2978
+ }
2979
+ }
2980
+
2981
+ // if (numRelaxed + numDropped)
2982
+ // printf("relaxed %d and dropped %d of %d resolved domain changes\n",
2983
+ // (int)numRelaxed, (int)numDropped,
2984
+ // (int)resolvedDomainChanges.size());
2985
+
2986
+ assert(covered <= localdom.mipsolver->mipdata_->feastol);
2987
+ }
2988
+ }
2989
+
2990
+ return true;
2991
+ }
2992
+
2993
+ bool HighsDomain::ConflictSet::resolveLinearLeq(HighsCDouble M, double Mlower,
2994
+ const double* vals) {
2995
+ resolvedDomainChanges.clear();
2996
+ double covered = double(M - Mlower);
2997
+ if (covered < 0) {
2998
+ for (const auto& reasonDomchg : resolveBuffer) {
2999
+ LocalDomChg locdomchg;
3000
+ locdomchg.pos = reasonDomchg.boundPos;
3001
+ locdomchg.domchg = localdom.domchgstack_[reasonDomchg.boundPos];
3002
+ M += reasonDomchg.delta;
3003
+ resolvedDomainChanges.push_back(locdomchg);
3004
+ assert(resolvedDomainChanges.back().pos >= 0);
3005
+ assert(resolvedDomainChanges.back().pos <
3006
+ (HighsInt)localdom.domchgstack_.size());
3007
+ covered = double(M - Mlower);
3008
+ if (covered >= 0) break;
3009
+ }
3010
+
3011
+ if (covered < 0) {
3012
+ // printf("local bounds reach only value of %.12g, need at least
3013
+ // %.12g\n",
3014
+ // M, Mlower);
3015
+ return false;
3016
+ }
3017
+
3018
+ if (covered > localdom.feastol()) {
3019
+ // there is room for relaxing bounds / dropping unneeded bound changes
3020
+ // from the explanation
3021
+ // HighsInt numRelaxed = 0;
3022
+ // HighsInt numDropped = 0;
3023
+ for (HighsInt k = resolvedDomainChanges.size() - 1; k >= 0; --k) {
3024
+ ResolveCandidate& reasonDomchg = resolveBuffer[k];
3025
+ LocalDomChg& locdomchg = resolvedDomainChanges[k];
3026
+ HighsInt i = reasonDomchg.valuePos;
3027
+ HighsInt col = locdomchg.domchg.column;
3028
+ if (locdomchg.domchg.boundtype == HighsBoundType::kLower) {
3029
+ double lb = locdomchg.domchg.boundval;
3030
+ double glb = reasonDomchg.baseBound;
3031
+ double relaxLb =
3032
+ double(((Mlower - (M - reasonDomchg.delta)) / vals[i]) + glb);
3033
+ if (!localdom.mipsolver->isColContinuous(col))
3034
+ relaxLb = std::ceil(relaxLb);
3035
+
3036
+ if (relaxLb - lb >= -localdom.feastol()) continue;
3037
+
3038
+ locdomchg.domchg.boundval = relaxLb;
3039
+
3040
+ if (relaxLb - glb <= localdom.mipsolver->mipdata_->epsilon) {
3041
+ // domain change can be fully removed from conflict
3042
+ HighsInt last = resolvedDomainChanges.size() - 1;
3043
+ std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]);
3044
+ resolvedDomainChanges.resize(last);
3045
+
3046
+ M -= reasonDomchg.delta;
3047
+ // ++numDropped;
3048
+ } else {
3049
+ // bound can be relaxed
3050
+ while (relaxLb <= localdom.prevboundval_[locdomchg.pos].first)
3051
+ locdomchg.pos = localdom.prevboundval_[locdomchg.pos].second;
3052
+
3053
+ M += vals[i] * (relaxLb - lb);
3054
+ // ++numRelaxed;
3055
+ }
3056
+
3057
+ covered = double(M - Mlower);
3058
+ if (covered <= localdom.feastol()) break;
3059
+ } else {
3060
+ double ub = locdomchg.domchg.boundval;
3061
+ double gub = reasonDomchg.baseBound;
3062
+ double relaxUb =
3063
+ double(((Mlower - (M - reasonDomchg.delta)) / vals[i]) + gub);
3064
+ if (!localdom.mipsolver->isColContinuous(col))
3065
+ relaxUb = std::floor(relaxUb);
3066
+
3067
+ if (relaxUb - ub <= localdom.feastol()) continue;
3068
+
3069
+ locdomchg.domchg.boundval = relaxUb;
3070
+
3071
+ if (relaxUb - gub >= -localdom.mipsolver->mipdata_->epsilon) {
3072
+ // domain change can be fully removed from conflict
3073
+ HighsInt last = resolvedDomainChanges.size() - 1;
3074
+ std::swap(resolvedDomainChanges[last], resolvedDomainChanges[k]);
3075
+ resolvedDomainChanges.resize(last);
3076
+
3077
+ M -= reasonDomchg.delta;
3078
+ // ++numDropped;
3079
+ } else {
3080
+ // bound can be relaxed
3081
+ while (relaxUb >= localdom.prevboundval_[locdomchg.pos].first)
3082
+ locdomchg.pos = localdom.prevboundval_[locdomchg.pos].second;
3083
+
3084
+ M += vals[i] * (relaxUb - ub);
3085
+ // ++numRelaxed;
3086
+ }
3087
+
3088
+ covered = double(M - Mlower);
3089
+ if (covered <= localdom.feastol()) break;
3090
+ }
3091
+ }
3092
+
3093
+ // if (numRelaxed + numDropped)
3094
+ // printf("relaxed %d and dropped %d of %d resolved domain changes\n",
3095
+ // (int)numRelaxed, (int)numDropped,
3096
+ // (int)resolvedDomainChanges.size());
3097
+
3098
+ assert(covered >= -localdom.mipsolver->mipdata_->feastol);
3099
+ }
3100
+ }
3101
+ return true;
3102
+ }
3103
+
3104
+ bool HighsDomain::ConflictSet::explainInfeasibility() {
3105
+ switch (localdom.infeasible_reason.type) {
3106
+ case Reason::kUnknown:
3107
+ case Reason::kBranching:
3108
+ return false;
3109
+ case Reason::kConflictingBounds: {
3110
+ resolvedDomainChanges.clear();
3111
+ HighsInt conflictingBoundPos = localdom.infeasible_reason.index;
3112
+ HighsInt col = localdom.domchgstack_[conflictingBoundPos].column;
3113
+
3114
+ resolvedDomainChanges.push_back(LocalDomChg{
3115
+ conflictingBoundPos, localdom.domchgstack_[conflictingBoundPos]});
3116
+
3117
+ HighsInt otherBoundPos;
3118
+ if (localdom.domchgstack_[conflictingBoundPos].boundtype ==
3119
+ HighsBoundType::kLower) {
3120
+ double ub =
3121
+ localdom.getColUpperPos(col, conflictingBoundPos, otherBoundPos);
3122
+ assert(localdom.domchgstack_[conflictingBoundPos].boundval - ub >
3123
+ +localdom.mipsolver->mipdata_->feastol);
3124
+ } else {
3125
+ double lb =
3126
+ localdom.getColLowerPos(col, conflictingBoundPos, otherBoundPos);
3127
+ assert(localdom.domchgstack_[conflictingBoundPos].boundval - lb <
3128
+ -localdom.mipsolver->mipdata_->feastol);
3129
+ }
3130
+ if (otherBoundPos != -1)
3131
+ resolvedDomainChanges.push_back(
3132
+ LocalDomChg{otherBoundPos, localdom.domchgstack_[otherBoundPos]});
3133
+ return true;
3134
+ }
3135
+ case Reason::kCliqueTable:
3136
+ assert(false);
3137
+ return false;
3138
+ case Reason::kModelRowLower: {
3139
+ HighsInt rowIndex = localdom.infeasible_reason.index;
3140
+
3141
+ // retrieve the matrix values of the cut
3142
+ HighsInt len;
3143
+ const HighsInt* inds;
3144
+ const double* vals;
3145
+ localdom.mipsolver->mipdata_->getRow(rowIndex, len, inds, vals);
3146
+
3147
+ double maxAct = globaldom.getMaxActivity(rowIndex);
3148
+
3149
+ return explainInfeasibilityGeq(
3150
+ inds, vals, len, localdom.mipsolver->rowLower(rowIndex), maxAct);
3151
+ }
3152
+ case Reason::kModelRowUpper: {
3153
+ HighsInt rowIndex = localdom.infeasible_reason.index;
3154
+
3155
+ // retrieve the matrix values of the cut
3156
+ HighsInt len;
3157
+ const HighsInt* inds;
3158
+ const double* vals;
3159
+ localdom.mipsolver->mipdata_->getRow(rowIndex, len, inds, vals);
3160
+
3161
+ double minAct = globaldom.getMinActivity(rowIndex);
3162
+
3163
+ return explainInfeasibilityLeq(
3164
+ inds, vals, len, localdom.mipsolver->rowUpper(rowIndex), minAct);
3165
+ }
3166
+ case Reason::kObjective: {
3167
+ HighsInt len;
3168
+ const HighsInt* inds;
3169
+ const double* vals;
3170
+ double rhs;
3171
+
3172
+ localdom.objProp_.getPropagationConstraint(localdom.infeasible_pos, vals,
3173
+ inds, len, rhs);
3174
+
3175
+ HighsInt ninfmin;
3176
+ HighsCDouble minAct;
3177
+ globaldom.computeMinActivity(0, len, inds, vals, ninfmin, minAct);
3178
+ // This case should only happen when a globally unbounded column is
3179
+ // bounded in the local domain, e.g., by a branching choice in some
3180
+ // heuristic.
3181
+ if (ninfmin > 0) return false;
3182
+
3183
+ return explainInfeasibilityLeq(inds, vals, len, rhs, double(minAct));
3184
+ }
3185
+ default:
3186
+ assert(localdom.infeasible_reason.type >= 0);
3187
+ assert(localdom.infeasible_reason.type <
3188
+ HighsInt(localdom.cutpoolpropagation.size() +
3189
+ localdom.conflictPoolPropagation.size()));
3190
+
3191
+ if (localdom.infeasible_reason.type <
3192
+ (HighsInt)localdom.cutpoolpropagation.size()) {
3193
+ HighsInt cutpoolIndex = localdom.infeasible_reason.type;
3194
+ HighsInt cutIndex = localdom.infeasible_reason.index;
3195
+
3196
+ // retrieve the matrix values of the cut
3197
+ HighsInt len;
3198
+ const HighsInt* inds;
3199
+ const double* vals;
3200
+ localdom.cutpoolpropagation[cutpoolIndex].cutpool->getCut(cutIndex, len,
3201
+ inds, vals);
3202
+
3203
+ double minAct = globaldom.getMinCutActivity(
3204
+ *localdom.cutpoolpropagation[cutpoolIndex].cutpool, cutIndex);
3205
+
3206
+ return explainInfeasibilityLeq(inds, vals, len,
3207
+ localdom.cutpoolpropagation[cutpoolIndex]
3208
+ .cutpool->getRhs()[cutIndex],
3209
+ minAct);
3210
+ } else {
3211
+ HighsInt conflictPoolIndex = localdom.infeasible_reason.type -
3212
+ localdom.cutpoolpropagation.size();
3213
+ HighsInt conflictIndex = localdom.infeasible_reason.index;
3214
+
3215
+ if (localdom.conflictPoolPropagation[conflictPoolIndex]
3216
+ .conflictFlag_[conflictIndex] &
3217
+ 8)
3218
+ return false;
3219
+
3220
+ // retrieve the conflict entries
3221
+ auto conflictRange =
3222
+ localdom.conflictPoolPropagation[conflictPoolIndex]
3223
+ .conflictpool_->getConflictRanges()[conflictIndex];
3224
+ const HighsDomainChange* conflict =
3225
+ localdom.conflictPoolPropagation[conflictPoolIndex]
3226
+ .conflictpool_->getConflictEntryVector()
3227
+ .data() +
3228
+ conflictRange.first;
3229
+ HighsInt len = conflictRange.second - conflictRange.first;
3230
+
3231
+ return explainInfeasibilityConflict(conflict, len);
3232
+ }
3233
+ }
3234
+ }
3235
+
3236
+ bool HighsDomain::ConflictSet::explainInfeasibilityConflict(
3237
+ const HighsDomainChange* conflict, HighsInt len) {
3238
+ resolvedDomainChanges.clear();
3239
+ for (HighsInt i = 0; i < len; ++i) {
3240
+ if (globaldom.isActive(conflict[i])) continue;
3241
+
3242
+ HighsInt pos;
3243
+ if (conflict[i].boundtype == HighsBoundType::kLower) {
3244
+ double lb = localdom.getColLowerPos(conflict[i].column,
3245
+ localdom.infeasible_pos, pos);
3246
+ if (pos == -1 || lb < conflict[i].boundval) return false;
3247
+
3248
+ while (localdom.prevboundval_[pos].first >= conflict[i].boundval) {
3249
+ pos = localdom.prevboundval_[pos].second;
3250
+ // since we checked that the bound value is not active globally and is
3251
+ // active for the local domain at pos
3252
+ // pos should never become -1
3253
+ assert(pos != -1);
3254
+ }
3255
+ } else {
3256
+ double ub = localdom.getColUpperPos(conflict[i].column,
3257
+ localdom.infeasible_pos, pos);
3258
+ if (pos == -1 || ub > conflict[i].boundval) return false;
3259
+
3260
+ while (localdom.prevboundval_[pos].first <= conflict[i].boundval) {
3261
+ pos = localdom.prevboundval_[pos].second;
3262
+ // since we checked that the bound value is not active globally and is
3263
+ // active for the local domain at pos
3264
+ // pos should never become -1
3265
+ assert(pos != -1);
3266
+ }
3267
+ }
3268
+
3269
+ resolvedDomainChanges.push_back(LocalDomChg{pos, conflict[i]});
3270
+ }
3271
+
3272
+ return true;
3273
+ }
3274
+
3275
+ bool HighsDomain::ConflictSet::explainInfeasibilityGeq(const HighsInt* inds,
3276
+ const double* vals,
3277
+ HighsInt len, double rhs,
3278
+ double maxAct) {
3279
+ if (maxAct == kHighsInf) return false;
3280
+
3281
+ HighsInt infeasible_pos = kHighsIInf;
3282
+ if (localdom.infeasible_) infeasible_pos = localdom.infeasible_pos;
3283
+
3284
+ resolveBuffer.reserve(len);
3285
+ resolveBuffer.clear();
3286
+ const auto& nodequeue = localdom.mipsolver->mipdata_->nodequeue;
3287
+ for (HighsInt i = 0; i < len; ++i) {
3288
+ HighsInt col = inds[i];
3289
+
3290
+ ResolveCandidate cand;
3291
+ cand.valuePos = i;
3292
+
3293
+ if (vals[i] > 0) {
3294
+ double ub = localdom.getColUpperPos(col, infeasible_pos, cand.boundPos);
3295
+ cand.baseBound = globaldom.col_upper_[col];
3296
+ if (cand.baseBound <= ub || cand.boundPos == -1) continue;
3297
+ cand.delta = vals[i] * (ub - cand.baseBound);
3298
+ cand.prio = computePrio(vals[i], ub, globaldom.col_upper_[col],
3299
+ nodequeue.numNodesDown(col));
3300
+ } else {
3301
+ double lb = localdom.getColLowerPos(col, infeasible_pos, cand.boundPos);
3302
+ cand.baseBound = globaldom.col_lower_[col];
3303
+ if (cand.baseBound >= lb || cand.boundPos == -1) continue;
3304
+ cand.delta = vals[i] * (lb - cand.baseBound);
3305
+ cand.prio = computePrio(vals[i], lb, globaldom.col_lower_[col],
3306
+ nodequeue.numNodesUp(col));
3307
+ }
3308
+
3309
+ resolveBuffer.push_back(cand);
3310
+ }
3311
+
3312
+ pdqsort(resolveBuffer.begin(), resolveBuffer.end());
3313
+
3314
+ // compute the lower bound of M that is necessary
3315
+ double Mupper = rhs - std::max(10.0, std::fabs(rhs)) *
3316
+ localdom.mipsolver->mipdata_->feastol;
3317
+
3318
+ assert(reasonSideFrontier.empty());
3319
+ return resolveLinearGeq(maxAct, Mupper, vals);
3320
+ }
3321
+
3322
+ bool HighsDomain::ConflictSet::explainInfeasibilityLeq(const HighsInt* inds,
3323
+ const double* vals,
3324
+ HighsInt len, double rhs,
3325
+ double minAct) {
3326
+ if (minAct == -kHighsInf) return false;
3327
+
3328
+ HighsInt infeasible_pos = kHighsIInf;
3329
+ if (localdom.infeasible_) infeasible_pos = localdom.infeasible_pos;
3330
+
3331
+ resolveBuffer.reserve(len);
3332
+ resolveBuffer.clear();
3333
+ const auto& nodequeue = localdom.mipsolver->mipdata_->nodequeue;
3334
+ for (HighsInt i = 0; i < len; ++i) {
3335
+ HighsInt col = inds[i];
3336
+
3337
+ ResolveCandidate cand;
3338
+ cand.valuePos = i;
3339
+
3340
+ if (vals[i] > 0) {
3341
+ double lb = localdom.getColLowerPos(col, infeasible_pos, cand.boundPos);
3342
+ cand.baseBound = globaldom.col_lower_[col];
3343
+ if (cand.baseBound >= lb || cand.boundPos == -1) continue;
3344
+ cand.delta = vals[i] * (lb - cand.baseBound);
3345
+ cand.prio = computePrio(vals[i], lb, globaldom.col_lower_[col],
3346
+ nodequeue.numNodesUp(col));
3347
+ } else {
3348
+ double ub = localdom.getColUpperPos(col, infeasible_pos, cand.boundPos);
3349
+ cand.baseBound = globaldom.col_upper_[col];
3350
+ if (cand.baseBound <= ub || cand.boundPos == -1) continue;
3351
+ cand.delta = vals[i] * (ub - cand.baseBound);
3352
+ cand.prio = computePrio(vals[i], ub, globaldom.col_upper_[col],
3353
+ nodequeue.numNodesDown(col));
3354
+ }
3355
+
3356
+ resolveBuffer.push_back(cand);
3357
+ }
3358
+
3359
+ pdqsort(resolveBuffer.begin(), resolveBuffer.end());
3360
+
3361
+ // compute the lower bound of M that is necessary
3362
+ double Mlower = rhs + std::max(10.0, std::fabs(rhs)) *
3363
+ localdom.mipsolver->mipdata_->feastol;
3364
+
3365
+ return resolveLinearLeq(minAct, Mlower, vals);
3366
+ }
3367
+
3368
+ bool HighsDomain::ConflictSet::explainBoundChange(
3369
+ const std::set<LocalDomChg>& currentFrontier, LocalDomChg domchg) {
3370
+ switch (localdom.domchgreason_[domchg.pos].type) {
3371
+ case Reason::kUnknown:
3372
+ case Reason::kBranching:
3373
+ case Reason::kConflictingBounds:
3374
+ return false;
3375
+ case Reason::kCliqueTable: {
3376
+ HighsInt col = localdom.domchgreason_[domchg.pos].index >> 1;
3377
+ HighsInt val = localdom.domchgreason_[domchg.pos].index & 1;
3378
+ resolvedDomainChanges.clear();
3379
+ HighsInt boundPos;
3380
+ if (val) {
3381
+ assert(localdom.colLowerPos_[col] >= 0);
3382
+ assert(localdom.colLowerPos_[col] <
3383
+ (HighsInt)localdom.domchgstack_.size());
3384
+
3385
+ localdom.getColLowerPos(col, domchg.pos, boundPos);
3386
+ } else {
3387
+ assert(localdom.colUpperPos_[col] >= 0);
3388
+ assert(localdom.colUpperPos_[col] <
3389
+ (HighsInt)localdom.domchgstack_.size());
3390
+
3391
+ localdom.getColUpperPos(col, domchg.pos, boundPos);
3392
+ }
3393
+
3394
+ if (boundPos != -1)
3395
+ resolvedDomainChanges.push_back(
3396
+ LocalDomChg{boundPos, localdom.domchgstack_[boundPos]});
3397
+
3398
+ return true;
3399
+ }
3400
+ case Reason::kModelRowLower: {
3401
+ HighsInt rowIndex = localdom.domchgreason_[domchg.pos].index;
3402
+
3403
+ // retrieve the matrix values of the cut
3404
+ HighsInt len;
3405
+ const HighsInt* inds;
3406
+ const double* vals;
3407
+ localdom.mipsolver->mipdata_->getRow(rowIndex, len, inds, vals);
3408
+
3409
+ double maxAct = globaldom.getMaxActivity(rowIndex);
3410
+
3411
+ return explainBoundChangeGeq(currentFrontier, domchg, inds, vals, len,
3412
+ localdom.mipsolver->rowLower(rowIndex),
3413
+ maxAct);
3414
+ }
3415
+ case Reason::kModelRowUpper: {
3416
+ HighsInt rowIndex = localdom.domchgreason_[domchg.pos].index;
3417
+
3418
+ // retrieve the matrix values of the cut
3419
+ HighsInt len;
3420
+ const HighsInt* inds;
3421
+ const double* vals;
3422
+ localdom.mipsolver->mipdata_->getRow(rowIndex, len, inds, vals);
3423
+
3424
+ double minAct = globaldom.getMinActivity(rowIndex);
3425
+
3426
+ return explainBoundChangeLeq(currentFrontier, domchg, inds, vals, len,
3427
+ localdom.mipsolver->rowUpper(rowIndex),
3428
+ minAct);
3429
+ }
3430
+ case Reason::kObjective: {
3431
+ HighsInt len;
3432
+ const HighsInt* inds;
3433
+ const double* vals;
3434
+ double rhs;
3435
+
3436
+ localdom.objProp_.getPropagationConstraint(domchg.pos, vals, inds, len,
3437
+ rhs, domchg.domchg.column);
3438
+
3439
+ HighsInt ninfmin;
3440
+ HighsCDouble minAct;
3441
+ globaldom.computeMinActivity(0, len, inds, vals, ninfmin, minAct);
3442
+ assert(ninfmin <= 1);
3443
+ // todo: treat case with a single infinite contribution that propagated a
3444
+ // bound
3445
+ if (ninfmin == 1) return false;
3446
+
3447
+ return explainBoundChangeLeq(currentFrontier, domchg, inds, vals, len,
3448
+ rhs, double(minAct));
3449
+ }
3450
+ default:
3451
+ assert(localdom.domchgreason_[domchg.pos].type >= 0);
3452
+ assert(localdom.domchgreason_[domchg.pos].type <
3453
+ (HighsInt)(localdom.cutpoolpropagation.size() +
3454
+ localdom.conflictPoolPropagation.size()));
3455
+ if (localdom.domchgreason_[domchg.pos].type <
3456
+ (HighsInt)localdom.cutpoolpropagation.size()) {
3457
+ HighsInt cutpoolIndex = localdom.domchgreason_[domchg.pos].type;
3458
+ HighsInt cutIndex = localdom.domchgreason_[domchg.pos].index;
3459
+
3460
+ // retrieve the matrix values of the cut
3461
+ HighsInt len;
3462
+ const HighsInt* inds;
3463
+ const double* vals;
3464
+ localdom.cutpoolpropagation[cutpoolIndex].cutpool->getCut(cutIndex, len,
3465
+ inds, vals);
3466
+ double minAct = globaldom.getMinCutActivity(
3467
+ *localdom.cutpoolpropagation[cutpoolIndex].cutpool, cutIndex);
3468
+
3469
+ return explainBoundChangeLeq(currentFrontier, domchg, inds, vals, len,
3470
+ localdom.cutpoolpropagation[cutpoolIndex]
3471
+ .cutpool->getRhs()[cutIndex],
3472
+ minAct);
3473
+ } else {
3474
+ HighsInt conflictPoolIndex = localdom.domchgreason_[domchg.pos].type -
3475
+ localdom.cutpoolpropagation.size();
3476
+ HighsInt conflictIndex = localdom.domchgreason_[domchg.pos].index;
3477
+
3478
+ if (localdom.conflictPoolPropagation[conflictPoolIndex]
3479
+ .conflictFlag_[conflictIndex] &
3480
+ 8)
3481
+ break;
3482
+
3483
+ // retrieve the conflict entries
3484
+ auto conflictRange =
3485
+ localdom.conflictPoolPropagation[conflictPoolIndex]
3486
+ .conflictpool_->getConflictRanges()[conflictIndex];
3487
+ const HighsDomainChange* conflict =
3488
+ localdom.conflictPoolPropagation[conflictPoolIndex]
3489
+ .conflictpool_->getConflictEntryVector()
3490
+ .data() +
3491
+ conflictRange.first;
3492
+ HighsInt len = conflictRange.second - conflictRange.first;
3493
+
3494
+ return explainBoundChangeConflict(domchg, conflict, len);
3495
+ }
3496
+ }
3497
+
3498
+ return false;
3499
+ }
3500
+
3501
+ bool HighsDomain::ConflictSet::explainBoundChangeConflict(
3502
+ const LocalDomChg& locdomchg, const HighsDomainChange* conflict,
3503
+ HighsInt len) {
3504
+ resolvedDomainChanges.clear();
3505
+ auto domchg = localdom.flip(locdomchg.domchg);
3506
+ bool foundDomchg = false;
3507
+ for (HighsInt i = 0; i < len; ++i) {
3508
+ if (!foundDomchg && conflict[i].column == domchg.column &&
3509
+ conflict[i].boundtype == domchg.boundtype) {
3510
+ if (conflict[i].boundtype == HighsBoundType::kLower) {
3511
+ if (conflict[i].boundval <= domchg.boundval) {
3512
+ foundDomchg = true;
3513
+ continue;
3514
+ }
3515
+ } else {
3516
+ if (conflict[i].boundval >= domchg.boundval) {
3517
+ foundDomchg = true;
3518
+ continue;
3519
+ }
3520
+ }
3521
+ }
3522
+ if (globaldom.isActive(conflict[i])) continue;
3523
+
3524
+ HighsInt pos;
3525
+ if (conflict[i].boundtype == HighsBoundType::kLower) {
3526
+ double lb =
3527
+ localdom.getColLowerPos(conflict[i].column, locdomchg.pos - 1, pos);
3528
+
3529
+ if (pos == -1 || lb < conflict[i].boundval) return false;
3530
+
3531
+ while (localdom.prevboundval_[pos].first >= conflict[i].boundval) {
3532
+ pos = localdom.prevboundval_[pos].second;
3533
+ // since we checked that the bound value is not active globally and is
3534
+ // active for the local domain at pos
3535
+ // pos should never become -1
3536
+ assert(pos != -1);
3537
+ }
3538
+ } else {
3539
+ double ub =
3540
+ localdom.getColUpperPos(conflict[i].column, locdomchg.pos - 1, pos);
3541
+
3542
+ if (pos == -1 || ub > conflict[i].boundval) return false;
3543
+
3544
+ while (localdom.prevboundval_[pos].first <= conflict[i].boundval) {
3545
+ pos = localdom.prevboundval_[pos].second;
3546
+ // since we checked that the bound value is not active globally and is
3547
+ // active for the local domain at pos
3548
+ // pos should never become -1
3549
+ assert(pos != -1);
3550
+ }
3551
+ }
3552
+
3553
+ resolvedDomainChanges.push_back(
3554
+ LocalDomChg{pos, localdom.domchgstack_[pos]});
3555
+ }
3556
+
3557
+ return foundDomchg;
3558
+ }
3559
+
3560
+ void HighsDomain::ConflictSet::pushQueue(
3561
+ std::set<LocalDomChg>::iterator domchg) {
3562
+ resolveQueue.emplace_back(domchg);
3563
+ std::push_heap(
3564
+ resolveQueue.begin(), resolveQueue.end(),
3565
+ [](const std::set<LocalDomChg>::iterator& a,
3566
+ const std::set<LocalDomChg>::iterator& b) { return a->pos < b->pos; });
3567
+ }
3568
+
3569
+ std::set<HighsDomain::ConflictSet::LocalDomChg>::iterator
3570
+ HighsDomain::ConflictSet::popQueue() {
3571
+ assert(!resolveQueue.empty());
3572
+ std::pop_heap(
3573
+ resolveQueue.begin(), resolveQueue.end(),
3574
+ [](const std::set<LocalDomChg>::iterator& a,
3575
+ const std::set<LocalDomChg>::iterator& b) { return a->pos < b->pos; });
3576
+ std::set<LocalDomChg>::iterator elem = resolveQueue.back();
3577
+ resolveQueue.pop_back();
3578
+ return elem;
3579
+ }
3580
+
3581
+ void HighsDomain::ConflictSet::clearQueue() { resolveQueue.clear(); }
3582
+
3583
+ HighsInt HighsDomain::ConflictSet::queueSize() const {
3584
+ return resolveQueue.size();
3585
+ }
3586
+
3587
+ bool HighsDomain::ConflictSet::resolvable(HighsInt domChgPos) const {
3588
+ assert(domChgPos >= 0);
3589
+ assert(domChgPos < (HighsInt)localdom.domchgreason_.size());
3590
+ // printf("domchgPos: %d\n", domChgPos);
3591
+ // printf("stacksize: %ld\n", localdom.domchgreason_.size());
3592
+ switch (localdom.domchgreason_[domChgPos].type) {
3593
+ case Reason::kBranching:
3594
+ case Reason::kUnknown:
3595
+ return false;
3596
+ default:
3597
+ return true;
3598
+ }
3599
+ }
3600
+
3601
+ HighsInt HighsDomain::ConflictSet::resolveDepth(std::set<LocalDomChg>& frontier,
3602
+ HighsInt depthLevel,
3603
+ HighsInt stopSize,
3604
+ HighsInt minResolve,
3605
+ bool increaseConflictScore) {
3606
+ clearQueue();
3607
+ LocalDomChg startPos =
3608
+ LocalDomChg{depthLevel == 0 ? 0 : localdom.branchPos_[depthLevel - 1] + 1,
3609
+ HighsDomainChange()};
3610
+ while (depthLevel < (HighsInt)localdom.branchPos_.size()) {
3611
+ HighsInt branchPos = localdom.branchPos_[depthLevel];
3612
+ if (localdom.domchgstack_[branchPos].boundval !=
3613
+ localdom.prevboundval_[branchPos].first)
3614
+ break;
3615
+ // printf("skipping redundant depth\n");
3616
+ ++depthLevel;
3617
+ }
3618
+
3619
+ auto iterEnd =
3620
+ depthLevel == (HighsInt)localdom.branchPos_.size()
3621
+ ? frontier.end()
3622
+ : frontier.upper_bound(LocalDomChg{localdom.branchPos_[depthLevel],
3623
+ HighsDomainChange()});
3624
+ bool empty = true;
3625
+ for (auto it = frontier.lower_bound(startPos); it != iterEnd; ++it) {
3626
+ assert(it != frontier.end());
3627
+ empty = false;
3628
+ if (resolvable(it->pos)) pushQueue(it);
3629
+ }
3630
+
3631
+ if (empty) return -1;
3632
+
3633
+ HighsInt numResolved = 0;
3634
+
3635
+ while (queueSize() > stopSize ||
3636
+ (queueSize() > 0 && numResolved < minResolve)) {
3637
+ std::set<LocalDomChg>::iterator pos = popQueue();
3638
+ if (!explainBoundChange(frontier, *pos)) continue;
3639
+
3640
+ ++numResolved;
3641
+ frontier.erase(pos);
3642
+ for (const LocalDomChg& i : resolvedDomainChanges) {
3643
+ auto insertResult = frontier.insert(i);
3644
+ if (insertResult.second) {
3645
+ if (increaseConflictScore) {
3646
+ if (localdom.domchgstack_[i.pos].boundtype == HighsBoundType::kLower)
3647
+ localdom.mipsolver->mipdata_->pseudocost.increaseConflictScoreUp(
3648
+ localdom.domchgstack_[i.pos].column);
3649
+ else
3650
+ localdom.mipsolver->mipdata_->pseudocost.increaseConflictScoreDown(
3651
+ localdom.domchgstack_[i.pos].column);
3652
+ }
3653
+ if (i.pos >= startPos.pos && resolvable(i.pos))
3654
+ pushQueue(insertResult.first);
3655
+ } else {
3656
+ if (i.domchg.boundtype == HighsBoundType::kLower) {
3657
+ // if (insertResult.first->domchg.boundval != i.domchg.boundval)
3658
+ // printf(
3659
+ // "got different relaxed lower bounds: current=%g, new=%g, "
3660
+ // "stack=%g\n",
3661
+ // insertResult.first->domchg.boundval, i.domchg.boundval,
3662
+ // localdom.domchgstack_[i.pos].boundval);
3663
+ //
3664
+ insertResult.first->domchg.boundval =
3665
+ std::max(insertResult.first->domchg.boundval, i.domchg.boundval);
3666
+ } else {
3667
+ // if (insertResult.first->domchg.boundval != i.domchg.boundval)
3668
+ // printf(
3669
+ // "got different relaxed upper bounds: current=%g, new=%g, "
3670
+ // "stack=%g\n",
3671
+ // insertResult.first->domchg.boundval, i.domchg.boundval,
3672
+ // localdom.domchgstack_[i.pos].boundval);
3673
+ insertResult.first->domchg.boundval =
3674
+ std::min(insertResult.first->domchg.boundval, i.domchg.boundval);
3675
+ }
3676
+ }
3677
+ }
3678
+ }
3679
+
3680
+ return numResolved;
3681
+ }
3682
+
3683
+ HighsInt HighsDomain::ConflictSet::computeCuts(
3684
+ HighsInt depthLevel, HighsConflictPool& conflictPool) {
3685
+ HighsInt numResolved = resolveDepth(
3686
+ reasonSideFrontier, depthLevel, 1,
3687
+ depthLevel == (HighsInt)localdom.branchPos_.size() ? 1 : 0, true);
3688
+ if (numResolved == -1) return -1;
3689
+ HighsInt numConflicts = 0;
3690
+ if (numResolved > 0) {
3691
+ // add conflict cut
3692
+ localdom.mipsolver->mipdata_->debugSolution.checkConflictReasonFrontier(
3693
+ reasonSideFrontier, localdom.domchgstack_);
3694
+
3695
+ conflictPool.addConflictCut(localdom, reasonSideFrontier);
3696
+ ++numConflicts;
3697
+ }
3698
+
3699
+ // if the queue size is 1 then we have a resolvable UIP that is not the
3700
+ // branch vertex
3701
+ if (queueSize() == 1) {
3702
+ LocalDomChg uip = *popQueue();
3703
+ clearQueue();
3704
+
3705
+ // compute the UIP reconvergence cut
3706
+ reconvergenceFrontier.clear();
3707
+ reconvergenceFrontier.insert(uip);
3708
+ HighsInt numResolved = resolveDepth(reconvergenceFrontier, depthLevel, 0);
3709
+
3710
+ if (numResolved > 0 && reconvergenceFrontier.count(uip) == 0) {
3711
+ localdom.mipsolver->mipdata_->debugSolution
3712
+ .checkConflictReconvergenceFrontier(reconvergenceFrontier, uip,
3713
+ localdom.domchgstack_);
3714
+ conflictPool.addReconvergenceCut(localdom, reconvergenceFrontier,
3715
+ uip.domchg);
3716
+ ++numConflicts;
3717
+ }
3718
+ }
3719
+
3720
+ return numConflicts;
3721
+ }
3722
+
3723
+ void HighsDomain::ConflictSet::conflictAnalysis(
3724
+ HighsConflictPool& conflictPool) {
3725
+ resolvedDomainChanges.reserve(localdom.domchgstack_.size());
3726
+
3727
+ if (!explainInfeasibility()) return;
3728
+
3729
+ localdom.mipsolver->mipdata_->pseudocost.increaseConflictWeight();
3730
+ for (const LocalDomChg& locdomchg : resolvedDomainChanges) {
3731
+ if (locdomchg.domchg.boundtype == HighsBoundType::kLower)
3732
+ localdom.mipsolver->mipdata_->pseudocost.increaseConflictScoreUp(
3733
+ locdomchg.domchg.column);
3734
+ else
3735
+ localdom.mipsolver->mipdata_->pseudocost.increaseConflictScoreDown(
3736
+ locdomchg.domchg.column);
3737
+ }
3738
+
3739
+ if (10 * resolvedDomainChanges.size() >
3740
+ 1000 + 3 * localdom.mipsolver->mipdata_->integral_cols.size())
3741
+ return;
3742
+
3743
+ reasonSideFrontier.insert(resolvedDomainChanges.begin(),
3744
+ resolvedDomainChanges.end());
3745
+
3746
+ localdom.mipsolver->mipdata_->debugSolution.checkConflictReasonFrontier(
3747
+ reasonSideFrontier, localdom.domchgstack_);
3748
+
3749
+ HighsInt numConflicts = 0;
3750
+ HighsInt lastDepth = localdom.branchPos_.size();
3751
+ // printf("start conflict analysis\n");
3752
+ HighsInt currDepth;
3753
+ for (currDepth = lastDepth; currDepth >= 0; --currDepth) {
3754
+ if (currDepth > 0) {
3755
+ // skip redundant branching changes which are just added for symmetry
3756
+ // handling
3757
+ HighsInt branchpos = localdom.branchPos_[currDepth - 1];
3758
+ if (localdom.domchgstack_[branchpos].boundval ==
3759
+ localdom.prevboundval_[branchpos].first) {
3760
+ --lastDepth;
3761
+ continue;
3762
+ }
3763
+ }
3764
+ HighsInt numNewConflicts = computeCuts(currDepth, conflictPool);
3765
+ // if the depth level was empty, do not consider it
3766
+ if (numNewConflicts == -1) {
3767
+ --lastDepth;
3768
+ continue;
3769
+ }
3770
+
3771
+ numConflicts += numNewConflicts;
3772
+ // if no conflict was found in the first non-empty depth level we stop here
3773
+ if (numConflicts == 0) break;
3774
+ // if no conflict was found in this depth level and all conflicts of the
3775
+ // first 5 non-empty depth levels are generated we stop here
3776
+ if (lastDepth - currDepth >= 4 && numNewConflicts == 0) break;
3777
+ }
3778
+
3779
+ // if we stopped in the highest non-empty depth it means no conflicts where
3780
+ // added yet. We want to at least add the current conflict frontier as it
3781
+ // means the bound change leading to infeasibility was the last branching
3782
+ // itself and hence should have been propagated in the previous depth but was
3783
+ // not, e.g. because the threshold for an integral variable was not reached.
3784
+ if (currDepth == lastDepth)
3785
+ conflictPool.addConflictCut(localdom, reasonSideFrontier);
3786
+ }
3787
+
3788
+ void HighsDomain::ConflictSet::conflictAnalysis(
3789
+ const HighsInt* proofinds, const double* proofvals, HighsInt prooflen,
3790
+ double proofrhs, HighsConflictPool& conflictPool) {
3791
+ resolvedDomainChanges.reserve(localdom.domchgstack_.size());
3792
+
3793
+ HighsInt ninfmin;
3794
+ HighsCDouble activitymin;
3795
+ globaldom.computeMinActivity(0, prooflen, proofinds, proofvals, ninfmin,
3796
+ activitymin);
3797
+ if (ninfmin != 0) return;
3798
+
3799
+ if (!explainInfeasibilityLeq(proofinds, proofvals, prooflen, proofrhs,
3800
+ double(activitymin)))
3801
+ return;
3802
+
3803
+ localdom.mipsolver->mipdata_->pseudocost.increaseConflictWeight();
3804
+ for (const LocalDomChg& locdomchg : resolvedDomainChanges) {
3805
+ if (locdomchg.domchg.boundtype == HighsBoundType::kLower)
3806
+ localdom.mipsolver->mipdata_->pseudocost.increaseConflictScoreUp(
3807
+ locdomchg.domchg.column);
3808
+ else
3809
+ localdom.mipsolver->mipdata_->pseudocost.increaseConflictScoreDown(
3810
+ locdomchg.domchg.column);
3811
+ }
3812
+
3813
+ if (10 * resolvedDomainChanges.size() >
3814
+ 1000 + 3 * localdom.mipsolver->mipdata_->integral_cols.size())
3815
+ return;
3816
+
3817
+ reasonSideFrontier.insert(resolvedDomainChanges.begin(),
3818
+ resolvedDomainChanges.end());
3819
+
3820
+ assert(resolvedDomainChanges.size() == reasonSideFrontier.size());
3821
+
3822
+ localdom.mipsolver->mipdata_->debugSolution.checkConflictReasonFrontier(
3823
+ reasonSideFrontier, localdom.domchgstack_);
3824
+
3825
+ HighsInt numConflicts = 0;
3826
+ HighsInt lastDepth = localdom.branchPos_.size();
3827
+ HighsInt currDepth;
3828
+ for (currDepth = lastDepth; currDepth >= 0; --currDepth) {
3829
+ if (currDepth > 0) {
3830
+ // skip redundant branching changes which are just added for symmetry
3831
+ // handling
3832
+ HighsInt branchpos = localdom.branchPos_[currDepth - 1];
3833
+ if (localdom.domchgstack_[branchpos].boundval ==
3834
+ localdom.prevboundval_[branchpos].first) {
3835
+ --lastDepth;
3836
+ continue;
3837
+ }
3838
+ }
3839
+ HighsInt numNewConflicts = computeCuts(currDepth, conflictPool);
3840
+ // if the depth level was empty, do not consider it
3841
+ if (numNewConflicts == -1) {
3842
+ --lastDepth;
3843
+ continue;
3844
+ }
3845
+
3846
+ numConflicts += numNewConflicts;
3847
+ // if no conflict was found in the first non-empty depth level we stop here
3848
+ if (numConflicts == 0) break;
3849
+ // if no conflict was found in this depth level and all conflicts of the
3850
+ // first 5 non-empty depth levels are generated we stop here
3851
+ if (lastDepth - currDepth >= 4 && numNewConflicts == 0) break;
3852
+ }
3853
+
3854
+ // if we stopped in the highest non-empty depth it means no conflicts where
3855
+ // added yet. We want to at least add the current conflict frontier as it
3856
+ // means the bound change leading to infeasibility was the last branching
3857
+ // itself and hence should have been propagated in the previous depth but was
3858
+ // not, e.g. because the threshold for an integral variable was not reached.
3859
+ if (currDepth == lastDepth)
3860
+ conflictPool.addConflictCut(localdom, reasonSideFrontier);
3861
+ }