Replies: 8 comments 5 replies
-
Every time you call In your case, so long as it is feasible for the variables associated with your new columns to take zero values, the simplex solver can start from a feasible solution to the new LP. This is very likely to be much faster than solving the new LP from scratch. However, if it is very much faster to solve your LP using the barrier solver, then it's not possible to exploit the knowledge of the optimal solution of a related problem. Since you are looking to do more than just solve a one-off LP, I strongly advise you to call HiGHS directly. From Python this can be done with Sorry for not replying sooner: I don't get notifications of discussion items |
Beta Was this translation helpful? Give feedback.
-
Thanks Julian, knowing that something like this should be possible is helpful by itself! I tried doing a comparison in which I, on one hand, solve the LP over and over using SciPy, and one in which I use highspy to build up the problem iteratively. What I find is that indeed the latter approach ends up being faster overall, and is much faster when I only add a few columns, but on the other hand, for the bulk of the calculation, solving it from scratch is in fact much faster. I checked that the act of modifying the model itself does not make a large contribution to running time compared to solving it, so that's not it. There could be some differences in how the library is compiled (which compiler optimization flags are included etc.), but that seems unlikely to matter enough to explain the difference. So, clearly I could get the best of both worlds if I figure out when to append to the existing solution rather than start from scratch, but I'm still surprised that it's not simply always faster to build up the solution; maybe I shouldn't be? As a bit of an aside, I noticed that the Python docs suggest using Concretely, the total calculation time for the two approaches on my problem are as follows:
Plotted: To benchmark, I've solved the whole thing to get the final matrices, then simply truncate them afterwards to put both approaches on equal footing; that is, I've represented the problem through sparse arrays for n in ns:
A_eq = A_eq_base[:, :n]
A_ub = A_ub_base[:, :n]
c = c_base[:n]
res = linprog(c=c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq=b_eq) and for the inf: np.double = highspy.kHighsInf
# Combine inequality and equality constraints
lhs_ub = -np.ones_like(b_ub) * np.inf
rhs_ub = b_ub
lhs_eq = b_eq
rhs_eq = b_eq
lhs = np.concatenate((lhs_ub, lhs_eq))
rhs = np.concatenate((rhs_ub, rhs_eq))
A = vstack((A_ub_base, A_eq_base))
numrow = A.shape[0]
h = highspy.Highs()
h.setOptionValue("log_to_console", False)
h.addRows(numrow, lhs, rhs, 0, np.empty(0, dtype=np.double), np.empty(0, dtype=np.double), np.empty(0, dtype=np.double))
for n1, n2 in zip([0] + ns, ns):
cols = A[:, n1:n2]
# The docs suggest that h.addCols ought to work, but that's not part of the highspy interface
for i in range(n1, n2):
col = A[:, i]
h.addCol(c_base[i], 0, inf, col.nnz, col.indices, col.data)
h.run() |
Beta Was this translation helpful? Give feedback.
-
In SciPy and HiGHS, you're still using the simplex solver for everything, and the behaviour you're getting is largely to be expected
However, when solving from scratch it's likely to be very much faster using the interior point solver.
|
Beta Was this translation helpful? Give feedback.
-
Yes, |
Beta Was this translation helpful? Give feedback.
-
Thanks again; much appreciated! I repeated the exercise with each of your suggestions and end up with the below results (redoing the two cases from before in the process), where it's implicit that "SciPy" means "starting from scratch", and "highspy" means "hot starting". Notably, when coming from SciPy, using
In particular, this means that if I use |
Beta Was this translation helpful? Give feedback.
-
As a bit of an aside, how much of the solver state would one have to pull out to be able to pick up progress after the process has ended; that is, to run the solver, close the process containing it, open another one a few days later, yet still be able to hot start. I noticed that we have |
Beta Was this translation helpful? Give feedback.
-
So, you have LPs where interior point isn't so much better than simplex, and hot start is using dual simplex - as it would if there were any primal infeasibilities when you add the new columns. |
Beta Was this translation helpful? Give feedback.
-
I just realized I never spelled that out, but my solution indeed remains primal feasible after adding new columns with zero weight. So I'm still surprised that the hot starting approach is much slower in the intermediate iterations than starting over, even though I stick to using the dual simplex solver in all cases. But perhaps that's expected? |
Beta Was this translation helpful? Give feedback.
-
I have a large-ish LP that can be effectively solved through column generation (adding some 10,000 columns at a time over 10-20 iterations, with the subproblem itself being efficiently implemented to the point of HiGHS being the bottleneck at the moment), and I'm curious if there are any natural tricks that I could be applying to minimize the amount of additional work required by HiGHS in each iteration. I'm using the
scipy.optimize.linprog
interface as a wrapper for the dual simplex solver, and am passing constraints as a sequence of growing CSC matrices, but maybe I would be better off using HiGHS internals directly?Beta Was this translation helpful? Give feedback.
All reactions