Propagating the minimum distance between selected pointsDRAFT
Selecting well-spaced points has a compact mathematical statement, but its straightforward CP model creates a distance variable for every selected pair. My ModRef 2026 paper Propagation Algorithms for the Minimum-Distance Constraint over Selected Points studies what happens when Gecode handles that relation directly.
Suppose we want to select five facility locations so that the closest pair is as far apart as possible. Let z denote that minimum distance. The straightforward CP model introduces a distance variable for every selected pair, then constrains z to be the minimum of those distances. The specification is clear, but the number of auxiliary variables and propagators grows quadratically.
I implemented several ways for Gecode to handle that relation directly: small pairwise propagators, global support scans, advisor-backed versions that remember which pairs need to be revisited, and an upper bound based on matchings in a conflict graph.
A small instance
Consider the eight candidate sites below. We must choose five. The highlighted selection {A, C, E, F, G} has minimum distance 4, attained by F and G.
This selection gives us a lower bound of 4. The next larger pair-distance level is 5, so proving optimality means ruling out every selection whose minimum distance is at least 5. The matching bound below does exactly that.
Propagator variants
Some variants change the inference itself. Others perform similar inference but differ in how they organise and remember the work.
| Variant | What it does |
|---|---|
| Tuple decomposition | The portable baseline: one distance variable and table constraint for each pair of selected positions. |
| Pair check | When both endpoints are fixed, uses their exact distance to tighten the upper bound on z. |
| Pairwise forward bound | When one endpoint is fixed, removes values that are too close from the other endpoint and maintains an upper bound for the pair. |
| Global forward bound | Performs the same forward-bound inference for every pair inside one global propagator. |
| Global pair support | Before either endpoint is fixed, checks that every value still has a supporting partner. This is stronger, but requires more scanning. |
| Advisor-backed forward bound | Uses advisors to revisit only affected pairs for the lighter forward-bound kernel, retaining useful pairwise witnesses between rounds. |
| Advisor-backed pair support | Uses the same scheduling and witness reuse for the stronger full pair-support kernel. |
| + matching | Adds a separate conflict-graph pass that tightens z.max. It complements the other filtering; it does not replace it. |
The advisor-backed variants change how the work is scheduled and remembered. The matching suffix adds a separate upper-bound argument.
The figure adapts the main experimental table from the paper. All 100 imported p-dispersion instances ask the solver to select well-spaced points. The MiniZinc Challenge area score rewards variants that find useful solutions early and continue improving them; higher is better. In these tests, the advisor-backed forward-bound propagator with the matching bound performs best. The simpler pairwise forward-bound propagator remains competitive. The global pair-support scan scores below the tuple decomposition in this comparison.
How the greedy maximal matching bound works
Take a candidate threshold t. Let the active sites be the union of the current selected-position domains. Build a conflict graph on those sites, with an edge between two sites when their distance is strictly less than t. A selection with minimum distance at least t must be an independent set in this graph. The propagator then computes a greedy maximal matching in the conflict graph.
Any matching gives a sound upper bound on the size of such an independent set; the propagator builds one greedily until it is maximal. Each matching edge has disjoint endpoints, and an independent set can contain at most one endpoint from each edge. If the active graph has n vertices and the matching has m edges, then the largest independent set, written α(Gₜ), satisfies
α(Gₜ) ≤ n − m.
For the eight-site instance, the conflict edges at threshold 5 are AB, AD, BG, CD, DE, EH, and FG. The four highlighted edges below form one greedy maximal matching: AB, CD, EH, and FG.
The matching proves that an independent set contains at most 8 − 4 = 4 sites. We need five, so a minimum distance of 5 is impossible and the propagator can lower z.max to the preceding distance level, 4. The selection in the first figure attains 4, so the lower and upper bounds meet: its minimum distance is optimal.
This is only an upper-bound certificate. A greedy maximal matching may fail to find a certificate even when the threshold is impossible, and passing the test does not prove that the threshold is feasible. Different maximal matchings can also have different sizes, so propagation may depend on which edges the greedy algorithm encounters first.1 The strict conflict test matters as well: points exactly 4 apart, such as F and G, remain compatible when testing t = 4.
The custom constraint avoids the auxiliary distance variables and lets the propagators use information specific to this problem. Advisors remember which pairs changed, while the matching pass supplies an additional upper-bound certificate. In this comparison, the advisor-backed forward-bound variant with matching has the best anytime score. The simpler pairwise forward-bound propagator remains competitive and is considerably easier to implement. These preliminary experiments do not identify one implementation as universally best. The paper contains the details and complete comparison, and the implementations are available as code.
Extended comparison
The paper compared selected combinations of propagators and matching propagation using Gecode’s Accumulated Failure Count heuristic.2 The extension tests all six custom propagators and the extensional tuple-set (table) variant, with matching off and on under two search settings, AFC and Size: 28 configurations on the same 100 instances.
The added propagator is pair-support. It posts a support-maintaining propagator for each pair of selected positions. The global-support and advisor-support variants tested in the paper perform the same filtering inside a global propagator. The filtering is essentially the same pairwise ternary scheme as the DistanceGT constraint described by Panteleimon Iosif, Nikolaos Ploskas, Kostas Stergiou, and Dimos Tsouros in Modeling the p-Dispersion Problem with Distance Constraints at CP 2026.
Each configuration was run once with Gecode 6.4.0 and a 120-second limit on an M1 Max. The ranking uses the same MiniZinc Challenge area calculation as the paper, which measures how quickly a configuration finds good solutions and continues to improve them.
The controls in the table below filter by search and matching, then recalculate scores and ranks for the selected field. Each score counts pairwise anytime wins against the configurations in that field. The final column shows the change from the paper’s ranking; “New” marks configurations absent from it.
The first three columns describe the experiment matrix:
- Propagator selects one of seven propagators: six custom minimum-distance propagators and the general tuple-set propagator.
- Matching used shows whether the separate matching upper bound is active. Every propagator is tested both ways.
- Search heuristic selects AFC or Size. AFC uses accumulated failure count divided by domain size and tries the smallest value first. Size uses smallest-domain selection and a seeded random value order for predictable runs.
28 configurations
| Propagator | Matching used | Search heuristic | Rank | All points | Best result | 42-case points | Best result | Change from paper |
|---|---|---|---|---|---|---|---|---|
| Pairwise forward bound | No | AFC | 1 | 488 | 69/100 | 164 | 21/42 | Up |
| Advisor forward bound | No | AFC | 2 | 486 | 70/100 | 233 | 22/42 | Down |
| Pairwise pair support | No | AFC | 3 | 354 | 67/100 | 102 | 21/42 | New |
| Advisor pair support | No | AFC | 4 | 347 | 67/100 | 176 | 21/42 | Same |
| Global forward bound | No | AFC | 5 | 308 | 70/100 | 148 | 22/42 | Up |
| Global pair support | No | AFC | 6 | 93 | 66/100 | 35 | 20/42 | Up |
| Tuple set | No | AFC | 7 | 24 | 65/100 | 24 | 19/42 | Down |
| Advisor forward bound | Yes | AFC | 1 | 487 | 76/100 | 234 | 28/42 | Same |
| Pairwise forward bound | Yes | AFC | 2 | 487 | 73/100 | 162 | 25/42 | New |
| Pairwise pair support | Yes | AFC | 3 | 356 | 71/100 | 105 | 25/42 | New |
| Advisor pair support | Yes | AFC | 4 | 339 | 70/100 | 168 | 24/42 | Same |
| Global forward bound | Yes | AFC | 5 | 309 | 76/100 | 149 | 28/42 | New |
| Global pair support | Yes | AFC | 6 | 93 | 67/100 | 35 | 21/42 | New |
| Tuple set | Yes | AFC | 7 | 29 | 65/100 | 29 | 19/42 | New |
| Pairwise forward bound | Yes | AFC | 1 | 1036 | 73/100 | 382 | 25/42 | New |
| Advisor forward bound | Yes | AFC | 2 | 1016 | 76/100 | 502 | 28/42 | Same |
| Pairwise forward bound | No | AFC | 3 | 995 | 69/100 | 299 | 21/42 | Up |
| Advisor forward bound | No | AFC | 4 | 973 | 70/100 | 418 | 22/42 | Down |
| Pairwise pair support | Yes | AFC | 5 | 792 | 71/100 | 284 | 25/42 | New |
| Advisor pair support | Yes | AFC | 6 | 762 | 70/100 | 405 | 24/42 | Down |
| Pairwise pair support | No | AFC | 7 | 759 | 67/100 | 203 | 21/42 | New |
| Advisor pair support | No | AFC | 8 | 718 | 67/100 | 330 | 21/42 | Same |
| Global forward bound | Yes | AFC | 9 | 677 | 76/100 | 340 | 28/42 | New |
| Global forward bound | No | AFC | 10 | 615 | 70/100 | 253 | 22/42 | Up |
| Global pair support | Yes | AFC | 11 | 305 | 67/100 | 169 | 21/42 | New |
| Global pair support | No | AFC | 12 | 246 | 66/100 | 89 | 20/42 | Up |
| Tuple set | Yes | AFC | 13 | 123 | 65/100 | 84 | 19/42 | New |
| Tuple set | No | AFC | 14 | 83 | 65/100 | 64 | 19/42 | Down |
| Advisor forward bound | No | Size | 1 | 530 | 60/100 | 221 | 17/42 | New |
| Advisor pair support | No | Size | 2 | 418 | 57/100 | 177 | 14/42 | New |
| Pairwise forward bound | No | Size | 3 | 387 | 62/100 | 152 | 17/42 | New |
| Pairwise pair support | No | Size | 4 | 286 | 57/100 | 105 | 14/42 | New |
| Global forward bound | No | Size | 5 | 223 | 61/100 | 110 | 17/42 | New |
| Tuple set | No | Size | 6 | 152 | 58/100 | 66 | 14/42 | New |
| Global pair support | No | Size | 7 | 104 | 57/100 | 51 | 14/42 | New |
| Advisor forward bound | Yes | Size | 1 | 514 | 64/100 | 214 | 21/42 | New |
| Advisor pair support | Yes | Size | 2 | 436 | 64/100 | 180 | 21/42 | New |
| Pairwise forward bound | Yes | Size | 3 | 387 | 67/100 | 158 | 22/42 | New |
| Pairwise pair support | Yes | Size | 4 | 296 | 63/100 | 120 | 20/42 | New |
| Global forward bound | Yes | Size | 5 | 220 | 66/100 | 113 | 22/42 | New |
| Tuple set | Yes | Size | 6 | 140 | 58/100 | 42 | 14/42 | New |
| Global pair support | Yes | Size | 7 | 107 | 62/100 | 55 | 19/42 | New |
| Advisor forward bound | Yes | Size | 1 | 1088 | 64/100 | 460 | 21/42 | New |
| Advisor forward bound | No | Size | 2 | 1072 | 60/100 | 421 | 17/42 | New |
| Advisor pair support | Yes | Size | 3 | 930 | 64/100 | 401 | 21/42 | New |
| Advisor pair support | No | Size | 4 | 868 | 57/100 | 348 | 14/42 | New |
| Pairwise forward bound | Yes | Size | 5 | 855 | 67/100 | 347 | 22/42 | New |
| Pairwise forward bound | No | Size | 6 | 763 | 62/100 | 290 | 17/42 | New |
| Pairwise pair support | Yes | Size | 7 | 663 | 63/100 | 277 | 20/42 | New |
| Pairwise pair support | No | Size | 8 | 606 | 57/100 | 206 | 14/42 | New |
| Global forward bound | Yes | Size | 9 | 519 | 66/100 | 270 | 22/42 | New |
| Global forward bound | No | Size | 10 | 483 | 61/100 | 229 | 17/42 | New |
| Tuple set | Yes | Size | 11 | 362 | 58/100 | 114 | 14/42 | New |
| Tuple set | No | Size | 12 | 323 | 58/100 | 150 | 14/42 | New |
| Global pair support | Yes | Size | 13 | 315 | 62/100 | 182 | 19/42 | New |
| Global pair support | No | Size | 14 | 253 | 57/100 | 127 | 14/42 | New |
| Advisor forward bound | No | Size | 1 | 952 | 60/100 | 381 | 17/42 | New |
| Pairwise forward bound | No | AFC | 2 | 937 | 69/100 | 341 | 21/42 | Up |
| Advisor forward bound | No | AFC | 3 | 924 | 70/100 | 434 | 22/42 | Down |
| Advisor pair support | No | Size | 4 | 813 | 57/100 | 323 | 14/42 | New |
| Pairwise pair support | No | AFC | 5 | 789 | 67/100 | 277 | 21/42 | New |
| Advisor pair support | No | AFC | 6 | 768 | 67/100 | 369 | 21/42 | Same |
| Pairwise forward bound | No | Size | 7 | 712 | 62/100 | 263 | 17/42 | New |
| Global forward bound | No | AFC | 8 | 707 | 70/100 | 325 | 22/42 | Up |
| Pairwise pair support | No | Size | 9 | 588 | 57/100 | 201 | 14/42 | New |
| Global forward bound | No | Size | 10 | 462 | 61/100 | 216 | 17/42 | New |
| Global pair support | No | AFC | 11 | 457 | 66/100 | 201 | 20/42 | Up |
| Tuple set | No | AFC | 12 | 347 | 65/100 | 185 | 19/42 | Down |
| Tuple set | No | Size | 13 | 342 | 58/100 | 170 | 14/42 | New |
| Global pair support | No | Size | 14 | 302 | 57/100 | 136 | 14/42 | New |
| Pairwise forward bound | Yes | AFC | 1 | 942 | 73/100 | 341 | 25/42 | New |
| Advisor forward bound | Yes | Size | 2 | 930 | 64/100 | 381 | 21/42 | New |
| Advisor forward bound | Yes | AFC | 3 | 920 | 76/100 | 426 | 28/42 | Same |
| Advisor pair support | Yes | Size | 4 | 830 | 64/100 | 331 | 21/42 | New |
| Pairwise pair support | Yes | AFC | 5 | 791 | 71/100 | 279 | 25/42 | New |
| Advisor pair support | Yes | AFC | 6 | 757 | 70/100 | 353 | 24/42 | Same |
| Pairwise forward bound | Yes | Size | 7 | 728 | 67/100 | 281 | 22/42 | New |
| Global forward bound | Yes | AFC | 8 | 705 | 76/100 | 321 | 28/42 | New |
| Pairwise pair support | Yes | Size | 9 | 615 | 63/100 | 236 | 20/42 | New |
| Global pair support | Yes | AFC | 10 | 464 | 67/100 | 201 | 21/42 | New |
| Global forward bound | Yes | Size | 11 | 457 | 66/100 | 220 | 22/42 | New |
| Tuple set | Yes | Size | 12 | 324 | 58/100 | 132 | 14/42 | New |
| Global pair support | Yes | Size | 13 | 322 | 62/100 | 160 | 19/42 | New |
| Tuple set | Yes | AFC | 14 | 315 | 65/100 | 160 | 19/42 | New |
| Pairwise forward bound | Yes | AFC | 1 | 1959 | 73/100 | 758 | 25/42 | New |
| Advisor forward bound | Yes | Size | 2 | 1941 | 64/100 | 815 | 21/42 | New |
| Advisor forward bound | No | Size | 3 | 1901 | 60/100 | 725 | 17/42 | New |
| Advisor forward bound | Yes | AFC | 4 | 1900 | 76/100 | 907 | 28/42 | Same |
| Pairwise forward bound | No | AFC | 5 | 1875 | 69/100 | 632 | 21/42 | Up |
| Advisor forward bound | No | AFC | 6 | 1829 | 70/100 | 796 | 22/42 | Down |
| Advisor pair support | Yes | Size | 7 | 1731 | 64/100 | 719 | 21/42 | New |
| Pairwise pair support | Yes | AFC | 8 | 1682 | 71/100 | 653 | 25/42 | New |
| Advisor pair support | No | Size | 9 | 1637 | 57/100 | 619 | 14/42 | New |
| Advisor pair support | Yes | AFC | 10 | 1620 | 70/100 | 799 | 24/42 | Down |
| Pairwise pair support | No | AFC | 11 | 1607 | 67/100 | 528 | 21/42 | New |
| Pairwise forward bound | Yes | Size | 12 | 1560 | 67/100 | 616 | 22/42 | New |
| Advisor pair support | No | AFC | 13 | 1536 | 67/100 | 690 | 21/42 | Same |
| Global forward bound | Yes | AFC | 14 | 1492 | 76/100 | 706 | 28/42 | New |
| Pairwise forward bound | No | Size | 15 | 1397 | 62/100 | 496 | 17/42 | New |
| Global forward bound | No | AFC | 16 | 1389 | 70/100 | 584 | 22/42 | Up |
| Pairwise pair support | Yes | Size | 17 | 1321 | 63/100 | 528 | 20/42 | New |
| Pairwise pair support | No | Size | 18 | 1195 | 57/100 | 383 | 14/42 | New |
| Global pair support | Yes | AFC | 19 | 1064 | 67/100 | 523 | 21/42 | New |
| Global forward bound | Yes | Size | 20 | 1016 | 66/100 | 504 | 22/42 | New |
| Global pair support | No | AFC | 21 | 955 | 66/100 | 397 | 20/42 | Up |
| Global forward bound | No | Size | 22 | 942 | 61/100 | 426 | 17/42 | New |
| Global pair support | Yes | Size | 23 | 764 | 62/100 | 407 | 19/42 | New |
| Tuple set | Yes | Size | 24 | 745 | 58/100 | 305 | 14/42 | New |
| Tuple set | Yes | AFC | 25 | 734 | 65/100 | 377 | 19/42 | New |
| Tuple set | No | AFC | 26 | 687 | 65/100 | 353 | 19/42 | Down |
| Tuple set | No | Size | 27 | 687 | 58/100 | 345 | 14/42 | New |
| Global pair support | No | Size | 28 | 634 | 57/100 | 285 | 14/42 | New |
The 42-case columns use the paper’s subset that excludes the 58 instances whose virtual best was 2. Each view is ordered by its all-instance score. The paper’s experimental table provides the original ordering.
Four patterns stand out in the results:
- A forward-bound configuration leads every selectable view. Pairwise forward bound with AFC and matching leads the full table, while advisor forward bound leads several narrower views.
- Matching raises all fourteen full-set scores and thirteen of the fourteen harder-subset scores. The exception is tuple set under Size.
- The rank depends on the selected field. Pairwise forward bound with AFC and matching leads the full table, but ties advisor forward bound at 487 points and appears second after the tie-break in the AFC-with-matching view. Scores count pairwise anytime wins against the selected configurations, so filtering removes points unevenly without changing the runs. This field sensitivity is worth keeping in mind when comparing anytime results.
- Search changes the ordering. AFC scores higher for the pairwise and global variants, while the advisor variants score higher with Size. AFC also scores higher throughout the harder subset. The difference likely comes mainly from value ordering, but needs further research.
The 100-case corpus and fixed 42-case subset, benchmark script, and runs and selectable score views are available in the public repository.
Footnotes
-
A maximum matching could strengthen the certificate by finding the largest possible
m. The classical approach is Edmonds’ blossom algorithm, with complexityO(n²|E|)fornactive sites and conflict-edge setE, compared withO(n²)for the simple greedy maximal matching used here. Blossom-style algorithms are also substantially harder to implement. Faster maximum-matching algorithms exist, but bring either more implementation complexity or significant constant factors. For this propagator, the greedy algorithm is a deliberate cost-strength tradeoff. ↩ -
Accumulated Failure Count is Gecode’s term for a measure that broadly corresponds to weighted degree. The
INT_VAR_AFC_SIZE_MAXGecode variable selector used here maximizes AFC divided by domain size and is Gecode’s counterpart to the heuristic usually calleddom/wdegin the literature. ↩