Skip to content

Commit 9d4b2e5

Browse files
committed
Finish draft
1 parent 74a36d3 commit 9d4b2e5

File tree

3 files changed

+59
-56
lines changed

3 files changed

+59
-56
lines changed

highs/mip/HighsPathSeparator.cpp

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "mip/HighsLpRelaxation.h"
1616
#include "mip/HighsMipSolverData.h"
1717
#include "mip/HighsTransformedLp.h"
18+
#include "pdqsort.h"
1819

1920
enum class RowType : int8_t {
2021
kUnusuable = -2,
@@ -58,10 +59,7 @@ void HighsPathSeparator::separateLpSolution(HighsLpRelaxation& lpRelaxation,
5859
}
5960

6061
std::vector<HighsInt> numContinuous(lp.num_row_);
61-
// Score will be used for deciding order in which rows get aggregated
62-
// TODO: The second entry is currently a hacky way to store the norm
63-
std::vector<std::pair<double, double>> rowscore(lp.num_row_,
64-
std::make_pair(0.0, 0.0));
62+
6563
size_t maxAggrRowSize = 0;
6664
for (HighsInt col : mip.mipdata_->continuous_cols) {
6765
if (transLp.boundDistance(col) == 0.0) continue;
@@ -70,10 +68,6 @@ void HighsPathSeparator::separateLpSolution(HighsLpRelaxation& lpRelaxation,
7068
for (HighsInt i = lp.a_matrix_.start_[col];
7169
i != lp.a_matrix_.start_[col + 1]; ++i) {
7270
++numContinuous[lp.a_matrix_.index_[i]];
73-
// Add the fractional score of the row
74-
rowscore[i].first +=
75-
lp.a_matrix_.value_[i] * transLp.getFracVbEstimate(col);
76-
rowscore[i].second += lp.a_matrix_.value_[i];
7771
}
7872
}
7973

@@ -114,6 +108,25 @@ void HighsPathSeparator::separateLpSolution(HighsLpRelaxation& lpRelaxation,
114108
rowtype[i] = RowType::kUnusuable;
115109
}
116110

111+
// Score will be used for deciding order in which rows get aggregated
112+
std::vector<std::pair<double, double>> rowscore(lp.num_row_,
113+
std::make_pair(0.0, 0.0));
114+
for (HighsInt col = 0; col != lp.num_col_; ++col) {
115+
for (HighsInt i = lp.a_matrix_.start_[col];
116+
i != lp.a_matrix_.start_[col + 1]; ++i) {
117+
HighsInt row = lp.a_matrix_.index_[i];
118+
double val = lp.a_matrix_.value_[i];
119+
rowscore[row].first += std::abs(val * transLp.getColFractionality(col));
120+
rowscore[row].second += std::abs(val);
121+
}
122+
}
123+
for (HighsInt row = 0; row != lp.num_row_; ++row) {
124+
if (rowscore[row].second > 0) {
125+
rowscore[row].first /= rowscore[row].second;
126+
rowscore[row].second = 1;
127+
}
128+
}
129+
117130
// for each continuous variable with nonzero transformed solution value
118131
// remember the <= and == rows where it is present with a positive coefficient
119132
// in its set of in-arc rows. Treat >= rows as <= rows with reversed sign
@@ -170,6 +183,20 @@ void HighsPathSeparator::separateLpSolution(HighsLpRelaxation& lpRelaxation,
170183

171184
colInArcs[col].second = inArcRows.size();
172185
colOutArcs[col].second = outArcRows.size();
186+
187+
// Sort the in and outgoing arcs by their scores
188+
pdqsort(inArcRows.begin() + colInArcs[col].first,
189+
inArcRows.begin() + colInArcs[col].second,
190+
[&](const std::pair<HighsInt, double>& i,
191+
const std::pair<HighsInt, double>& j) {
192+
return rowscore[i.first] > rowscore[j.first];
193+
});
194+
pdqsort(outArcRows.begin() + colOutArcs[col].first,
195+
outArcRows.begin() + colOutArcs[col].second,
196+
[&](const std::pair<HighsInt, double>& i,
197+
const std::pair<HighsInt, double>& j) {
198+
return rowscore[i.first] > rowscore[j.first];
199+
});
173200
}
174201

175202
HighsCutGeneration cutGen(lpRelaxation, cutpool);
@@ -266,31 +293,9 @@ void HighsPathSeparator::separateLpSolution(HighsLpRelaxation& lpRelaxation,
266293
const std::vector<std::pair<HighsInt, HighsInt>>& colArcs,
267294
const std::vector<std::pair<HighsInt, double>>& arcRows,
268295
HighsInt& row, double& weight) {
269-
HighsInt arcRow = randgen.integer(colArcs[bestArcCol].first,
270-
colArcs[bestArcCol].second);
271-
HighsInt r = arcRows[arcRow].first;
272-
double w = -val / arcRows[arcRow].second;
273-
if (!isRowInCurrentPath(r) && checkWeight(w)) {
274-
row = r;
275-
weight = w;
276-
return true;
277-
}
278-
279-
for (HighsInt nextRow = arcRow + 1;
280-
nextRow < colArcs[bestArcCol].second; ++nextRow) {
281-
r = arcRows[nextRow].first;
282-
w = -val / arcRows[nextRow].second;
283-
if (!isRowInCurrentPath(r) && checkWeight(w)) {
284-
row = r;
285-
weight = w;
286-
return true;
287-
}
288-
}
289-
290-
for (HighsInt nextRow = colArcs[bestArcCol].first; nextRow < arcRow;
291-
++nextRow) {
292-
r = arcRows[nextRow].first;
293-
w = -val / arcRows[nextRow].second;
296+
for (HighsInt arcRow = colArcs[bestArcCol].first; arcRow != colArcs[bestArcCol].second; ++arcRow) {
297+
HighsInt r = arcRows[arcRow].first;
298+
double w = -val / arcRows[arcRow].second;
294299
if (!isRowInCurrentPath(r) && checkWeight(w)) {
295300
row = r;
296301
weight = w;

highs/mip/HighsTransformedLp.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ HighsTransformedLp::HighsTransformedLp(const HighsLpRelaxation& lprelaxation,
3232
std::make_pair(-1, HighsImplications::VarBound()));
3333
boundTypes.resize(numTransformedCol);
3434
vectorsum.setDimension(numTransformedCol);
35+
colFractionality.resize(lprelaxation.numCols());
3536

3637
for (HighsInt col : mipsolver.mipdata_->continuous_cols) {
3738
mipsolver.mipdata_->implications.cleanupVarbounds(col);
@@ -57,9 +58,26 @@ HighsTransformedLp::HighsTransformedLp(const HighsLpRelaxation& lprelaxation,
5758
if (ubDist[col] <= mipsolver.mipdata_->feastol) ubDist[col] = 0.0;
5859

5960
boundDist[col] = std::min(lbDist[col], ubDist[col]);
61+
62+
if (lbDist[col] <= ubDist[col] && lbDist[col] <= simpleLbDist[col] &&
63+
bestVlb[col].first != -1) {
64+
const double frac =
65+
std::min(lpSolution.col_value[bestVlb[col].first],
66+
1 - lpSolution.col_value[bestVlb[col].first]);
67+
colFractionality[col] = bestVlb[col].second.coef * frac;
68+
} else if (ubDist[col] <= lbDist[col] && ubDist[col] <= simpleUbDist[col] &&
69+
bestVub[col].first != -1) {
70+
const double frac =
71+
std::min(lpSolution.col_value[bestVub[col].first],
72+
1 - lpSolution.col_value[bestVub[col].first]);
73+
colFractionality[col] = bestVub[col].second.coef * frac;
74+
}
6075
}
6176

6277
for (HighsInt col : mipsolver.mipdata_->integral_cols) {
78+
double frac =
79+
lpSolution.col_value[col] - std::floor(lpSolution.col_value[col]);
80+
colFractionality[col] = std::min(frac, 1 - frac);
6381
double bestub = mipsolver.mipdata_->domain.col_upper_[col];
6482
double bestlb = mipsolver.mipdata_->domain.col_lower_[col];
6583

highs/mip/HighsTransformedLp.h

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
#include <vector>
1818

19-
#include "HighsLpRelaxation.h"
2019
#include "lp_data/HConst.h"
2120
#include "mip/HighsImplications.h"
2221
#include "util/HighsCDouble.h"
@@ -38,6 +37,7 @@ class HighsTransformedLp {
3837
std::vector<double> lbDist;
3938
std::vector<double> ubDist;
4039
std::vector<double> boundDist;
40+
std::vector<double> colFractionality;
4141
enum class BoundType : uint8_t {
4242
kSimpleUb,
4343
kSimpleLb,
@@ -53,28 +53,8 @@ class HighsTransformedLp {
5353

5454
double boundDistance(HighsInt col) const { return boundDist[col]; }
5555

56-
// TODO: Should this simple be calculated when we initialise the transLp?
57-
double getFracVbEstimate(HighsInt col) const {
58-
HighsInt vbCol = -1;
59-
double vbCoef = 0.0;
60-
if (ubDist[col] <= lbDist[col] && bestVlb[col].first != -1) {
61-
vbCol = bestVlb[col].first;
62-
vbCoef = bestVlb[col].second.coef;
63-
} else if (lbDist[col] <= ubDist[col] && bestVub[col].first != -1) {
64-
vbCol = bestVub[col].first;
65-
vbCoef = bestVub[col].second.coef;
66-
} else if (bestVlb[col].first != -1) {
67-
vbCol = bestVlb[col].first;
68-
vbCoef = bestVlb[col].second.coef;
69-
} else if (bestVub[col].first != -1) {
70-
vbCol = bestVub[col].first;
71-
vbCoef = bestVub[col].second.coef;
72-
}
73-
if (vbCol == -1) return 0;
74-
// TODO: This differs from the SCIP definition? Their frac can be > 1?
75-
double val = vbCoef * lprelaxation.solutionValue(col);
76-
double frac = std::max(val - std::floor(val), 0.0);
77-
return std::min(frac, 1 - frac);
56+
double getColFractionality(HighsInt col) const {
57+
return colFractionality[col];
7858
}
7959

8060
bool transform(std::vector<double>& vals, std::vector<double>& upper,

0 commit comments

Comments
 (0)