Data
Dataset
---- 43 PARAMETER k = 25 number of points to select ---- 43 PARAMETER p points x y point1 4.97311132 9.63862756 point2 8.73922492 8.44273500 point3 1.91226253 4.94526579 point4 2.34553216 3.80983451 point5 6.00887463 1.51476321 point6 5.07716895 4.63323882 point7 3.59064347 1.52625715 point8 3.66418827 8.26045475 point9 0.23893508 0.59261597 point10 2.84759145 1.14012489 point11 8.90454986 3.74340300 point12 2.34069434 1.47696552 point13 0.19119162 0.78401936 point14 9.27971966 5.55039788 point15 6.16361826 3.60477909 point16 5.21416943 4.32016162 point17 7.49929678 8.17376279 point18 0.16037081 3.72949918 point19 6.97091674 7.66895295 point20 8.87457833 8.11673997 point21 7.89650246 8.03634493 point22 0.16576575 3.93244606 point23 9.60138480 7.21520825 point24 8.14734411 8.37501191 point25 7.74541956 5.28258128 point26 6.55663865 3.92384422 point27 4.85091115 4.02642582 point28 4.34623796 1.93472329 point29 1.28959803 4.87601902 point30 7.91163148 6.85615242 point31 3.02621818 0.00063517 point32 4.46278421 8.14820541 point33 2.08022534 3.35953314 point34 2.81600217 1.56499252 point35 6.20283636 8.59944445 point36 6.15258941 3.85719583 point37 7.63343999 7.31506452 point38 0.79832230 0.82942221 point39 0.19238302 2.45380498 point40 3.34088869 3.03838803 point41 8.34902953 3.86320590 point42 0.53110352 5.05611011 point43 1.91904761 2.34489699 point44 9.34705030 7.86066922 point45 9.43453787 1.71763581 point46 1.81723665 2.02565095 point47 5.32342079 5.06474382 point48 2.10786534 6.38173925 point49 2.95917598 5.53252693 point50 0.34180259 8.07512765 point51 3.55101998 9.88688936 point52 8.13607683 7.15280359 point53 2.43498983 5.41651376 point54 5.01929436 1.10750815 point55 1.68573148 2.86927244 point56 8.41569886 8.06049381 point57 5.63100458 1.57040011 point58 2.71516744 0.33909707 point59 7.18412193 7.05045720 point60 1.57713422 7.52170649 point61 9.55352881 7.85491794 point62 2.56555975 0.88005074 point63 7.99748484 2.19292948 point64 9.55568192 8.03379715 point65 4.59853976 2.02151223 point66 8.95713092 5.24080749 point67 8.71950503 9.06200769 point68 3.51902443 3.22910422 point69 9.24501444 6.34123137 point70 4.14098498 2.68712111 point71 2.81651324 7.41232701 point72 6.57107119 4.55851885 point73 3.80600433 4.96108423 point74 8.99943277 5.32278562 point75 0.60195961 3.95965993 point76 4.30151391 9.59964284 point77 2.71652476 8.77681007 point78 1.87229129 4.95157553 point79 3.73429995 4.27888100 point80 9.51936360 5.11992531 point81 4.61819146 4.18987215 point82 0.91512513 9.23192650 point83 9.52838375 6.38224088 point84 5.35277514 8.98266937 point85 0.46190997 4.24850010 point86 8.16439743 4.83398475 point87 8.05382905 3.06655684 point88 8.59419222 7.31792459 point89 5.60900115 3.90522405 point90 2.74138705 4.44598243 point91 9.81040377 2.77587450 point92 7.98768312 9.73693294 point93 5.81026191 7.96489037 point94 8.28671680 7.17813456 point95 4.33880861 2.03345798 point96 2.70771867 6.64833521 point97 1.10849014 8.46666734 point98 2.17469964 2.35013718 point99 8.99662815 8.51057738 point100 8.92751427 2.23560422 ---- 53 PARAMETER box min/max values min max x 0.160 9.810 y 0.001 9.887
Nonconvex optimization model
- Select \(k\) out of \(n\) data points
- Draw a rectangle around these points
| High-level model |
|---|
| \[\begin{align} \min\> &{\color{darkred}{\mathit{area}}} = \prod_c ({\color{darkred}{\mathit{rect}}}_{c,up}-{\color{darkred}{\mathit{rect}}}_{c,lo}) \\ & {\color{darkred}\delta}_i = 1 \implies {\color{darkblue}p}_{i,c} \in [{\color{darkred}{\mathit{rect}}}_{c,lo},{\color{darkred}{\mathit{rect}}}_{c,up}] & \forall i,c\\ & \sum_i{\color{darkred}\delta}_i = {\color{darkblue}k} \\ & {\color{darkred}\delta}_i \in \{0,1\} \\ & c \in \{x,y\} \end{align}\] |
The objective is quadratic and non-convex, so we need to use a global solver.
| Implemented model |
|---|
| \[\begin{align} \min\> &{\color{darkred}{\mathit{area}}} = {\color{darkred}d}_x \cdot{\color{darkred}d}_y \\ & {\color{darkred}d}_c = {\color{darkred}{\mathit{rect}}}_{c,up}- {\color{darkred}{\mathit{rect}}}_{c,lo} & \forall c \\ & {\color{darkred}{\mathit{rect}}}_{c,lo} \le {\color{darkred}\delta}_i {\color{darkblue}p}_{i,c} + (1-{\color{darkred}\delta}_i) {\color{darkblue}{\mathit{box}}}_{c,up} & \forall i,c \\ & {\color{darkred}{\mathit{rect}}}_{c,up} \ge {\color{darkred}\delta}_i {\color{darkblue}p}_{i,c} + (1-{\color{darkred}\delta}_i){\color{darkblue}{\mathit{box}}}_{c,lo}& \forall i,c\\ & \sum_i{\color{darkred}\delta}_i = {\color{darkblue}k} \\& {\color{darkred}{\mathit{rect}}}_{c,lo},{\color{darkred}{\mathit{rect}}}_{c,up} \in [{\color{darkblue}{\mathit{box}}}_{c,lo},{\color{darkblue}{\mathit{box}}}_{c,up}] \\ & {\color{darkred}d}_c \in [0,{\color{darkblue}{\mathit{box}}}_{c,up}-{\color{darkblue}{\mathit{box}}}_{c,lo}] \\ & {\color{darkred}\delta}_i \in \{0,1\}\\ &{\color{darkblue}{\mathit{box}}}_{c,lo} = \min_i{\color{darkblue}p}_{i,c} \\ &{\color{darkblue}{\mathit{box}}}_{c,up} = \max_i{\color{darkblue}p}_{i,c}\\ & c \in \{x,y\} \end{align}\] |
Notes:
- If we want to avoid large big-M coefficients (and we should), scale the data points. In our case, we generated points inside a \(([0,10]\times[0,10])\) square.
- All constraints are linear.
- To help global solvers, it is a good idea to use tight bounds on all variables.
- ChatGPT suggested to explicitly allow more than \(k\) points in the rectangle by changing the equality constraint into an inequality. We already allow more points in the rectangle. In the picture below, we could have some blue points inside the rectangle. As long as this does not affect optimality, that is fine. I am not sure why that proposed change is a good idea.
Solution
---- 101 VARIABLE rect2.L contain k points min max x 7.184 9.601 y 4.834 8.511 ---- 101 VARIABLE delta.L point is selected point2 1.000, point14 1.000, point17 1.000, point20 1.000, point21 1.000, point23 1.000, point24 1.000 point25 1.000, point30 1.000, point37 1.000, point44 1.000, point52 1.000, point56 1.000, point59 1.000 point61 1.000, point64 1.000, point66 1.000, point69 1.000, point74 1.000, point80 1.000, point83 1.000 point86 1.000, point88 1.000, point94 1.000, point99 1.000 ---- 101 VARIABLE area.L = 8.887 size of rectangle
- Solutions will have at least one selected point located on each side of the optimal rectangle. This property is not used in this model, but is key in algorithms for this problem.
- It is possible that non-selected (blue) points are inside the optimal rectangle. This is not the case in this particular solution. It is easy to see that this can happen if multiple points share the same coordinates.
-------------------------------------------------------------------------------
Time (s) Nodes explored Nodes remaining Best possible Best found Relative Gap
-------------------------------------------------------------------------------
0 1 1 +0.000e+00 +1.476e+01 --
4 96 0 +8.886e+00 +8.887e+00 +1.000e-04
-------------------------------------------------------------------------------
Termination Status : Global minimum
Best Feasible Point: +8.887291e+00
Best Possible Point: +8.886402e+00
Relative Gap: +1.000000e-04
Algorithms
- Sort the points \(p_i\) on \(y\) coordinate.
- Look at windows \(p_{\ell},p_u\) with \(u\ge \ell + k - 1\) (at least \(k\) points in between)
- For each \(y\) window, sort on \(x\), and look at sliding \(x\) windows of exactly \(k\) points
- Calculate the rectangle and area, and record the best.
n=100,k=25 x bounds: [7.18412193, 9.6013848] y bounds: [4.833984750000001, 8.51057738] width: 2.41726287 height: 3.67659263 area: 8.88729085261465 selected points: [2, 14, 17, 20, 21, 23, 24, 25, 30, 37, 44, 52, 56, 59, 61, 64, 66, 69, 74, 80, 83, 86, 88, 94, 99]
Variant 1: Next best cluster
solve m minimizing area using miqcp;
delta.fx(i)$(delta.l(i)>0.5) = 0;
solve m minimizing area using miqcp;
The area of the next-best solution is significantly larger than the original, best solution. This may explain why the models are fairly easy to solve.
GAMS Model
$onText
Find smallest axis-aligned rectangle containing k out of n points. References: Timothy M. Chan, Sariel Har-Peled Smallest k-Enclosing Rectangle Revisited https://arxiv.org/abs/1903.06785
$offtext
*--------------------------------------------------------------- * options *---------------------------------------------------------------
* 0: no plot * 1: produce HTML plot) $set htmlplot 0
option miqcp=antigone;
option seed=12345;
*--------------------------------------------------------------- * data *---------------------------------------------------------------
scalars maxsize 'size of the outer box' / 10 / k 'number of points to select' / 25 / ;
sets i 'points' /point1*point100/ c 'coordinates' /x,y/ lu 'lower/upper values' /min,max/ ;
parameter p(i,c) 'points'; p(i,c) = uniform(0,maxsize);
display k,p;
*--------------------------------------------------------------- * derived data *---------------------------------------------------------------
parameter box(c,lu) 'min/max values'; box(c,'min') = smin(i, p(i,c)); box(c,'max') = smax(i, p(i,c));
display box;
*--------------------------------------------------------------- * model: enclose k points *---------------------------------------------------------------
binary variable delta(i) 'point is selected';
variable rect(c,lu) 'rectangle to contain k points' d(c) 'length of sides' area 'size of rectangle' ;
* bounds rect.lo(c,lu) = box(c,'min'); rect.up(c,lu) = box(c,'max');
d.lo(c) = 0; d.up(c) = box(c,'max') - box(c,'min');
equations obj 'objective: area of enclosing rectangle' count 'number of points to select' inside_min(i,c) 'points are inside' inside_max(i,c) 'points are inside' calcd(c) 'calculate d' ;
count.. sum(i, delta(i)) =e= k;
* inside: delta(i)=1 ==> rect(c,'min') <= p(i,c) <= rect(c,'max') inside_min(i,c).. rect(c,'min') =l= delta(i)*p(i,c) + (1-delta(i))*box(c,'max'); inside_max(i,c).. rect(c,'max') =g= delta(i)*p(i,c) + (1-delta(i))*box(c,'min');
calcd(c).. d(c) =e= rect(c,'max')-rect(c,'min');
obj.. area =e= d('x')*d('y');
model m /all/; solve m minimizing area using miqcp;
display rect.l,delta.l,area.l;
*--------------------------------------------------------------------- * algorithm *---------------------------------------------------------------------
scalar n; n = card(i);
embeddedCode Python:
n = int(list(gams.get("n"))[0]); k = int(list(gams.get("k"))[0]); print(f"n={n},k={k}")
# get points and store as list of tuples (id,x,y) points=[] pgen = gams.get("p",keyFormat=KeyFormat.FLAT) for i in range(n): px = next(pgen) py = next(pgen) points.append((i+1,px[2],py[2]))
# the rest was largely generated by ChatGPT
y_values = sorted({y for _, _, y in points})
best = None
# Try every possible bottom and top edge. for i, bottom in enumerate(y_values): for top in y_values[i:]: # Points inside this horizontal band, sorted by x. in_band = sorted( (x, number) for number, x, y in points if bottom <= y <= top )
if len(in_band) < k: continue
# Any minimal-width interval containing k points can be # represented by k consecutive points in this sorted list. for start in range(len(in_band) - k + 1): left = in_band[start][0] right = in_band[start + k - 1][0] width = right - left height = top - bottom area = width * height
if best is None or area < best["area"]: best = { "area": area, "left": left, "right": right, "bottom": bottom, "top": top, "point_numbers": [ number for _, number in in_band[start:start + k] ], }
print(f"x bounds: [{best['left']}, {best['right']}]") print(f"y bounds: [{best['bottom']}, {best['top']}]") print(f"width: {best['right'] - best['left']}") print(f"height: {best['top'] - best['bottom']}") print(f"area: {best['area']}") print(f"selected points: {sorted(best['point_numbers'])}")
endEmbeddedCode
*--------------------------------------------------------------------- * visualization *---------------------------------------------------------------------
$set html plot.html $set data data.js
$if %htmlplot%==0 $goto skipplot
file fdata /%data%/; put fdata;
* points put "p=["/; loop(i, put " {i:'",i.tl:0,"',x:",p(i,'x'):0:4,",y:",p(i,'y'):0:4,",delta:"; put$(delta.l(i)>0.5) "'red'"; put$(delta.l(i)<0.5) "'darkblue'"; put "},"/; ); put "]"/; put "pnts={n:",(card(i)):0:0, ",map:'[0,",maxsize:0:0,"]×[0,",maxsize:0:0,"]'", ",minx:",box('x','min'):0:3, ",miny:",box('y','min'):0:3, ",maxx:",box('x','max'):0:3, ",maxy:",box('y','max'):0:3, ",avgx:",(sum(i,p(i,'x'))/card(i)):0:3, ",avgy:",(sum(i,p(i,'y'))/card(i)):0:3, ",k:",k:0:0, ",rxmin:",(rect.l('x','min')):0:3, ",rxmax:",(rect.l('x','max')):0:3, ",rymin:",(rect.l('y','min')):0:3, ",rymax:",(rect.l('y','max')):0:3, ",area:",(area.l):0:3, "}"/;
putclose;
$onecho > %html% <html> <script src="https://cdn.plot.ly/plotly-3.4.0.min.js" charset="utf-8"></script> <script src="%data%" charset="utf-8"></script> <style> .brdr { border: 1px solid black; border-collapse: collapse; } th, td { padding-left: 4px; padding-right: 4px; } </style>
<h1>Data</h1> <table><tr><td> <table class="brdr"> <tr><th colspan=2 class="brdr">points</th></tr> <tr><td class="brdr">𝑛</td><td class="brdr" id="d_n"></td></tr> <tr><td class="brdr">map</td><td class="brdr" id="d_map"></td></tr> <tr><td class="brdr">min 𝑥</td><td class="brdr" id="d_minx"></td></tr> <tr><td class="brdr">max 𝑥</td><td class="brdr" id="d_maxx"></td></tr> <tr><td class="brdr">avg 𝑥</td><td class="brdr" id="d_avgx"></td></tr> <tr><td class="brdr">min 𝑦</td><td class="brdr" id="d_miny"></td></tr> <tr><td class="brdr">max 𝑦</td><td class="brdr" id="d_maxy"></td></tr> <tr><td class="brdr">avg 𝑦</td><td class="brdr" id="d_avgy"></td></tr> </table> </td><td> <div id="plotDiv0" style="width: 800px; height: 600px;"></div> </td></tr></table>
<h1>Smallest Rectangle</h1> <table><tr><td> <table class="brdr"> <tr><th colspan=2 class="brdr">solution</th></tr> <tr><td class="brdr">𝑛</td><td class="brdr" id="d_n2"></td></tr> <tr><td class="brdr">𝑘</td><td class="brdr" id="d_k"></td></tr> <tr><td class="brdr">𝑥min</td><td class="brdr" id="xmin">0</td></tr> <tr><td class="brdr">𝑥max</td><td class="brdr" id="xmax">0</td></tr> <tr><td class="brdr">𝑦min</td><td class="brdr" id="ymin">0</td></tr> <tr><td class="brdr">𝑦max</td><td class="brdr" id="ymax">0</td></tr> <tr><td class="brdr">area</td><td class="brdr" id="area">0</td></tr> </table> </td><td> <div id="plotDiv1" style="width: 800px; height: 600px;"></div> </td></tr></table>
<script>
document.getElementById("d_n").innerHTML = pnts['n']; document.getElementById("d_map").innerHTML = pnts['map']; document.getElementById("d_minx").innerHTML = pnts['minx']; document.getElementById("d_maxx").innerHTML = pnts['maxx']; document.getElementById("d_miny").innerHTML = pnts['miny']; document.getElementById("d_maxy").innerHTML = pnts['maxy']; document.getElementById("d_avgx").innerHTML = pnts['avgx']; document.getElementById("d_avgy").innerHTML = pnts['avgy'];
document.getElementById("d_n2").innerHTML = pnts['n']; document.getElementById("d_k").innerHTML = pnts['k']; document.getElementById("xmin").innerHTML = pnts['rxmin']; document.getElementById("xmax").innerHTML = pnts['rxmax']; document.getElementById("ymin").innerHTML = pnts['rymin']; document.getElementById("ymax").innerHTML = pnts['rymax']; document.getElementById("area").innerHTML = pnts['area'];
px = p.map((x) => x['x']) py = p.map((x) => x['y']) delta = p.map((x) => x['delta'])
var data1 = { x: px, y: py, mode: 'markers', type: 'scatter', name: 'data points', color: 'darkblue' };
var layout1 = { autosize: false, width: 650, height: 600, showlegend: false, title: {text:"Data Points"}, }
var data2 = { x: px, y: py, mode: 'markers', type: 'scatter', name: 'solution', marker: { color: delta }, showlegend: false,
};
var layout2 = { autosize: false, width: 650, height: 600, showlegend: false, title: {text:"Solution"}, shapes: [{type:'rect', xref:'x', yref:'y', x0:pnts['rxmin'], y0:pnts['rymin'], x1:pnts['rxmax'], y1:pnts['rymax'], line:{color:'darkred',width:2,opacity:0.5}, fillcolor:'rgba(0, 255, 255, 0.5)', },] }
var trc1 = [data1]; var options1 = {staticPlot: true, displayModeBar: false, responsive: false}; Plotly.newPlot('plotDiv0', trc1, layout1, options1);
var trc2 = [data2]; var options2 = {staticPlot: true, displayModeBar: false, responsive: false}; Plotly.newPlot('plotDiv1', trc2, layout2, options2);
</script> </html> $offecho
executetool 'win32.ShellExecute "%html%"';
$label skipplot
|
Variant 2: 3d weight constrained model
Dataset
---- 42 PARAMETER minWeight = 25.000 required total weight ---- 42 PARAMETER p points x y z w point1 4.97311132 9.63862756 8.73922492 0.48694222 point2 8.44273500 1.91226253 4.94526579 1.97392086 point3 2.34553216 3.80983451 6.00887463 1.88604759 point4 1.51476321 5.07716895 4.63323882 2.84102226 point5 3.59064347 1.52625715 3.66418827 0.28598810 point6 8.26045475 0.23893508 0.59261597 0.74594589 point7 2.84759145 1.14012489 8.90454986 1.43031631 point8 3.74340300 2.34069434 1.47696552 2.91848795 point9 0.19119162 0.78401936 9.27971966 0.24722803 point10 5.55039788 6.16361826 3.60477909 1.54572707 point11 5.21416943 4.32016162 7.49929678 1.44839493 point12 8.17376279 0.16037081 3.72949918 0.35158607 point13 6.97091674 7.66895295 8.87457833 1.40797918 point14 8.11673997 7.89650246 8.03634493 0.01746947 point15 0.16576575 3.93244606 9.60138480 2.82216428 point16 7.21520825 8.14734411 8.37501191 2.86088036 point17 7.74541956 5.28258128 6.55663865 2.15518773 point18 3.92384422 4.85091115 4.02642582 0.49230636 point19 4.34623796 1.93472329 1.28959803 2.66902215 point20 4.87601902 7.91163148 6.85615242 2.64424362 point21 3.02621818 0.00063517 4.46278421 1.06793976 point22 8.14820541 2.08022534 3.35953314 0.37095954 point23 2.81600217 1.56499252 6.20283636 2.20711958 point24 8.59944445 6.15258941 3.85719583 2.47151690 point25 7.63343999 7.31506452 0.79832230 0.09003760 point26 0.82942221 0.19238302 2.45380498 0.98465450 point27 3.34088869 3.03838803 8.34902953 2.26614420 point28 3.86320590 0.53110352 5.05611011 0.48269769 point29 1.91904761 2.34489699 9.34705030 2.36613572 point30 7.86066922 9.43453787 1.71763581 1.12082503 point31 1.81723665 2.02565095 5.32342079 2.22454539 point32 5.06474382 2.10786534 6.38173925 0.49201408 point33 2.95917598 5.53252693 0.34180259 1.39078968 point34 8.07512765 3.55101998 9.88688936 0.21046279 point35 8.13607683 7.15280359 2.43498983 1.08584045 point36 5.41651376 5.01929436 1.10750815 0.32816410 point37 1.68573148 2.86927244 8.41569886 0.70203212 point38 8.06049381 5.63100458 1.57040011 1.03604428 point39 2.71516744 0.33909707 7.18412193 0.67756099 point40 7.05045720 1.57713422 7.52170649 2.86265273 point41 9.55352881 7.85491794 2.56555975 1.67214859 point42 0.88005074 7.99748484 2.19292948 0.49649330 point43 9.55568192 8.03379715 4.59853976 2.83082090 point44 2.02151223 8.95713092 5.24080749 1.85253269 point45 8.71950503 9.06200769 3.51902443 2.85107000 point46 3.22910422 9.24501444 6.34123137 0.55814034 point47 4.14098498 2.68712111 2.81651324 1.00289323 point48 7.41232701 6.57107119 4.55851885 0.38501468 point49 3.80600433 4.96108423 8.99943277 2.99576587 point50 5.32278562 0.60195961 3.95965993 2.38442606 point51 4.30151391 9.59964284 2.71652476 2.04875708 point52 8.77681007 1.87229129 4.95157553 2.26472630 point53 3.73429995 4.27888100 9.51936360 1.21839747 point54 5.11992531 4.61819146 4.18987215 0.81940347 point55 0.91512513 9.23192650 9.52838375 0.04029898 point56 6.38224088 5.35277514 8.98266937 0.04989643 point57 0.46190997 4.24850010 8.16439743 2.37151490 point58 4.83398475 8.05382905 3.06655684 2.88987083 point59 8.59419222 7.31792459 5.60900115 0.02396737 point60 3.90522405 2.74138705 4.44598243 2.18304321 point61 9.81040377 2.77587450 7.98768312 1.13544649 point62 9.73693294 5.81026191 7.96489037 2.16547194 point63 8.28671680 7.17813456 4.33880861 2.37657744 point64 2.03345798 2.70771867 6.64833521 2.48492345 point65 1.10849014 8.46666734 2.17469964 1.44539345 point66 2.35013718 8.99662815 8.51057738 0.33858711 point67 8.92751427 2.23560422 2.24591679 0.84037876 point68 8.66033570 8.13866369 3.55150241 2.57050056 point69 2.38252571 6.77980742 0.04611403 2.81595325 point70 4.86160682 6.21125032 0.99224055 2.76802585 point71 6.95409069 1.54137047 4.72319908 0.51330419 point72 1.48556645 0.52138555 2.59667923 2.03764570 point73 5.23274123 5.67431764 0.51242147 2.65722595 point74 0.46637606 7.84666623 3.42950908 1.99782248 point75 9.12075148 6.62127069 3.16943360 1.22121036 point76 9.32398470 8.61141502 5.43944178 1.40091651 point77 9.90875460 8.64934732 5.54423034 0.04479335 point78 7.61158446 3.40928578 9.43670811 0.69092216 point79 8.94830907 0.49443490 4.59025930 0.04885652 point80 5.25949368 0.48432727 3.50423564 0.43704578 point81 9.71403687 5.77860854 5.44716786 2.60240596 point82 2.39148403 8.53557465 1.92326606 1.99617675 point83 9.86191789 3.84063928 1.07906650 2.81705489 point84 8.84041273 6.22256973 2.61438727 1.10294490 point85 3.15780224 9.94484490 1.77369425 2.61049940 point86 7.99741669 0.49593827 3.30467894 1.84808825 point87 5.49767336 9.31596887 8.18561520 0.88339756 point88 2.72818944 9.25260567 2.30602627 2.23725467 point89 8.25085350 2.50810826 1.73096670 0.26801162 point90 1.94732458 3.49788333 0.78445261 1.61420166 point91 6.78641732 7.26785086 7.38760084 1.02966832 point92 3.33428691 6.12756745 7.54948123 1.35768156 point93 1.80636836 2.54101527 0.33444540 1.09511773 point94 3.69935940 8.37069102 6.12492871 1.79299763 point95 0.67172074 0.18046144 7.82525390 1.76851896 point96 0.39180678 2.78360137 2.23733221 0.43721792 point97 4.74344419 8.89007749 1.08722063 1.24374664 point98 5.05399142 8.07553458 8.84330606 2.31860623 point99 4.60749515 0.89989148 2.21880935 2.98406425 point100 4.21063606 5.03441875 0.29718500 1.07116102
The model only needs minor changes.
| 3d weight constrained model |
|---|
| \[\begin{align} \min\> &{\color{darkred}{\mathit{volume}}} = {\color{darkred}d}_x \cdot{\color{darkred}d}_y\cdot{\color{darkred}d}_z \\ & {\color{darkred}d}_c = {\color{darkred}{\mathit{sbox}}}_{c,up}- {\color{darkred}{\mathit{sbox}}}_{c,lo} & \forall c \\ & {\color{darkred}{\mathit{sbox}}}_{c,lo} \le {\color{darkred}\delta}_i {\color{darkblue}p}_{i,c} + (1-{\color{darkred}\delta}_i) {\color{darkblue}{\mathit{box}}}_{c,up} & \forall i,c \\ & {\color{darkred}{\mathit{sbox}}}_{c,up} \ge {\color{darkred}\delta}_i {\color{darkblue}p}_{i,c} + (1-{\color{darkred}\delta}_i){\color{darkblue}{\mathit{box}}}_{c,lo}& \forall i,c\\ & \sum_i{\color{darkblue}p}_{i,w} {\color{darkred}\delta}_i \ge {\color{darkblue}{\mathit{minWeight}}} \\& {\color{darkred}{\mathit{sbox}}}_{c,lo},{\color{darkred}{\mathit{sbox}}}_{c,up} \in [{\color{darkblue}{\mathit{box}}}_{c,lo},{\color{darkblue}{\mathit{box}}}_{c,up}] \\ & {\color{darkred}d}_c \in [0,{\color{darkblue}{\mathit{box}}}_{c,up}-{\color{darkblue}{\mathit{box}}}_{c,lo}] \\ & {\color{darkred}\delta}_i \in \{0,1\}\\ &{\color{darkblue}{\mathit{box}}}_{c,lo} = \min_i{\color{darkblue}p}_{i,c} \\ &{\color{darkblue}{\mathit{box}}}_{c,up} = \max_i{\color{darkblue}p}_{i,c}\\ & c \in \{x,y,z\} \end{align}\] |
---- 102 VARIABLE sbox.L box to contain selected points min max x 8.287 9.714 y 1.872 9.062 z 2.566 5.447 ---- 102 VARIABLE delta.L point is selected point2 1.000, point24 1.000, point41 1.000, point43 1.000, point45 1.000, point52 1.000, point63 1.000 point68 1.000, point75 1.000, point76 1.000, point81 1.000, point84 1.000 ---- 102 VARIABLE volume.L = 29.571 size of box PARAMETER count = 12.000 number of selected points PARAMETER totw = 25.339 total weight of selected points
-------------------------------------------------------------------------------
Time (s) Nodes explored Nodes remaining Best possible Best found Relative Gap
-------------------------------------------------------------------------------
0 1 1 +0.000e+00 +1.127e+02 --
4 41 0 +2.957e+01 +2.957e+01 +1.000e-04
-------------------------------------------------------------------------------
Termination Status : Global minimum
Best Feasible Point: +2.957114e+01
Best Possible Point: +2.956818e+01
Relative Gap: +1.000000e-04
GAMS Model
$onText
Find smallest axis-aligned 3d containing box containing a subset of given 3d points such that the total weight of the points inside the box is larger than a given number.
$offText
*--------------------------------------------------------------- * options *---------------------------------------------------------------
option minlp=antigone;
option seed=12345;
*--------------------------------------------------------------- * data *---------------------------------------------------------------
scalars maxsize 'size of the outer box' / 10 / minWeight 'required total weight' / 25 / ;
sets i 'points' /point1*point100/ a 'attributes (coordinates,weight)' /x,y,z,w/ c(a) 'coordinates' /x,y,z/ lu 'lower/upper values' /min,max/ ;
parameters p(i,a) 'points'; p(i,c) = uniform(0,maxsize); p(i,'w') = uniform(0,3); display minWeight,p;
*--------------------------------------------------------------- * derived data *---------------------------------------------------------------
parameter box(c,lu) 'outer box: min/max values'; box(c,'min') = smin(i, p(i,c)); box(c,'max') = smax(i, p(i,c)); display box;
*--------------------------------------------------------------- * model: enclose k points *---------------------------------------------------------------
binary variable delta(i) 'point is selected';
variable sbox(c,lu) 'box to contain selected points' d(c) 'length of sides' volume 'size of box' ;
* bounds sbox.lo(c,lu) = box(c,'min'); sbox.up(c,lu) = box(c,'max');
d.lo(c) = 0; d.up(c) = box(c,'max') - box(c,'min');
equations obj 'objective: area of enclosing rectangle' sumweight 'weight restriction' inside_min(i,c) 'points are inside' inside_max(i,c) 'points are inside' calcd(c) 'calculate d' ;
sumweight.. sum(i, p(i,'w')*delta(i)) =g= minWeight;
* inside: delta(i)=1 ==> sbox(c,'min') <= p(i,c) <= sbox(c,'max') inside_min(i,c).. sbox(c,'min') =l= delta(i)*p(i,c) + (1-delta(i))*box(c,'max'); inside_max(i,c).. sbox(c,'max') =g= delta(i)*p(i,c) + (1-delta(i))*box(c,'min');
calcd(c).. d(c) =e= sbox(c,'max')-sbox(c,'min');
obj.. volume =e= d('x')*d('y')*d('z');
model m /all/; solve m minimizing volume using minlp;
scalars count 'number of selected points' totw 'total weight of selected points' ; count = sum(i$(delta.l(i)>0.5),1); totw = sum(i$(delta.l(i)>0.5),p(i,'w'));
display sbox.l,delta.l,volume.l,count,totw; |
Variant 3: max number of points
| Max Covered Points model |
|---|
| \[\begin{align} \max\> &{\color{darkred}{k}}=\sum_i{\color{darkred}\delta}_i \\ & {\color{darkblue}{\mathit{area}}} = {\color{darkred}d}_x \cdot{\color{darkred}d}_y \\ & {\color{darkred}d}_c = {\color{darkred}{\mathit{rect}}}_{c,up}- {\color{darkred}{\mathit{rect}}}_{c,lo} & \forall c \\ & {\color{darkred}{\mathit{rect}}}_{c,lo} \le {\color{darkred}\delta}_i {\color{darkblue}p}_{i,c} + (1-{\color{darkred}\delta}_i) {\color{darkblue}{\mathit{box}}}_{c,up} & \forall i,c \\ & {\color{darkred}{\mathit{rect}}}_{c,up} \ge {\color{darkred}\delta}_i {\color{darkblue}p}_{i,c} + (1-{\color{darkred}\delta}_i){\color{darkblue}{\mathit{box}}}_{c,lo}& \forall i,c\\& {\color{darkred}{\mathit{rect}}}_{c,lo},{\color{darkred}{\mathit{rect}}}_{c,up} \in [{\color{darkblue}{\mathit{box}}}_{c,lo},{\color{darkblue}{\mathit{box}}}_{c,up}] \\ & {\color{darkred}d}_c \in [0,{\color{darkblue}{\mathit{box}}}_{c,up}-{\color{darkblue}{\mathit{box}}}_{c,lo}] \\ & {\color{darkred}\delta}_i \in \{0,1\} \\ &{\color{darkblue}{\mathit{box}}}_{c,lo} = \min_i{\color{darkblue}p}_{i,c}\\ &{\color{darkblue}{\mathit{box}}}_{c,up} = \max_i{\color{darkblue}p}_{i,c}\\ & c \in \{x,y\} \end{align}\] |
Global solvers have no problem with the non-convex quadratic objective becoming a constraint.
I.e., we can find a rectangle with a given area of 10 that contains 26 points. In general, the solution is not unique (we may move the rectangle around a little bit).
Solver issues
- Somehow Baron gives up on these models with the message:
A potentially catastrophic access violation just took place
I have passed on the model to the GAMS people for further investigation. I don't have a workaround for this. - Xpress gives for the second-best model a slightly non-optimal solution:
Other solvers find a second solution of 12.99. This may be a tolerance issue, although Xpress thinks this is globally optimal:
... Status: Normal (1) / Global Optimal (1)
... Objective Value: 1.305122276856e+01
... Objective Bound: 1.305122276856e+01
... Optimality Gap: 0.000000000000e+00 (0.00%)
After changing the optimality tolerance from 1e-6 to 1e-7, Xpress delivers the solution of 12.99.
... Status: Normal (1) / Global Optimal (1)
... Objective Value: 1.299035980013e+01
... Objective Bound: 1.299035980013e+01
... Optimality Gap: 0.000000000000e+00 (0.00%)
In general, I don't like changing solver tolerances, but this was a useful exercise. It confirms that we are dealing with a tolerance issue.
Conclusion
References
- Eppstein, D., Erickson, J. Iterated nearest neighbors and finding minimal polytopes. Discrete Comput Geom 11, 321–350 (1994). https://doi.org/10.1007/BF02574012
- Timothy M. Chan and Sariel Har-Peled, Smallest k-Enclosing Rectangle Revisited, 2019, https://arxiv.org/abs/1903.06785.

No comments:
Post a Comment