| Title: | Discrete Diversity, Dispersion, and Coverage Subset Selection |
|---|---|
| Description: | Solves discrete location objectives on a distance matrix or Euclidean coordinate set. The Max-Min Diversity (MMDP / p-dispersion) objective, which maximizes the minimum pairwise distance within a selection of k items, is solved by farthest-first selection (Gonzalez 1985) <doi:10.1016/0304-3975(85)90224-5>; the DropAdd tabu-search heuristic (Porumbel, Hao & Glover 2011) <doi:10.1007/s10479-011-0898-z>, GRASP with path-relinking (Resende, Marti, Gallego & Duarte 2010) <doi:10.1016/j.cor.2008.05.011>, and an exact node-packing integer program (Sayyady & Fathi 2016) <doi:10.1016/j.ejor.2016.02.026>. The Max-Mean Dispersion objective, which selects a subset of unrestricted size maximising the sum of its pairwise distances divided by the number of selected elements, is solved by reinforcement-learning-guided tabu search (Nijimbere et al. 2020) <doi:10.3934/jimo.2020115>. The discrete k-centre (min-max covering / facility location) objective, which chooses k centres to minimise the largest distance from any point to its nearest centre, is solved via the CDSh heuristic (Garcia-Diaz et al. 2017 <doi:10.1007/s10732-017-9345-x>, 2019 <doi:10.1109/ACCESS.2019.2933875>), and an exact minimum-cover integer program. The maximum-entropy (maxdet) objective, which maximises the log-determinant of a similarity kernel built from the distances (Shewry & Wynn 1987 <doi:10.1080/02664768700000020>; the mode of a determinantal point process, Kulesza & Taskar 2012 <doi:10.1561/2200000044>), is solved by greedy pivoted-Cholesky selection and, for small instances, exact enumeration. |
| Authors: | Martin R. Smith [aut, cre, cph] (ORCID: <https://orcid.org/0000-0001-5660-1727>) |
| Maintainer: | Martin R. Smith <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 1.0.0.9004 |
| Built: | 2026-10-11 12:41:14 UTC |
| Source: | https://github.com/ms609/coreset |
DropAdd() selects a maximally-dispersed subset of k points using the
DropAdd tabu search algorithm, which comprises a greedy construction
followed by a first-in, first-out drop-add tabu search, with streamlined
neighbour-evaluation tricks
(algorithms 1–4 in Porumbel et al. 2011).
DropAdd( k, d = NULL, plateau = 5000L, maxSeconds = Inf, points = NULL, maxCandidates = 46340L, seed = NULL, N = NULL )DropAdd( k, d = NULL, plateau = 5000L, maxSeconds = Inf, points = NULL, maxCandidates = 46340L, seed = NULL, N = NULL )
k |
Integer: subset size, |
d |
A |
plateau |
Integer: stop after this many consecutive drop-add iterations do not improve the score. |
maxSeconds |
Numeric: terminate search after this many seconds have elapsed. |
points |
A numeric |
maxCandidates |
Integer: when the number of candidate points |
seed |
Optional integer specifying the index of an element with which to seed the warm-start search. |
N |
Integer: the total number of elements. Required only if |
DropAdd() returns an integer vector of length k containing
the selected indices, sorted ascending, with attributes:
numeric specifying the achieved MaxMin objective
.
numeric specifying the achieved (upper triangle) sum of
pairwise distances over .
numeric specifying wall-clock seconds spent.
integer specifying main-loop iterations executed, excluding the construction phase.
The vector has class "MaxMinSelection" and prints as a one-line summary
(see print.MaxMinSelection()).
In interactive sessions, status messages are shown.
To toggle, set options("Coreset.progress" = FALSE) (or TRUE).
To parallelize computation when OpenMP is available, set the "mc.cores"
option:
options(mc.cores = 2L) # use a fixed number of cores options(mc.cores = parallel::detectCores()) # or all available cores
When d is a function, d(i) must return the distances from element i
to every element (length N, with the self-distance ignored),
or to every element except i (length N - 1, in order).
N is required, and memory is .
This suits metrics where no stored matrix or coordinate embedding is available.
Because d is typically called many times; specifying a distance matrix
(where memory permits) is likely to require less calculation than multiple
calls to d, unless d implements efficient caching.
Porumbel D, Hao J, Glover F (2011). “A simple and effective algorithm for the MaxMin diversity problem.” Annals of Operations Research, 186, 275–293. doi:10.1007/s10479-011-0898-z.
set.seed(1) pts <- matrix(rnorm(200), ncol = 2) DropAdd(5L, dist(pts)) # Composable coreset: thin to 40 candidates with farthest-first, then run # DropAdd on the coreset. Returned indices are original-space row indices. suppressWarnings(DropAdd(5L, points = pts, maxCandidates = 40L)) # Disable thinning on the full problem DropAdd(5L, points = pts, maxCandidates = 0L) # Distance function; `cache` memoizes the columns to reduce computation. data("USArrests") ArrestDist <- function(dat) { scaled <- scale(as.matrix(dat)) # derived once cache <- new.env(parent = emptyenv()) function(i) { key <- as.character(i) if (is.null(cache[[key]])) { cache[[key]] <- sqrt(rowSums(sweep(scaled, 2, scaled[i, ], "-") ^ 2)) } cache[[key]] } } arrests <- USArrests[, c("Murder", "Assault", "Rape")] idx <- DropAdd(4L, ArrestDist(arrests), N = nrow(arrests), plateau = 200L) USArrests[idx, ]set.seed(1) pts <- matrix(rnorm(200), ncol = 2) DropAdd(5L, dist(pts)) # Composable coreset: thin to 40 candidates with farthest-first, then run # DropAdd on the coreset. Returned indices are original-space row indices. suppressWarnings(DropAdd(5L, points = pts, maxCandidates = 40L)) # Disable thinning on the full problem DropAdd(5L, points = pts, maxCandidates = 0L) # Distance function; `cache` memoizes the columns to reduce computation. data("USArrests") ArrestDist <- function(dat) { scaled <- scale(as.matrix(dat)) # derived once cache <- new.env(parent = emptyenv()) function(i) { key <- as.character(i) if (is.null(cache[[key]])) { cache[[key]] <- sqrt(rowSums(sweep(scaled, 2, scaled[i, ], "-") ^ 2)) } cache[[key]] } } arrests <- USArrests[, c("Murder", "Assault", "Rape")] idx <- DropAdd(4L, ArrestDist(arrests), N = nrow(arrests), plateau = 200L) USArrests[idx, ]
ExactKCentre() finds an optimal solution to the discrete k-centre
problem.
ExactKCentre(k, d, maxSeconds = 60) ExactKCenter(k, d, maxSeconds = 60)ExactKCentre(k, d, maxSeconds = 60) ExactKCenter(k, d, maxSeconds = 60)
k |
Integer specifying maximum number of centres to identify,
from 1 to |
d |
|
maxSeconds |
Numeric specifying wall-clock budget, in seconds, for
the search.
If the time expires before the optimum is proven, the smallest radius proven
feasible is returned, with the attribute |
The optimum covering radius is the smallest threshold r, over the achieved
distinct distances, for which k centres can cover every point within r.
Each probe asks whether k centres cover every point within a candidate
radius. This is decided combinatorially via unit propagation and dominance
reduction, then an exhaustive component-wise search.
The search is warm-started from the KCentre() radius, then bisects
downwards.
ExactKCentre() returns an integer vector of length
listing the chosen centres in ascending order.
It has class c("KCentreExact", "KCentreSelection") and attributes:
The covering radius achieved; the proven optimum when
proven is TRUE, otherwise an upper bound.
Logical: TRUE if optimality is certified.
Wall-clock seconds elapsed.
Instance size and centre budget.
In interactive sessions, a progress indicator is shown.
To toggle, set options("Coreset.progress" = FALSE) (or TRUE).
KCentre() for the fast near-optimal heuristic; ExactMaxMin() for
the dual MMDP optimum.
set.seed(1) pts <- matrix(rnorm(40), ncol = 2) d <- dist(pts) ExactKCentre(3L, d)set.seed(1) pts <- matrix(rnorm(40), ncol = 2) d <- dist(pts) ExactKCentre(3L, d)
ExactMaxMin() finds the optimal solution to the Max-Min Diversity Problem
(discrete p-dispersion) by iterated node-packing
(Sayyady and Fathi 2016) (which may be slow or intractable on large
sets).
ExactMaxMin( k, d, maxSeconds = 60, warmStart = NULL, nStart = 1L, graspPlateau = 50L, dropPlateau = 512L, boundSeconds = 0, upper = Inf )ExactMaxMin( k, d, maxSeconds = 60, warmStart = NULL, nStart = 1L, graspPlateau = 50L, dropPlateau = 512L, boundSeconds = 0, upper = Inf )
k |
Integer: target subset size, between 2 and |
d |
|
maxSeconds |
Numeric: search terminates after this many seconds have elapsed, returning largest threshold proven feasible. |
warmStart |
Optional integer vector giving indices of a candidate subset to add to the heuristic warm-start pool. |
nStart |
Integer: how many |
graspPlateau, dropPlateau
|
Integer: the stopping plateaus given to the
pool's |
boundSeconds |
Numeric: seconds to spend bracketing the optimum from above
before the main search, in addition to |
upper |
Numeric: a proven upper bound on the optimum, such as the
|
The search is warm-started from a heuristic lower bound (the best of
nStart Grasp() restarts and a DropAdd() pass), then gallops upward from that
bound to the first infeasible threshold and bisects the resulting bracket.
To parallelize computation when OpenMP is available, set the "mc.cores"
option:
options(mc.cores = 2L) # use a fixed number of cores options(mc.cores = parallel::detectCores()) # or all available cores
Parallelization returns identical results under a given seed.
ExactMaxMin() returns an integer vector of length k (sorted
ascending) with class "MaxMinSelection", carrying attributes:
The minimum pairwise distance within the selection.
When proven is TRUE this is the optimum; otherwise
a lower bound.
Logical: TRUE if the search certified optimality within
the budget, FALSE if it returned an unproven incumbent.
An upper bound on the optimum: the largest distance below
the smallest threshold proven infeasible, and no greater than the
upper argument. Equals score when
proven is TRUE.
Wall-clock seconds elapsed.
Instance size and target subset size.
Prints as a terse summary via print.MaxMinSelection().
In interactive sessions, a progress indicator is shown.
To toggle, set options("Coreset.progress" = FALSE) (or TRUE).
Sayyady F, Fathi Y (2016). “An integer programming approach for solving the p-dispersion problem.” European Journal of Operational Research, 253(1), 216–225. doi:10.1016/j.ejor.2016.02.026.
set.seed(1) pts <- matrix(rnorm(18), ncol = 2) ExactMaxMin(3L, dist(pts))set.seed(1) pts <- matrix(rnorm(18), ncol = 2) ExactMaxMin(3L, dist(pts))
ExactMaxSum() finds the optimal solution to the Max-Sum Diversity Problem
(the "maximum diversity problem"): it selects the k points that maximizes
the total pairwise distance between points. As the problem is NP-hard, it is
feasible only for small sets.
ExactMaxSum(k, d, maxSeconds = 30, warmStart = NULL)ExactMaxSum(k, d, maxSeconds = 30, warmStart = NULL)
k |
Integer: target subset size, between 2 and |
d |
|
maxSeconds |
Numeric: search terminates after this many seconds have elapsed, returning largest threshold proven feasible. |
warmStart |
Optional integer vector giving indices of a candidate subset to add to the heuristic warm-start pool. |
The solver uses per-node integer-program linearisation
(Kuo et al. 1993), starting from a multi-start 1-swap local
search, whose result is returned when optimality cannot be proven within
maxSeconds.
ExactMaxSum() returns an integer vector of length k, sorted
ascending, with class "MaxSumSelection", carrying attributes:
Numeric specifying the achieved total pairwise distance
within the selection. When proven is TRUE this is the optimum;
otherwise a lower bound.
Logical: TRUE if optimality was certified.
Numerics reporting the wall-clock seconds elapsed; instance size; and target size.
Kuo C, Glover F, Dhir KS (1993). “Analyzing and modeling the maximum diversity problem by zero-one programming.” Decision Sciences, 24(6), 1171–1185. doi:10.1111/j.1540-5915.1993.tb00509.x.
set.seed(1) pts <- matrix(rnorm(20), ncol = 2) # Package 'highs' is required for ExactMaxSum if (requireNamespace("highs", quietly = TRUE)) { ExactMaxSum(3L, dist(pts)) }set.seed(1) pts <- matrix(rnorm(20), ncol = 2) # Package 'highs' is required for ExactMaxSum if (requireNamespace("highs", quietly = TRUE)) { ExactMaxSum(3L, dist(pts)) }
Greedy farthest-first selection (González 1985; Hochbaum and Shmoys 1985) iteratively selects the point furthest from the current selection to yield a 2-approximation to the k-centre and Max Min Diversity problems.
FarFirst( k, d = NULL, points = NULL, N = NULL, strategy = "random_furthest", nSeeds = 3L )FarFirst( k, d = NULL, points = NULL, N = NULL, strategy = "random_furthest", nSeeds = 3L )
k |
Integer: number of points to select. |
d |
A |
points |
Optional |
N |
Integer: the total number of elements. Required (and used) only on the distance-column oracle path, where it cannot be inferred from the closure; ignored for the matrix and coordinate paths. |
strategy |
Optional integer or character identifying one or more
of the seeding strategies described in |
nSeeds |
Integer: number of distinct seeds to draw under the
|
FarFirst() returns an integer vector with class MaxMinSelection,
listing the selected indices in the order they were selected.
Attributes report:
score: the selection's minimum pairwise distance ().
winning_strategy: character vector listing strategies that attained the
optimal score.
strategy_results: results for each strategy.
In interactive sessions, the distance-column path shows a progress bar.
To toggle, set options("Coreset.progress" = FALSE) (or TRUE).
To parallelize computation when OpenMP is available, set the "mc.cores"
option:
options(mc.cores = 2L) # use a fixed number of cores options(mc.cores = parallel::detectCores()) # or all available cores
The main use case for parallelization is when nSeeds is a multiple of
mc.cores, so each seed point can be evaluated in parallel.
González TF (1985).
“Clustering to minimize the maximum intercluster distance.”
Theoretical Computer Science, 38, 293–306.
doi:10.1016/0304-3975(85)90224-5.
Hochbaum DS, Shmoys DB (1985).
“A best possible heuristic for the -center problem.”
Mathematics of Operations Research, 10(2), 180–184.
doi:10.1287/moor.10.2.180.
PickPoint() for the seed indices alone; DropAdd() and
ExactMaxMin() for higher-effort solvers.
set.seed(1) pts <- matrix(rnorm(60), ncol = 2) d <- dist(pts) # Default: best of three random-furthest starts (set.seed for reproducibility): FarFirst(5L, d) # More random-furthest starts: FarFirst(5L, d, nSeeds = 15L) # Custom two-anchor ensemble: FarFirst(5L, d, strategy = c("diameter", "anti_medoid")) # A single strategy: FarFirst(5L, d, strategy = "diameter") # An explicit start index (integer strategy): FarFirst(5L, d, strategy = 1L) # Matrix-free coordinate path (identical result, O(N) memory): FarFirst(5L, points = pts, strategy = 1L) # Distance-column oracle: supply one column at a time, never the full matrix. data("USArrests") arrestTypes <- USArrests[, c("Murder", "Assault", "Rape")] StateDist <- function(i) { diffs <- sweep(arrestTypes, 2, unlist(arrestTypes[i, ]), "-") sqrt(rowSums(diffs ^ 2)) } idx <- FarFirst(4L, StateDist, N = nrow(arrestTypes), strategy = 1L) arrestTypes[idx, ]set.seed(1) pts <- matrix(rnorm(60), ncol = 2) d <- dist(pts) # Default: best of three random-furthest starts (set.seed for reproducibility): FarFirst(5L, d) # More random-furthest starts: FarFirst(5L, d, nSeeds = 15L) # Custom two-anchor ensemble: FarFirst(5L, d, strategy = c("diameter", "anti_medoid")) # A single strategy: FarFirst(5L, d, strategy = "diameter") # An explicit start index (integer strategy): FarFirst(5L, d, strategy = 1L) # Matrix-free coordinate path (identical result, O(N) memory): FarFirst(5L, points = pts, strategy = 1L) # Distance-column oracle: supply one column at a time, never the full matrix. data("USArrests") arrestTypes <- USArrests[, c("Murder", "Assault", "Rape")] StateDist <- function(i) { diffs <- sweep(arrestTypes, 2, unlist(arrestTypes[i, ]), "-") sqrt(rowSums(diffs ^ 2)) } idx <- FarFirst(4L, StateDist, N = nrow(arrestTypes), strategy = 1L) arrestTypes[idx, ]
Grasp() solves the Max-Min Diversity Problem (discrete p-dispersion) with
the static variant of the GRASP / path-relinking metaheuristic
(Resende et al. 2010, fig. 4). This expensive heuristic
often attains high-quality selections.
Grasp( k, d, plateau = 100L, eliteSize = 10L, alpha = 0.8, maxSeconds = Inf, maxCandidates = 2000L )Grasp( k, d, plateau = 100L, eliteSize = 10L, alpha = 0.8, maxSeconds = Inf, maxCandidates = 2000L )
k |
Integer subset size, |
d |
Either a |
plateau |
Integer; stop after this many consecutive GRASP iterations have not improved the best elite objective. |
eliteSize |
Size of the elite set |ES|. |
alpha |
Numeric in |
maxSeconds |
Numeric specifying wall-clock ceiling, in seconds. |
maxCandidates |
Integer: when the number of candidate points |
The GRASP with path-relinking algorithm conducts a randomised-greedy construction with extended-improvement local search builds; it identifies an elite set, then conducts a single pass of path relinking over all elite pairs (Resende et al. 2010).
The refinement loop stops after plateau consecutive GRASP iterations
fail to improve the best elite objective, or once maxSeconds have
elapsed.
This method will fail if the complete distance matrix is
too large to fit into memory.
Grasp() returns an integer vector of length k specifying the
indices of the selected points, with attributes:
Achieved MaxMin objective .
Wall-clock seconds spent.
Number of GRASP refinement iterations executed.
Number of path-relinking pair-applications run.
The vector has class "MaxMinSelection" and prints as a one-line summary
(see print.MaxMinSelection()).
To parallelize computation when OpenMP is available, set the "mc.cores"
option:
options(mc.cores = 2L) # use a fixed number of cores options(mc.cores = parallel::detectCores()) # or all available cores
In interactive sessions, a bar tracks how close the search is to its plateau stopping criterion, snapping back each time a better solution is found.
To toggle, set options("Coreset.progress" = FALSE) (or TRUE).
Resende MGC, Martí R, Gallego M, Duarte A (2010). “GRASP and path relinking for the max-min diversity problem.” Computers & Operations Research, 37(3), 498–508. doi:10.1016/j.cor.2008.05.011.
DropAdd() for scalable refinement;
ExactMaxMin() for the proven optimum on small instances.
set.seed(1) pts <- matrix(rnorm(60), ncol = 2) Grasp(5L, dist(pts), plateau = 20L, eliteSize = 4L) # Composable coreset: thin to 20 candidates with farthest-first, then run # GRASP on the coreset. Returned indices are original-space row indices. suppressWarnings(Grasp(5L, dist(pts), plateau = 20L, maxCandidates = 20L))set.seed(1) pts <- matrix(rnorm(60), ncol = 2) Grasp(5L, dist(pts), plateau = 20L, eliteSize = 4L) # Composable coreset: thin to 20 candidates with farthest-first, then run # GRASP on the coreset. Returned indices are original-space row indices. suppressWarnings(Grasp(5L, dist(pts), plateau = 20L, maxCandidates = 20L))
KCentre() selects elements (centres) so as to minimize the largest
distance from any point to its nearest centre (the covering radius),
using the Critical Dominating Set heuristic (CDSh)
(García-Díaz et al. 2017; García-Díaz et al. 2019).
KCentre(k, d, nstart = 1L, effort = 1L) KCenter(k, d, nstart = 1L, effort = 1L)KCentre(k, d, nstart = 1L, effort = 1L) KCenter(k, d, nstart = 1L, effort = 1L)
k |
Integer specifying maximum number of centres to identify,
from 1 to |
d |
|
nstart |
Integer specifying how many deterministic peripheral seeds to try. |
effort |
Integer: if |
On the benchmark instances of García-Díaz et al. (2019),
the CDS heuristic reaches roughly 1–3.5%
of the optimum at , far tighter than FarFirst().
Despite this good performance in practice, the CDSh is a
3-approximation.
To guard against occasional cases where a better candidate is missed,
KCentre() runs by default an exhaustive search of a small candidate grid
(for n up to ~150); and an additional FarFirst() pass
(controlled via the effort argument). These safeguards ensure
that KCentre() always returns at least a 2-approximation.
KCentre() returns an integer vector of length specifying
the chosen centres in ascending order.
The achieved covering radius is attached as attribute radius.
The vector has class "KCentreSelection" and prints as a one-line summary.
García-Díaz J, Menchaca-Méndez R, Menchaca-Méndez R, Pomares Hernández S, Pérez-Sansalvador JC, Lakouari N (2019).
“Approximation algorithms for the vertex -center problem: survey and experimental evaluation.”
IEEE Access, 7, 109228–109245.
doi:10.1109/ACCESS.2019.2933875.
García-Díaz J, Sánchez-Hernández J, Menchaca-Méndez R, Menchaca-Méndez R (2017).
“When a worse approximation factor gives better performance: a 3-approximation algorithm for the vertex -center problem.”
Journal of Heuristics, 23(5), 349–366.
doi:10.1007/s10732-017-9345-x.
González TF (1985).
“Clustering to minimize the maximum intercluster distance.”
Theoretical Computer Science, 38, 293–306.
doi:10.1016/0304-3975(85)90224-5.
ExactKCentre() for the proven optimum;
KCentreRadius() for a selection's score;
FarFirst() for the González (1985)
2-approximation baseline.
set.seed(1) pts <- matrix(rnorm(120), ncol = 2) d <- dist(pts) centres <- KCentre(5L, d) KCentreRadius(d, centres) # Results will beat a Gonzalez 2-approximation: KCentreRadius(d, FarFirst(5L, d, nSeeds = 1))set.seed(1) pts <- matrix(rnorm(120), ncol = 2) d <- dist(pts) centres <- KCentre(5L, d) KCentreRadius(d, centres) # Results will beat a Gonzalez 2-approximation: KCentreRadius(d, FarFirst(5L, d, nSeeds = 1))
KCentreRadius() computes the covering radius of a set of centres:
the largest distance from any of the N points to its nearest centre,
. This is the min-max
k-centre objective (González 1985) minimized by
KCentre() and ExactKCentre().
KCentreRadius(d = NULL, idx, points = NULL) KCenterRadius(d = NULL, idx, points = NULL)KCentreRadius(d = NULL, idx, points = NULL) KCenterRadius(d = NULL, idx, points = NULL)
d |
Pairwise distance matrix or |
idx |
Integer vector of centre indices ( |
points |
|
KCentreRadius() returns a numeric denoting the covering radius.
González TF (1985). “Clustering to minimize the maximum intercluster distance.” Theoretical Computer Science, 38, 293–306. doi:10.1016/0304-3975(85)90224-5.
KCentre() and ExactKCentre() (which minimise this); MinDist()
for the complementary MMDP objective.
set.seed(1) pts <- matrix(rnorm(60), ncol = 2) d <- dist(pts) centres <- KCentre(4L, d) KCentreRadius(d, centres)set.seed(1) pts <- matrix(rnorm(60), ncol = 2) d <- dist(pts) centres <- KCentre(4L, d) KCentreRadius(d, centres)
MaxEntropy() selects the k points that maximise the log-determinant of
their kernel block, . This is equivalent to finding the set
of k points that span the largest volume, which corresponds to
the maximum-entropy sampling criterion (Shewry and Wynn 1987) and
the maximum-a-posteriori mode of a determinantal point process
(Kulesza and Taskar 2012).
MaxEntropy( k, d, sigma = NULL, repair = c("clip", "shift", "truncate"), exact = NA, maxCombos = 300000L )MaxEntropy( k, d, sigma = NULL, repair = c("clip", "shift", "truncate"), exact = NA, maxCombos = 300000L )
k |
Integer specifying target selection size, |
d |
|
sigma |
Optional numeric specifying kernel bandwidth; defaults to the median positive distance. |
repair |
Character selecting a positive semi-definite repair method:
|
exact |
Logical: |
maxCombos |
Integer specifying ceiling on |
A radial-basis kernel is built from
the supplied distances and repaired to a positive-semidefinite matrix.
The exact argmax is NP-hard (Kulesza and Taskar 2012).
A greedy approximation is built by pivoted Cholesky, adding at each step
the point of largest residual conditional variance.
Ties are broken by selecting the more peripheral point.
Large instances run faster when R is linked to an optimised BLAS, such as OpenBLAS, Intel MKL or Apple Accelerate.
MaxEntropy() returns an integer vector of length k (sorted
ascending) with class "MaxEntropySelection", carrying attributes:
The retained of the selection.
-Inf is returned for a degenerate selection where k exceeds the
number of distinct points.
Fraction of spectral mass removed by the positive semi-definite repair.
The bandwidth, repair, and whether the optimum was certified by enumeration.
The peripheral seed index, instance size, target size.
Kulesza A, Taskar B (2012).
“Determinantal point processes for machine learning.”
Foundations and Trends in Machine Learning, 5(2–3), 123–286.
doi:10.1561/2200000044.
Shewry MC, Wynn HP (1987).
“Maximum entropy sampling.”
Journal of Applied Statistics, 14(2), 165–170.
doi:10.1080/02664768700000020.
set.seed(1) pts <- matrix(rnorm(40), ncol = 2) MaxEntropy(4L, dist(pts))set.seed(1) pts <- matrix(rnorm(40), ncol = 2) MaxEntropy(4L, dist(pts))
MaxMean() selects a maximally dispersed subset of elements from a
pairwise distance matrix, maximising the max-mean objective:
The number of elements in the subset is chosen so as
to maximise the mean dispersion.
MaxMean(d, maxSeconds = 0.1, maxIter = 1000, useRL = TRUE)MaxMean(d, maxSeconds = 0.1, maxIter = 1000, useRL = TRUE)
d |
A |
maxSeconds |
Numeric: wall-clock time budget, in seconds. |
maxIter |
Numeric: cap on the total tabu-search iterations across restarts. |
useRL |
Logical: if |
MaxMean() implements the reinforcement-learning tabu search
algorithm of (Nijimbere et al. 2020).
An initial solution is constructed randomly for the first restart and
via -learning thereafter; each initial solution is then refined by a
tabu search using one-flip moves (adding or removing one element per step).
Restarts continue until either the maxSeconds or maxIter budget is
reached.
The reinforcement-learning and tabu hyperparameters are fixed at the tuned
values reported by Nijimbere et al. (2020): greedy factor
, learning rate , discount
, maximum tabu tenure 120, search depth 50 000.
MaxMean() returns an integer vector of selected 1-based indices
(sorted ascending) with class "MaxMeanSelection" and attributes:
numeric, achieved objective
.
integer, number of selected elements .
numeric, wall-clock seconds spent.
numeric, total tabu-search iterations across restarts.
The vector has class "MaxMeanSelection" and prints as a one-line summary
(see print.MaxMeanSelection()); it is otherwise an ordinary integer
vector that indexes the distance matrix directly.
In interactive sessions, status messages are shown.
To toggle, set options("Coreset.progress" = FALSE) (or TRUE).
Nijimbere D, Zhao S, Gu X, Esangbedo MO, Dominique N (2020). “Tabu search guided by reinforcement learning for the max-mean dispersion problem.” Journal of Industrial & Management Optimization, 17, 3223–3254. doi:10.3934/jimo.2020115.
MeanDist() to score an arbitrary selection under this objective;
FarFirst(), DropAdd() and Grasp() for fixed-cardinality max-min
solvers.
# The max-mean problem is defined for signed dissimilarities; with these the # optimal subset has an interior size, chosen to maximise mean dispersion. set.seed(1) x <- matrix(runif(100, -5, 5), 10) d <- (x + t(x)) / 2 # symmetric, signed selection <- MaxMean(d) selection # 5 of the 10 elements: {2, 5, 6, 8, 10} MeanDist(d, selection) # 2.714 — equals attr(selection, "score")# The max-mean problem is defined for signed dissimilarities; with these the # optimal subset has an interior size, chosen to maximise mean dispersion. set.seed(1) x <- matrix(runif(100, -5, 5), 10) d <- (x + t(x)) / 2 # symmetric, signed selection <- MaxMean(d) selection # 5 of the 10 elements: {2, 5, 6, 8, 10} MeanDist(d, selection) # 2.714 — equals attr(selection, "score")
MeanDist() reports the sum of pairwise distances divided by the number of
selected elements,
,
the objective maximised by MaxMean().
MeanDist(d, idx)MeanDist(d, idx)
d |
Pairwise distance matrix or |
idx |
Integer vector of selected row/col indices. |
MeanDist() returns a numeric scalar, or NA_real_ if
length(idx) < 2.
MaxMean() which maximises this objective; MinDist() for the
max-min (MMDP) analogue.
# The max-mean problem is defined for signed dissimilarities; with these the # optimal subset has an interior size, chosen to maximise mean dispersion. set.seed(1) x <- matrix(runif(100, -5, 5), 10) d <- (x + t(x)) / 2 # symmetric, signed selection <- MaxMean(d) selection # 5 of the 10 elements: {2, 5, 6, 8, 10} MeanDist(d, selection) # 2.714 — equals attr(selection, "score")# The max-mean problem is defined for signed dissimilarities; with these the # optimal subset has an interior size, chosen to maximise mean dispersion. set.seed(1) x <- matrix(runif(100, -5, 5), 10) d <- (x + t(x)) / 2 # symmetric, signed selection <- MaxMean(d) selection # 5 of the 10 elements: {2, 5, 6, 8, 10} MeanDist(d, selection) # 2.714 — equals attr(selection, "score")
Returns the minimum pairwise distance among selected points .
A set of points that is more dispersed will exhibit a higher value.
MinDist(d = NULL, idx, points = NULL)MinDist(d = NULL, idx, points = NULL)
d |
Pairwise distance matrix or |
idx |
Integer vector of selected row/col indices. |
points |
Optional |
The solvers in this package (FarFirst(), DropAdd(), Grasp())
already attach the achieved as a score attribute.
MinDist() allows arbitrary selections to be scored, or an existing
selection to be scored against a different distance matrix.
MinDist() returns a numeric specifying the minimum distance between
two selected points (or NA_real_, if length(idx) < 2).
FarFirst(), DropAdd(), Grasp() and ExactMaxMin().
set.seed(1) pts <- matrix(rnorm(60), ncol = 2) d <- dist(pts) MinDist(d, FarFirst(5L, d))set.seed(1) pts <- matrix(rnorm(60), ncol = 2) d <- dist(pts) MinDist(d, FarFirst(5L, d))
PickPoint() implements a range of strategies to select a seed for greedy
farthest-first selection. Propitious seeds yield better solutions.
PickPoint( d = NULL, points = NULL, strategy = c("peripheral", "anti_centroid", "random_furthest", "diameter", "anti_medoid", "medoid", "rowsum", "rownorm"), N = NULL, nSeeds = 1L )PickPoint( d = NULL, points = NULL, strategy = c("peripheral", "anti_centroid", "random_furthest", "diameter", "anti_medoid", "medoid", "rowsum", "rownorm"), N = NULL, nSeeds = 1L )
d |
A |
points |
Optional |
strategy |
Character specifying method to employ:
Only |
N |
Integer: the total number of elements. Required (and used) only on the distance-column oracle path, where it cannot be inferred from the closure; ignored for the matrix and coordinate paths. |
nSeeds |
Integer specifying how many distinct seeds to obtain under
|
PickPoint() returns an integer that identifies the index of a
proposed seed in d or points; under "random_furthest" with
nSeeds > 1, up to nSeeds distinct indices, in ascending order.
FarFirst(), which seeds and runs the greedy pass in one call.
set.seed(1) pts <- matrix(rnorm(60), ncol = 2) d <- dist(pts) PickPoint(d, strategy = "diameter") FarFirst(5L, d, strategy = PickPoint(d, strategy = "diameter")) # Seeds for three starts, from distances computed one column at a time. # The seeds drawn are identical to those selected by FarFirst(). Column <- function(i) sqrt(colSums((t(pts) - pts[i, ]) ^ 2)) set.seed(2) PickPoint(Column, strategy = "random_furthest", N = nrow(pts), nSeeds = 3) set.seed(2) FarFirst(5L, Column, N = nrow(pts), strategy = "random_furthest", nSeeds = 3)set.seed(1) pts <- matrix(rnorm(60), ncol = 2) d <- dist(pts) PickPoint(d, strategy = "diameter") FarFirst(5L, d, strategy = PickPoint(d, strategy = "diameter")) # Seeds for three starts, from distances computed one column at a time. # The seeds drawn are identical to those selected by FarFirst(). Column <- function(i) sqrt(colSums((t(pts) - pts[i, ]) ^ 2)) set.seed(2) PickPoint(Column, strategy = "random_furthest", N = nrow(pts), nSeeds = 3) set.seed(2) FarFirst(5L, Column, N = nrow(pts), strategy = "random_furthest", nSeeds = 3)
Terse summaries of the objects returned by the Coreset solvers.
## S3 method for class 'MaxMinSelection' format(x, ...) ## S3 method for class 'MaxMinSelection' print(x, ...)## S3 method for class 'MaxMinSelection' format(x, ...) ## S3 method for class 'MaxMinSelection' print(x, ...)
x |
A |
... |
Ignored; present for S3 compatibility. |
print.Coreset() returns x, invisibly. It is called for its side-effect
of printing format(x) to the console.
format.Coreset() returns a character string reporting the selection size,
the selected indices, the algorithm (and if applicable strategy or proof
status), and the achieved .
Other reporting functions:
print.KCentre,
print.MaxEntropy,
print.MaxMeanSelection(),
print.MaxSum,
summary.Coreset
set.seed(1) pts <- matrix(rnorm(60), ncol = 2) print(FarFirst(5L, dist(pts)))set.seed(1) pts <- matrix(rnorm(60), ncol = 2) print(FarFirst(5L, dist(pts)))
Terse summaries of the objects returned by KCentre()
("KCentreSelection") and ExactKCentre() ("KCentreExact")
## S3 method for class 'KCentreSelection' format(x, ...) ## S3 method for class 'KCentreSelection' print(x, ...) ## S3 method for class 'KCentreExact' format(x, ...) ## S3 method for class 'KCentreExact' print(x, ...)## S3 method for class 'KCentreSelection' format(x, ...) ## S3 method for class 'KCentreSelection' print(x, ...) ## S3 method for class 'KCentreExact' format(x, ...) ## S3 method for class 'KCentreExact' print(x, ...)
x |
A |
... |
Ignored; present for S3 compatibility. |
print.KCentre() returns x, invisibly. It is called for its side-effect
of printing format(x) to the console.
format.KCentre() returns a character string describing a KCentreSelection;
it reports the centre count, the chosen indices, the method, and the achieved
covering radius (with proof status for the exact solver).
Other reporting functions:
print.Coreset,
print.MaxEntropy,
print.MaxMeanSelection(),
print.MaxSum,
summary.Coreset
set.seed(1) KCentre(4L, dist(matrix(rnorm(60), ncol = 2)))set.seed(1) KCentre(4L, dist(matrix(rnorm(60), ncol = 2)))
Terse summary of the object returned by MaxEntropy()
("MaxEntropySelection"), reporting the retained log-determinant
(, the maxdet objective) and the magnitude of the
positive-semidefinite repair.
## S3 method for class 'MaxEntropySelection' format(x, ...) ## S3 method for class 'MaxEntropySelection' print(x, ...)## S3 method for class 'MaxEntropySelection' format(x, ...) ## S3 method for class 'MaxEntropySelection' print(x, ...)
x |
A |
... |
Ignored; present for S3 compatibility. |
format.MaxEntropySelection() returns a one-line character summary;
print.MaxEntropySelection() returns x invisibly, called for its
side-effect.
Other reporting functions:
print.Coreset,
print.KCentre,
print.MaxMeanSelection(),
print.MaxSum,
summary.Coreset
set.seed(1) MaxEntropy(4L, dist(matrix(rnorm(40), ncol = 2)))set.seed(1) MaxEntropy(4L, dist(matrix(rnorm(40), ncol = 2)))
Terse one-line and detailed summaries of the objects returned by MaxMean().
## S3 method for class 'MaxMeanSelection' format(x, ...) ## S3 method for class 'MaxMeanSelection' print(x, ...) ## S3 method for class 'MaxMeanSelection' summary(object, ...)## S3 method for class 'MaxMeanSelection' format(x, ...) ## S3 method for class 'MaxMeanSelection' print(x, ...) ## S3 method for class 'MaxMeanSelection' summary(object, ...)
x |
A |
... |
Ignored; present for S3 compatibility. |
object |
A |
print.MaxMeanSelection() returns x, invisibly.
format.MaxMeanSelection() returns a character string reporting the
selection size, the selected indices, and the achieved max-mean objective
.
Other reporting functions:
print.Coreset,
print.KCentre,
print.MaxEntropy,
print.MaxSum,
summary.Coreset
set.seed(1) pts <- matrix(rnorm(60), ncol = 2) print(MaxMean(dist(pts), maxSeconds = 1))set.seed(1) pts <- matrix(rnorm(60), ncol = 2) print(MaxMean(dist(pts), maxSeconds = 1))
Terse summary of the object returned by ExactMaxSum()
("MaxSumSelection"), reporting the achieved total pairwise distance
(the max-sum objective) rather than the minimum distance of ExactMaxMin().
## S3 method for class 'MaxSumSelection' format(x, ...) ## S3 method for class 'MaxSumSelection' print(x, ...)## S3 method for class 'MaxSumSelection' format(x, ...) ## S3 method for class 'MaxSumSelection' print(x, ...)
x |
A |
... |
Ignored; present for S3 compatibility. |
format.MaxSumSelection() returns a one-line character summary;
print.MaxSumSelection() returns x invisibly, called for its side-effect.
Other reporting functions:
print.Coreset,
print.KCentre,
print.MaxEntropy,
print.MaxMeanSelection(),
summary.Coreset
set.seed(1) # Package 'highs' is required for ExactMaxSum() if (requireNamespace("highs", quietly = TRUE)) { ExactMaxSum(3L, dist(matrix(rnorm(20), ncol = 2))) }set.seed(1) # Package 'highs' is required for ExactMaxSum() if (requireNamespace("highs", quietly = TRUE)) { ExactMaxSum(3L, dist(matrix(rnorm(20), ncol = 2))) }
A fuller counterpart to print.MaxMinSelection(): the one-line headline,
followed by the achieved objective(s), search effort, and – for a
FarFirst() ensemble – the per-strategy table.
## S3 method for class 'MaxMinSelection' summary(object, ...)## S3 method for class 'MaxMinSelection' summary(object, ...)
object |
A |
... |
Ignored; present for S3 compatibility. |
summary.Coreset() returns object, invisibly.
Other reporting functions:
print.Coreset,
print.KCentre,
print.MaxEntropy,
print.MaxMeanSelection(),
print.MaxSum
set.seed(1) pts <- matrix(rnorm(60), ncol = 2) summary(FarFirst(5L, dist(pts)))set.seed(1) pts <- matrix(rnorm(60), ncol = 2) summary(FarFirst(5L, dist(pts)))