Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
312 commits
Select commit Hold shift + click to select a range
05cc5ec
Add globaldom to all heuristics
Opt-Mucca Sep 22, 2025
d580c4d
Add index to lprow for cutpool
Opt-Mucca Sep 22, 2025
ec1c4cc
Add pointer magic for cutpool during shrink
Opt-Mucca Sep 22, 2025
05c430e
Pass globaldom to some lprelaxation functions
Opt-Mucca Sep 22, 2025
6ec6465
Replace more global domain usages
Opt-Mucca Sep 23, 2025
2f5ddc5
Give all lp relaxations a index
Opt-Mucca Sep 23, 2025
1263d08
Add globaldom to implications
Opt-Mucca Sep 23, 2025
d45d294
Add globaldom as arg to conflictanalysis
Opt-Mucca Sep 23, 2025
7f946c5
Pass local conflict pool to redcost propagation
Opt-Mucca Sep 23, 2025
a9a9476
Make lpcutremoved thread safe
Opt-Mucca Sep 23, 2025
8a96182
Access lprelax in heur via worker
Opt-Mucca Sep 24, 2025
0e80ead
Make cutpool a pointer
Opt-Mucca Sep 24, 2025
9345801
Make lprelax also pointer. Add convencience functions
Opt-Mucca Sep 24, 2025
1aaf5da
Add more lambda functions
Opt-Mucca Sep 24, 2025
3a575ec
Fix bug on non-synced solutions
Opt-Mucca Sep 24, 2025
4d322af
Add more lambdas. Start work on main loop
Opt-Mucca Sep 25, 2025
f79b79c
Create lambda for evaluating nodes
Opt-Mucca Sep 25, 2025
b8bf59f
Create lambda for handling pruned nodes
Opt-Mucca Sep 25, 2025
ebec009
Use sepa per worker
Opt-Mucca Sep 25, 2025
d171a40
Add lambda for sepa and store basis
Opt-Mucca Sep 25, 2025
b0b8374
Use mipworker cutpool in separation
Opt-Mucca Sep 26, 2025
b1f1acc
Add parallel lock. Fix cut pool sepa
Opt-Mucca Sep 26, 2025
75b7e7b
Increase numlps when copying an LP
Opt-Mucca Sep 29, 2025
092ea99
Rework locks. Add missing lower bound update
Opt-Mucca Sep 29, 2025
d9c57a6
Add more solution syncs. Fix wrong index and addincumbent call
Opt-Mucca Sep 29, 2025
62c4994
Add sync pools
Opt-Mucca Sep 30, 2025
a4ac096
Fix conflict bug. Parallel dives
Opt-Mucca Sep 30, 2025
c4cf00b
Add heuristics to dive
Opt-Mucca Sep 30, 2025
7879c0e
Add missing lock
Opt-Mucca Oct 1, 2025
1da3cdf
Add global cutpool aging. Add safe local pool aging
Opt-Mucca Oct 1, 2025
2e6aba5
Allow implied bounds sepa parallel
Opt-Mucca Oct 1, 2025
c59322a
general worker create lambda. Make conflictpool a pointer
Opt-Mucca Oct 1, 2025
0408d10
use local conflict pool and worker sols in heur
Opt-Mucca Oct 1, 2025
5d07616
Make helper functions for flushing global domain changes
Opt-Mucca Oct 2, 2025
94b909b
Make globaldom_ a pointer too
Opt-Mucca Oct 2, 2025
892d098
Add miptwork to lp. Fix some global info updates
Opt-Mucca Oct 2, 2025
1d8882e
Make master worker use local global copy
Opt-Mucca Oct 2, 2025
a53e0da
Remove debugging resize
Opt-Mucca Oct 2, 2025
9d0eee8
Correctly add incumbent to worker or global
Opt-Mucca Oct 2, 2025
917d61f
Fix worker solution. Add more checks
Opt-Mucca Oct 6, 2025
f1ea4bf
Add more calls to worker in lprelax
Opt-Mucca Oct 6, 2025
5065984
Fix incorrect logic
Opt-Mucca Oct 6, 2025
7ee9606
Add cut aging call
Opt-Mucca Oct 6, 2025
e3ee17c
Disable broken aging
Opt-Mucca Oct 6, 2025
fd13d2f
Remove redundant line. Fix order of calls
Opt-Mucca Oct 7, 2025
756d7cf
Rework how cutspools are handled in paralell case
Opt-Mucca Dec 1, 2025
34145f9
Add minor changes on when stuff is called
Opt-Mucca Dec 2, 2025
f97964c
Age the local cut pools
Opt-Mucca Dec 2, 2025
cf8dc44
re-enable test and fix cut aging
Opt-Mucca Dec 2, 2025
7bb891b
Reenable more tests
Opt-Mucca Dec 2, 2025
05c83ea
Merge v1.12 into branch"
Opt-Mucca Dec 3, 2025
cfc2795
Add highdebugsol. Add simulate_concurrency option
Opt-Mucca Dec 3, 2025
341b2c9
Disable heuristic timers when parallel lock is active
Opt-Mucca Dec 18, 2025
d828de6
Fix minor bugs. Comment out confusing code"
Opt-Mucca Dec 19, 2025
58d05c3
Remove unnecessary debug solution resetdomains
Opt-Mucca Dec 19, 2025
8f6489c
Fix minor things. Add comments
Opt-Mucca Jan 5, 2026
ef918f3
Add generalised parallel call
Opt-Mucca Jan 5, 2026
66b4f3d
Parallelise dive and separate functions
Opt-Mucca Jan 6, 2026
701a8e7
Fix clocks. Enable heuristics
Opt-Mucca Jan 6, 2026
257bacd
Disable parallelism for submips. Add missing search domain sync
Opt-Mucca Jan 6, 2026
1ae4665
Add C++ LLM black magic
Opt-Mucca Jan 7, 2026
895e6a8
sync and flush functions for local pseudocosts
Opt-Mucca Jan 8, 2026
16f34e6
Add pseudo-cost deque to mipsolverdata
Opt-Mucca Jan 8, 2026
8f7d267
Make pseudo-costs not be optimized out
Opt-Mucca Jan 8, 2026
bcfa281
Enable clique seperation for parallel
Opt-Mucca Jan 9, 2026
aa58e8c
Fix incorrect logic
Opt-Mucca Jan 9, 2026
52efade
Correctly handle infeasible return via updateActivity in cutpoolprop
Opt-Mucca Jan 9, 2026
935cca1
Make compiler happy with highsint"
Opt-Mucca Jan 9, 2026
dc2d1ea
Rename and tidy up
Opt-Mucca Jan 12, 2026
8bfb9fc
Parallelise and sync reset worker domains
Opt-Mucca Jan 13, 2026
4f5b4cf
More tidying up
Opt-Mucca Jan 13, 2026
a4777bd
Tidy up. Revert incorrect simplification
Opt-Mucca Jan 13, 2026
5af1a62
Create sepa stats
Opt-Mucca Jan 13, 2026
c4ee39e
Add duplicate check in master cut pool
Opt-Mucca Jan 13, 2026
9ae2cda
Remove reference re-assignment attempts
Opt-Mucca Jan 14, 2026
f5e1014
Tidy up LpRelaxation functions
Opt-Mucca Jan 14, 2026
6174a83
Clean up heuristic stats
Opt-Mucca Jan 14, 2026
6887c5e
Add terminator calls using worker info
Opt-Mucca Jan 14, 2026
976c023
Update worker upper bound in single-threaded case
Opt-Mucca Jan 14, 2026
9a1bc7e
Add general addincumbent and trySoolution functions to heursitics"
Opt-Mucca Jan 14, 2026
febe041
Clean up HighsSearch
Opt-Mucca Jan 14, 2026
f73c828
Tidy up separators
Opt-Mucca Jan 14, 2026
d578ee8
Rename usedInDive and usedInROund
Opt-Mucca Jan 15, 2026
0f309d6
Tidy up HighsMipSolver
Opt-Mucca Jan 15, 2026
cc21b5f
Enable trivial heur. Change sync sol logic.
Opt-Mucca Jan 15, 2026
31ee713
Reenable RENS at root. Tidy up HighsMipSolverData
Opt-Mucca Jan 15, 2026
e501353
Reenable root reduced cost heuristic
Opt-Mucca Jan 16, 2026
62ce4b8
Add getter functions for global + worker heur stats
Opt-Mucca Jan 16, 2026
ada97eb
Use original random seed when not in parallel
Opt-Mucca Jan 16, 2026
b67fce8
Dont sync ps in single worker case
Opt-Mucca Jan 16, 2026
fc77312
Update global pseudo cost is lock not active
Opt-Mucca Jan 19, 2026
f2b2c81
Fix bug with intcols being globally changes
Opt-Mucca Jan 19, 2026
5d54551
Fix error in conflict score averaging
Opt-Mucca Jan 19, 2026
15d217f
Remove conflict weight multiplier
Opt-Mucca Jan 20, 2026
8261ee6
Reset sepa inbetween restarts
Opt-Mucca Jan 20, 2026
a2cf2ff
Add centralised backtrack plunge
Opt-Mucca Jan 20, 2026
ded9f80
Initialise numCol in worker nodequeue. Fix index bug
Opt-Mucca Jan 20, 2026
00aa78d
Scale backtrack plunge budget by workers
Opt-Mucca Jan 21, 2026
c4fbbb6
Fix bugs. Re-enable compiler optimisation
Opt-Mucca Jan 21, 2026
6a7a45b
Enable bazel sanitizers
Opt-Mucca Jan 21, 2026
9fbd004
reverse order of domain and pools
Opt-Mucca Jan 21, 2026
4ab615a
Change order of members
Opt-Mucca Jan 21, 2026
fb2269b
Comment out an LP timer
Opt-Mucca Jan 21, 2026
6063638
Change backtracked to uint8_t too
Opt-Mucca Jan 22, 2026
4eaf31e
Dont check limits during search if parallel
Opt-Mucca Jan 22, 2026
5a0e839
Define shared pointer to basis inside of lambda
Opt-Mucca Jan 22, 2026
bc26bb7
Introduce new serial parameter to runTask
Opt-Mucca Jan 22, 2026
62911e8
Add safety rail to copying poolprops
Opt-Mucca Jan 22, 2026
9f8dc9f
Add parallel.md for help in understading branch
Opt-Mucca Jan 23, 2026
be7655c
Add extra TODO to parallel.md
Opt-Mucca Jan 23, 2026
89684d9
Dynamically create workers
Opt-Mucca Jan 29, 2026
48f8bf9
Change code to avoid confusion on domain resetting
Opt-Mucca Jan 30, 2026
f423df7
Remove point from parallel.md. Make bazel happy with parallel
Opt-Mucca Jan 30, 2026
98c7564
Fix bug of skipping infeasible row activity update
Opt-Mucca Feb 2, 2026
4e29a0d
Add an extra solution sync
Opt-Mucca Feb 3, 2026
6aef65f
Merge latest into branch
Opt-Mucca Mar 2, 2026
f0c99ec
Github action stuff
Opt-Mucca Mar 2, 2026
f6afc95
github action v2
Opt-Mucca Mar 2, 2026
a654d5d
Reformat after merging latest
Opt-Mucca Mar 2, 2026
56b8567
Add comments from Franz
Opt-Mucca Mar 3, 2026
24a3726
Comments from Franz v2
Opt-Mucca Mar 3, 2026
08ad869
Remove forward declaration and potential circualr dependency
Opt-Mucca Mar 3, 2026
a06cf54
Formatting
Opt-Mucca Mar 3, 2026
9314a91
Remove empty line
Opt-Mucca Mar 4, 2026
832ebd8
Comments from Franz v3
Opt-Mucca Mar 4, 2026
9863be4
Move assert outside loop
Opt-Mucca Mar 5, 2026
f28a935
Make globaldom const in translp
Opt-Mucca Mar 13, 2026
9bedd5a
Merge branch 'latest' into hmw-mt
jajhall Mar 15, 2026
93b6992
Fix cutpool aging bugs. Enable MIP timers in non-parallel
Opt-Mucca Mar 16, 2026
1e6813a
Double backtrack plunge allowance
Opt-Mucca Mar 16, 2026
eaae314
Add deterministic test
Opt-Mucca Mar 16, 2026
0e069b0
Make thread sanitizer happy
Opt-Mucca Mar 17, 2026
d2c4528
Remove references
fwesselm Mar 17, 2026
1637356
Revert std::atomic for parallel_lock
Opt-Mucca Mar 17, 2026
bdba2bd
Format. Fix pseudocost bug. Move cutpool init
Opt-Mucca Mar 17, 2026
5f85038
Add HighsMipWorker.cpp to meson.build"
Opt-Mucca Mar 17, 2026
8d81865
Add const getter functions
Opt-Mucca Mar 17, 2026
323a03f
Merge branch 'hmw-mt-2' into hmw-mt
Opt-Mucca Mar 17, 2026
76172a0
All tests pass
Mar 17, 2026
75f5622
Added HighsSubSolverCallTime::update
Mar 17, 2026
5fe7974
Recovered timing code in HApp.h
Mar 17, 2026
db3795b
See what's wrong
Mar 17, 2026
e27fe6d
Now to modify reportSubSolverCallTime and mipTimerUpdate to handle mu…
Mar 17, 2026
36d41d9
Highs::reportSubSolverCallTime() now multi-threaded
Mar 17, 2026
efd3338
HighsTimer: Overriding this->printf_flag
Mar 18, 2026
7a2cbe4
Refactor main solve loop. Create single sync point
Opt-Mucca Mar 25, 2026
57ab48e
Fix bugs in refactor.
Opt-Mucca Mar 25, 2026
99092ad
Make additional check for diff solution path
Opt-Mucca Mar 25, 2026
be54b11
Separate worker cutpools. Keep dyanmic worker spawning
Opt-Mucca Mar 25, 2026
16d9bd1
Make formatter happy
Opt-Mucca Mar 25, 2026
9c94db2
Delete pools after highsmipworker. Check if valgrind is happy
Opt-Mucca Mar 26, 2026
114e23c
Also sync propagated cuts. Disable heuristics during rampup
Opt-Mucca Mar 27, 2026
7ad0e81
Randomise heuristic allowance for workers
Opt-Mucca Mar 27, 2026
079c4b1
Move basis re-init to correct location
Opt-Mucca Mar 27, 2026
55818e8
Destroy old workers after resetting sepa / search for masterworker
Opt-Mucca Mar 27, 2026
bb7104f
Make std::max happy with two HighsInts
Opt-Mucca Mar 31, 2026
6173c15
Introduced thread_mip_clocks_ and thread_submip_clocks_ to HighsMipAn…
Apr 5, 2026
10aee8e
Merged latest into this branch
Apr 6, 2026
ef0d6ec
Now starting the local HighsMipSolver timer when solving sub-MIPs
Apr 6, 2026
5ee6fdb
Merge branch 'latest' into hmw-mt
fwesselm Apr 7, 2026
df8d8a1
Fix merge issue
fwesselm Apr 7, 2026
dc108e6
Remove extra semicolon
fwesselm Apr 7, 2026
f082f53
Now have vectors of submip, start_time and clock_running in HighsSubS…
Apr 7, 2026
146a529
Time to get rid of old sub_system_call_time infrastructure
Apr 7, 2026
bb52c88
Now to remove sub_solver_call_time_ from solver_object
Apr 7, 2026
651815e
Reworked HighsSubSolverCallTime for multi-threading, and introduced g…
Apr 7, 2026
4732125
Restored Highs::reportSubSolverCallTime
Apr 8, 2026
e755d57
Got a bit further!
Apr 8, 2026
2cef98c
flugpl runs OK; bell5 segfaults due to its submips
Apr 8, 2026
f12f23b
And bell5 finishes!
Apr 8, 2026
625f6ce
Now logging MIP and sub-MIP sub-solver times for thread 0
Apr 8, 2026
31f24f6
Almost there!
Apr 9, 2026
1f968a5
Merge branch 'latest' into thread-mip-timer
jajhall Apr 11, 2026
56971f4
Merge branch 'thread-mip-timer' of https://github.com/ERGO-Code/HiGHS…
jajhall Apr 11, 2026
1f39414
Cleaned up hrule
jajhall Apr 11, 2026
204cc5a
Merged thread-mip-timer into this branch and cleared conflicts
jajhall Apr 11, 2026
4fc2a2e
Need to have a sub-MIP clock for each thread
jajhall Apr 11, 2026
f7332b8
Bell5 profiled OK
jajhall Apr 11, 2026
ffcbcc3
Formatted
jajhall Apr 11, 2026
32ab256
DO need sub-MIP subsolver time for each thread
jajhall Apr 11, 2026
f831580
Now each thread has a sub-MIP clock_running/start_time record
jajhall Apr 11, 2026
593f925
Over-ruling this->printf_flag to chase non-Linux error
jajhall Apr 12, 2026
9b5e292
Suppressed test mip-sub-solver-time as it uses the currently unsuppor…
jajhall Apr 12, 2026
412be8e
Merge pull request #2966 from ERGO-Code/hmw-mt-timer
jajhall Apr 13, 2026
561330b
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into hmw-mt
fwesselm Apr 15, 2026
ea972be
Rename HighsMipSolver::global_sub_solver_call_time_
jajhall Apr 15, 2026
32fd4ab
Seems OK, so now allow sub_solver_call_time_ to be nullptr
jajhall Apr 15, 2026
1b86b31
Eliminated HighsSubSolverCallTime instance in Highs: now just pointer…
jajhall Apr 15, 2026
8af5ed6
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into hmw-mt
fwesselm Apr 16, 2026
045145c
Generalised SubSolverCallTime to Profiling
jajhall Apr 16, 2026
577168c
Now to sort out when basic MIP clocks are started/stopped
jajhall Apr 16, 2026
a7490b7
Now running for MIP without profiling segfaulting
jajhall Apr 16, 2026
14e730b
Now to move top-level mip profiling clocks to top of clock list
jajhall Apr 16, 2026
c4fcc93
Need to use kPresolveTime/kSolveTime/kPostsolveTime and this will bre…
jajhall Apr 16, 2026
7c36670
Refactored subsystem solving to use dedicated start time for each clock
jajhall Apr 16, 2026
ffd6a76
Now to add MIP/sub-MIP selector to profile time reader
jajhall Apr 17, 2026
f3a0a17
Profiling sub-MIPs OK, but max_submip_level looks incorrect
jajhall Apr 17, 2026
f53a9e3
Corrected max sub-MIP depth calculation and enhanced timing logging
jajhall Apr 17, 2026
e13d5f4
HighsMipAnalysis now redundant
jajhall Apr 17, 2026
60e2736
OK so far
jajhall Apr 17, 2026
fc65e86
MIP timing logging recovered
jajhall Apr 17, 2026
12d8a03
Problems is in Highs::setBasis()
jajhall Apr 17, 2026
4b52e11
Why does semi-variable-model segfault?
jajhall Apr 17, 2026
5a3da16
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into hmw-mt
fwesselm Apr 20, 2026
4f2740a
Removed the submip data member from HighsProfiling, as it can't be se…
jajhall Apr 21, 2026
1328973
semi-variable-model passes if (this->profiling_->initialized) return …
jajhall Apr 21, 2026
0e0e3b2
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into hmw-mt
fwesselm Apr 22, 2026
db94e65
Added HighsProfiling::clear() so clearing Highs::profiling_ when High…
jajhall Apr 22, 2026
272369f
All unit tests pass: try CI
jajhall Apr 23, 2026
e2b1a5c
Deleted highs/mip/HighsMipAnalysis.*
jajhall Apr 23, 2026
df5834f
Merge branch 'hmw-mt' into hmw-mt-mip-profile
jajhall Apr 23, 2026
2b14ab9
Do need setSubmip
jajhall Apr 25, 2026
60c9635
Still needs to reinstate submip parameter in getHighsProfilingRecord
jajhall Apr 25, 2026
feaa48a
Separated HighsMipSolver::solvingReport and restored sub-MIP timing
jajhall Apr 25, 2026
fc3202a
Now exploring MIP solver
jajhall Apr 26, 2026
61b53d8
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into hmw-mt
fwesselm Apr 27, 2026
53ee1d7
Formatted
jajhall Apr 28, 2026
081043c
Ignore user interrupt when parallel
Opt-Mucca May 7, 2026
678262d
Make many things in HighsMipWorker private
Opt-Mucca May 7, 2026
01b7df0
Clean up branch
Opt-Mucca May 11, 2026
a8d47c2
Fix missed domain -> getDomain for debugsol
Opt-Mucca May 11, 2026
9665f43
Recomment out mip sub solver time
Opt-Mucca May 11, 2026
1271284
Merge latest into branch
Opt-Mucca May 12, 2026
415172b
Add missing resetHeurStats. Update worker even in non-concurrency
Opt-Mucca May 18, 2026
4cd678b
Fix error for outdated logic of mip_search_concurrency
Opt-Mucca May 18, 2026
2d24813
Fix bug in pseudocost sync!
Opt-Mucca May 18, 2026
375d761
Reinterpret conflict score in parallel
Opt-Mucca May 18, 2026
50f764e
Listen to IDE
Opt-Mucca May 18, 2026
444ac9b
Fix UB (credit explanation: Filippo)
Opt-Mucca May 18, 2026
3cac1f5
Fix bug. Incorrect lp used to notify cutpools
Opt-Mucca May 18, 2026
1217f4f
Make clang happy
Opt-Mucca May 18, 2026
3e7b2d2
Reformat conflictpool.cpp
Opt-Mucca May 18, 2026
c24e427
Add symmetric branching for parallel
Opt-Mucca May 18, 2026
0942e66
Clean up symmetry
Opt-Mucca May 18, 2026
3643b76
Change success gate to worker specific logic
Opt-Mucca May 19, 2026
ac08772
Gate missed checkLimits by parallelLockActive
Opt-Mucca May 19, 2026
8411919
Remove outdated TODOs and unneeded asserts
Opt-Mucca May 19, 2026
e955c75
No longer timing MIP components in sub-MIPs; added code to track whet…
May 19, 2026
5e000f2
Merged hmw-mt into this branch and cleared conflicts
May 19, 2026
aaae06b
Now completeSolutionFromDiscreteAssignment profiles as MIP, but reset…
May 19, 2026
2b6b4ba
Updated debug logging in HighsPrimalHeuristics.cpp
May 20, 2026
4a5c682
Merge latest into branch
Opt-Mucca May 20, 2026
1ab5960
Disable clique-nieghbour parallelism in parallel search + submips
Opt-Mucca May 20, 2026
249a1ea
Merge branch 'latest' into hmw-mt
Opt-Mucca May 21, 2026
5f1e079
Merged hmw-mt into this branch and cleared minor profiling-related co…
May 21, 2026
0167086
Merge branch 'latest' into hmw-mt
Opt-Mucca May 21, 2026
2634d03
Sub-solver profiling now off by default (as was intended) and HighsPr…
jajhall May 21, 2026
4ce8028
Merge branch 'hmw-mt-mip-profile' into hmw-mt
Opt-Mucca May 22, 2026
91493f5
Add missing timer.stop. Re-remove sources-oython.cmake
Opt-Mucca May 22, 2026
d681813
Add local limit check during parallel search
Opt-Mucca May 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion check/TestBasisSolves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ TEST_CASE("Basis-solves", "[highs_basis_solves]") {
// filename = std::string(HIGHS_DIR) + "/check/instances/25fv47.mps";

Highs highs;
if (!dev_run) highs.setOptionValue("output_flag", false);
highs.setOptionValue("output_flag", dev_run);

vector<HighsInt> basic_variables;
vector<double> rhs, solution_row, solution_col;
Expand Down
31 changes: 25 additions & 6 deletions check/TestCheckSolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {
HighsSolution optimal_solution = highs.getSolution();

HighsInt scratch_num_nodes = info.mip_node_count;
HighsInt scratch_num_simplex = info.simplex_iteration_count;
if (dev_run) printf("Num nodes = %d\n", int(scratch_num_nodes));

std::string solution_file = test_name + model + ".sol";
Expand All @@ -113,7 +114,10 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {

highs.run();
if (dev_run) printf("Num nodes = %d\n", int(info.mip_node_count));
REQUIRE(info.mip_node_count != scratch_num_nodes);
const bool different_search =
info.mip_node_count != scratch_num_nodes ||
info.simplex_iteration_count != scratch_num_simplex;
REQUIRE(different_search);
highs.clear();
}

Expand All @@ -132,7 +136,10 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {

highs.run();
if (dev_run) printf("Num nodes = %d\n", int(info.mip_node_count));
REQUIRE(info.mip_node_count != scratch_num_nodes);
const bool different_search =
info.mip_node_count != scratch_num_nodes ||
info.simplex_iteration_count != scratch_num_simplex;
REQUIRE(different_search);
highs.clear();
}

Expand Down Expand Up @@ -162,7 +169,10 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {

highs.run();
if (dev_run) printf("Num nodes = %d\n", int(info.mip_node_count));
REQUIRE(info.mip_node_count != scratch_num_nodes);
const bool different_search =
info.mip_node_count != scratch_num_nodes ||
info.simplex_iteration_count != scratch_num_simplex;
REQUIRE(different_search);
highs.clear();
}

Expand All @@ -185,7 +195,10 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {

highs.run();
if (dev_run) printf("Num nodes = %d\n", int(info.mip_node_count));
REQUIRE(info.mip_node_count != scratch_num_nodes);
const bool different_search =
info.mip_node_count != scratch_num_nodes ||
info.simplex_iteration_count != scratch_num_simplex;
REQUIRE(different_search);
highs.clear();
}

Expand Down Expand Up @@ -232,7 +245,10 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {
return_status = highs.setSolution(starting_solution);
REQUIRE(return_status == HighsStatus::kOk);
highs.run();
REQUIRE(info.mip_node_count != scratch_num_nodes);
const bool different_search =
info.mip_node_count != scratch_num_nodes ||
info.simplex_iteration_count != scratch_num_simplex;
REQUIRE(different_search);
highs.clear();
}

Expand Down Expand Up @@ -283,7 +299,10 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {
return_status = highs.setSolution(num_entries, index.data(), value.data());
REQUIRE(return_status == HighsStatus::kOk);
highs.run();
REQUIRE(info.mip_node_count != scratch_num_nodes);
const bool different_search =
info.mip_node_count != scratch_num_nodes ||
info.simplex_iteration_count != scratch_num_simplex;
REQUIRE(different_search);
highs.clear();
}
assert(other_tests);
Expand Down
24 changes: 24 additions & 0 deletions check/TestMipSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1162,6 +1162,7 @@ TEST_CASE("mip-lp-solver", "[highs_test_mip_solver]") {
#endif
}

/*
TEST_CASE("mip-sub-solver-time", "[highs_test_mip_solver]") {
const std::string model = "flugpl"; //"rgn"; //
std::string model_file =
Expand All @@ -1174,6 +1175,7 @@ TEST_CASE("mip-sub-solver-time", "[highs_test_mip_solver]") {
REQUIRE(h.run() == HighsStatus::kOk);
REQUIRE(h.getModelStatus() == HighsModelStatus::kOptimal);
}
*/

TEST_CASE("get-fixed-lp", "[highs_test_mip_solver]") {
std::string model = "avgas";
Expand Down Expand Up @@ -1405,6 +1407,28 @@ TEST_CASE("issue-2173", "[highs_test_mip_solver]") {
solve(highs, kHighsOnString, require_model_status, optimal_objective);
}

TEST_CASE("parallel-mip-determinism", "[highs_test_mip_solver]") {
std::string filename = std::string(HIGHS_DIR) + "/check/instances/bell5.mps";
HighsInt num_runs = 6;
std::vector<HighsInt> lp_iters(num_runs);
for (HighsInt i = 0; i < num_runs; i++) {
Highs highs;
highs.setOptionValue("output_flag", dev_run);
highs.setOptionValue("mip_rel_gap", 0);
highs.setOptionValue("threads", 2);
highs.setOptionValue("mip_search_concurrency", 2);
if (i % 2 == 0) highs.setOptionValue("mip_search_simulate_concurrency", 1);
highs.readModel(filename);
const HighsModelStatus require_model_status = HighsModelStatus::kOptimal;
const double optimal_objective = 8966406.491519;
solve(highs, kHighsOffString, require_model_status, optimal_objective);
lp_iters[i] = highs.getInfo().simplex_iteration_count;
if (i > 0) {
REQUIRE(lp_iters[i] == lp_iters[0]);
}
}
}

TEST_CASE("issue-2957", "[highs_test_mip_solver]") {
HighsLp lp;
lp.num_col_ = 2;
Expand Down
1 change: 1 addition & 0 deletions check/TestSemiVariables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ TEST_CASE("semi-variable-model", "[highs_test_semi_variables]") {
const double semi_col_lower = lp.col_lower_[semi_col];
const double semi_col_upper = lp.col_upper_[semi_col];
lp.col_cost_[semi_col] = semi_col_cost;
lp.model_name_ = "semi-variable-model";
optimal_objective_function_value = 6.83333;
// Legal to have infinte upper bounds on semi-variables
lp.col_upper_[semi_col] = inf;
Expand Down
4 changes: 2 additions & 2 deletions cmake/sources.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -380,9 +380,9 @@ set(highs_sources
mip/HighsImplications.cpp
mip/HighsLpAggregator.cpp
mip/HighsLpRelaxation.cpp
mip/HighsMipAnalysis.cpp
mip/HighsMipSolver.cpp
mip/HighsMipSolverData.cpp
mip/HighsMipWorker.cpp
mip/HighsModkSeparator.cpp
mip/HighsNodeQueue.cpp
mip/HighsObjectiveFunction.cpp
Expand Down Expand Up @@ -510,9 +510,9 @@ set(highs_headers
mip/HighsImplications.h
mip/HighsLpAggregator.h
mip/HighsLpRelaxation.h
mip/HighsMipAnalysis.h
mip/HighsMipSolver.h
mip/HighsMipSolverData.h
mip/HighsMipWorker.h
mip/HighsModkSeparator.h
mip/HighsNodeQueue.h
mip/HighsObjectiveFunction.h
Expand Down
54 changes: 35 additions & 19 deletions highs/Highs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1235,24 +1235,9 @@ class Highs {
HighsStatus setBasis();

/**
* @brief Return a const reference to the internal sub-solver call and time
* instance
*/
const HighsSubSolverCallTime& getSubSolverCallTime() const {
return sub_solver_call_time_;
}

/**
* @brief Report internal sub-solver call and time instance
*/
void reportSubSolverCallTime() const;

/**
* @brief Initialise the internal sub-solver call and time instance
* @brief Report profiling
*/
void initialiseSubSolverCallTime() {
this->sub_solver_call_time_.initialise();
}
void reportProfiling() const;

/**
* @brief Run IPX crossover from a given HighsSolution instance and,
Expand Down Expand Up @@ -1282,6 +1267,14 @@ class Highs {
std::string basisValidityToString(const HighsInt basis_validity) const;
std::string presolveRuleTypeToString(const HighsInt presolve_rule) const;

/**
* @brief Ensures that the global scheduler is initialized,
* returning HighsStatus::kError if it has already been initialized,
* but the threads option is nonzero and not equal to
* this->max_threads_.
*/
HighsStatus initializeMultiThreading();

/**
* @brief Releases all resources held by the global scheduler instance. It is
* not thread-safe to call this function while calling run() or presolve() on
Expand All @@ -1297,6 +1290,29 @@ class Highs {
*/
static void resetGlobalScheduler(bool blocking = false);

/**
* @brief If profiling is not nullptr, sets up profiling and copies
* its pointer to Highs
*/
void initializeProfiling(HighsProfiling* profiling);
void initializeSingleThreadedProfiling(HighsProfiling* profiling);

/**
* @brief Clears and then initializes profiling
*/
void resetProfiling();

/**
* @brief If Highs::profiling_ is not nullptr, clears profiling and
* sets Highs::profiling_ to nullptr
*/
void clearProfiling();

/**
* @brief Checks that pointer is not nullptr, and copies it to Highs
*/
void setProfiling(HighsProfiling* profiling);

// Start of advanced methods: only for internal use!

// Nested methods below Highs::run()
Expand Down Expand Up @@ -1563,9 +1579,9 @@ class Highs {

HighsPresolveLog presolve_log_;

HighsSubSolverCallTime sub_solver_call_time_;
HighsProfiling* profiling_ = nullptr;

HighsInt max_threads = 0;
HighsInt max_threads_ = 0;
// This is strictly for debugging. It's used to check whether
// returnFromOptimizeModel() was called after the previous call to
// Highs::optimizeModel() and, assuming that this is always done, it checks
Expand Down
20 changes: 18 additions & 2 deletions highs/lp_data/HConst.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const std::string kHighsChooseString = "choose";
const std::string kHighsOnString = "on";
const HighsInt kHighsMaxStringLength = 512;
const HighsInt kSimplexConcurrencyLimit = 8;
const HighsInt kMipSearchConcurrencyLimit = 8;
const double kRunningAverageMultiplier = 0.05;

const double kExcessivelySmallObjectiveCoefficient = 1e-4;
Expand Down Expand Up @@ -302,8 +303,22 @@ enum IisStatus : int {
kIisStatusMax = kIisStatusInConflict
};

enum MipChooseSubMipRecord : int {
kMipRecord = -1,
kChooseRecord,
kSubMipRecord
};

enum PresolveSolvePostsolveIndex : int {
kPresolveTime = 0,
kSolveTime,
kPostsolveTime,
kToPresolveSolvePostsolve
};

enum SubSolverIndex : int {
kSubSolverMip = 0,
kFromSubSolver = kToPresolveSolvePostsolve,
kSubSolverMip = kFromSubSolver,
kSubSolverDuSimplexBasis,
kSubSolverDuSimplexNoBasis,
kSubSolverPrSimplexBasis,
Expand All @@ -315,7 +330,8 @@ enum SubSolverIndex : int {
kSubSolverPdlp,
kSubSolverQpAsm,
kSubSolverSubMip,
kSubSolverCount
kLastSubSolver = kSubSolverSubMip,
kToSubSolver = kLastSubSolver + 1
};

// Minimum and default KKT tolerance
Expand Down
43 changes: 38 additions & 5 deletions highs/lp_data/HStruct.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <vector>

#include "lp_data/HConst.h"
#include "util/HighsTimer.h"

struct HighsSolution {
bool value_valid = false;
Expand Down Expand Up @@ -165,13 +166,45 @@ struct HighsLinearObjective {
void clear();
};

struct HighsSubSolverCallTime {
std::vector<std::string> name;
struct HighsProfilingRecord {
std::vector<HighsInt> num_call;
std::vector<double> run_time;
void initialise();
void add(const HighsSubSolverCallTime& sub_solver_call_time,
const bool analytic_centre = false);
std::vector<double> start_time;
};

struct HighsProfiling {
HighsTimer* timer = nullptr;
bool multi_threaded = true;
std::string model_name_ = "";
bool sub_solver_ = false;
bool mip_ = false;
HighsInt num_profiling_clock_ = -1;
std::vector<std::string> name;
// These vectors are over threads
std::vector<bool> submip;
std::vector<HighsProfilingRecord> record;
std::vector<HighsProfilingRecord> submip_record;
bool initialized = false;

void initialize(HighsTimer& timer_, const bool subsolver_profiling,
const bool mip_profiling = false);
void clear();
HighsInt numThread();
HighsInt myThread();
void setSubMip(const bool submip);
bool isSubMip();
HighsProfilingRecord* getHighsProfilingRecord(
const HighsInt record_type = kChooseRecord);
void start(const HighsInt profiling_clock, const bool restart = false);
void stop(const HighsInt profiling_clock);
double read(const HighsInt profiling_clock,
const HighsInt record_type = kChooseRecord);
bool running(const HighsInt profiling_clock,
const HighsInt record_type = kChooseRecord);
HighsInt numCall(const HighsInt profiling_clock,
const HighsInt record_type = kChooseRecord);
void solveCall(const std::string& model, const bool submip);
// HighsInt getSepaClockIndex(const std::string& name);
};

struct HighsSimplexStats {
Expand Down
Loading
Loading