1010
1111#include " mip/HighsMachineSchedSeparator.h"
1212
13- #include " ../extern/pdqsort/pdqsort.h"
13+ #include < unordered_map>
14+
1415#include " mip/HighsCutGeneration.h"
1516#include " mip/HighsLpRelaxation.h"
1617#include " mip/HighsMipSolverData.h"
@@ -137,6 +138,7 @@ bool HighsMachineSchedSeparator::findSingleMachineScheduleClique(
137138 if (numRows > maxRows) break ;
138139 }
139140
141+ // A clique of size 3 needs at least 6 arcs
140142 if (numRows <= 5 ) return false ;
141143
142144 // Greedily search neighbours of largest degree column for a double-sided
@@ -149,24 +151,19 @@ bool HighsMachineSchedSeparator::findSingleMachineScheduleClique(
149151 potentialNeighbours.emplace_back (std::get<0 >(arc.first ));
150152 }
151153 }
152- inds.reserve (std::min (largestDegree, 50 ));
153- inds.emplace_back ();
154- inds.back ().reserve (std::min (largestDegree, 50 ));
155- rhss.resize (largestDegree + 1 , 0 );
156154 std::vector<HighsInt> neighbours;
157155 neighbours.reserve (largestDegree + 1 );
158156 neighbours.emplace_back (largestDegreeCol);
159157 releasedate = mipsolver.mipdata_ ->domain .col_lower_ [largestDegreeCol];
160158 std::vector<double > processingTimes;
161159 processingTimes.resize (largestDegree + 1 , kHighsInf );
162- // Iterate over potential neighbours, check validity, and build inequalities
160+ // Iterate over potential neighbours and check validity
163161 for (HighsInt col : potentialNeighbours) {
164162 bool valid_neighbour = true ;
165163 for (HighsInt neighbour : neighbours) {
166164 auto fromArc = adjacency.find ({col, neighbour});
167165 auto toArc = adjacency.find ({neighbour, col});
168- // Need to actually verify that the to and fromArc are opposites (or
169- // can't exist together)
166+ // Need to verify that the to and fromArc exist and are opposites
170167 if (toArc == adjacency.end () || fromArc == adjacency.end () ||
171168 std::get<1 >(fromArc->second ) != std::get<1 >(toArc->second ) ||
172169 std::get<2 >(fromArc->second ) == std::get<2 >(toArc->second )) {
@@ -176,46 +173,44 @@ bool HighsMachineSchedSeparator::findSingleMachineScheduleClique(
176173 }
177174 if (!valid_neighbour) continue ;
178175 size_t newNeighbourIndex = neighbours.size ();
179- inds.emplace_back ();
180- inds.back ().reserve (std::min (largestDegree, 50 ));
176+ // Extract the processing times from the arcs
181177 for (size_t i = 0 ; i != neighbours.size (); ++i) {
182178 HighsInt neighbour = neighbours[i];
183179 const auto fromArc = adjacency.find ({col, neighbour});
184180 const auto toArc = adjacency.find ({neighbour, col});
185- inds[i].emplace_back (std::get<1 >(toArc->second ));
186181 processingTimes[newNeighbourIndex] = std::min (
187- processingTimes[newNeighbourIndex], std::get<0 >(toArc->second ));
188- inds[newNeighbourIndex].emplace_back (std::get<1 >(fromArc->second ));
182+ processingTimes[newNeighbourIndex], std::get<0 >(fromArc->second ));
189183 processingTimes[i] =
190- std::min (processingTimes[i], std::get<0 >(fromArc ->second ));
184+ std::min (processingTimes[i], std::get<0 >(toArc ->second ));
191185 }
192186 releasedate =
193187 std::min (mipsolver.mipdata_ ->domain .col_lower_ [col], releasedate);
194188 neighbours.emplace_back (col);
195189 }
196- if (neighbours.size () <= 3 ) return false ;
190+ if (neighbours.size () < 3 ) return false ;
197191
198- // Now populate the actual cut coefficients
199- // Currently we only have the cut indices (processing times, i.e.,
200- // coefficients, were not available before this point)
201- vals .resize (neighbours.size ());
192+ // Now populate the actual inequalities
193+ vals. resize (neighbours. size (), std::vector< double >(neighbours. size ()));
194+ inds. resize (neighbours. size (), std::vector<HighsInt>(neighbours. size ()));
195+ rhss .resize (neighbours.size ());
202196 for (size_t i = 0 ; i != neighbours.size (); ++i) {
203197 rhss[i] -= releasedate;
204198 HighsInt col = neighbours[i];
205- vals[i].resize (inds[i].size () + 1 );
206- for (size_t j = 0 ; j != inds[i].size (); ++j) {
199+ for (size_t j = 0 ; j != neighbours.size (); ++j) {
207200 size_t jj = j >= i ? j + 1 : j;
201+ if (jj >= neighbours.size ()) continue ;
208202 HighsInt neighbour = neighbours[jj];
209- const auto arc = adjacency.find ({neighbour, col});
210- assert (arc != adjacency.end ());
203+ const auto toArc = adjacency.find ({neighbour, col});
204+ assert (toArc != adjacency.end ());
205+ inds[i][j] = std::get<1 >(toArc->second );
211206 vals[i][j] = processingTimes[jj];
212- if (std::get<2 >(arc ->second ) == ArcType::kIfBinZero ) {
207+ if (std::get<2 >(toArc ->second ) == ArcType::kIfBinZero ) {
213208 rhss[i] -= vals[i][j];
214209 vals[i][j] *= -1 ;
215210 }
216211 }
217212 // Put the job start time on the LHS
218- inds[i].emplace_back (neighbours[i]) ;
213+ inds[i].back () = col ;
219214 vals[i].back () = -1 ;
220215 }
221216
@@ -232,7 +227,7 @@ void HighsMachineSchedSeparator::separateLpSolution(
232227 std::vector<double > rhss;
233228 double releasedate;
234229 has_single_machine_schedule =
235- findSingleMachineScheduleClique (vals, inds, rhss, releasedate, mip);
230+ findSingleMachineScheduleClique (vals, inds, rhss, releasedate, mip);
236231 if (!has_single_machine_schedule) {
237232 separated = true ;
238233 return ;
@@ -246,7 +241,8 @@ void HighsMachineSchedSeparator::separateLpSolution(
246241 viol += lpSolution[inds[i][j]] * vals[i][j];
247242 }
248243 if (viol >= 10 * mip.mipdata_ ->feastol )
249- cutpool.addCut (mip, inds[i].data (), vals[i].data (), inds[i].size (), rhss[i]);
244+ cutpool.addCut (mip, inds[i].data (), vals[i].data (), inds[i].size (),
245+ rhss[i]);
250246 }
251247 separated = true ;
252248}
0 commit comments