% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/Optimal_Dispersion.R
\name{optimal_dispersion}
\alias{optimal_dispersion}
\title{Maximize dispersion for K groups}
\usage{
optimal_dispersion(
  x,
  K,
  solver = NULL,
  max_dispersion_considered = NULL,
  min_dispersion_considered = NULL,
  npartitions = 1,
  time_limit = NULL
)
}
\arguments{
\item{x}{The data input. Can be one of two structures: (1) A
feature matrix where rows correspond to elements and columns
correspond to variables (a single numeric variable can be
passed as a vector). (2) An N x N matrix dissimilarity matrix;
can be an object of class \code{dist} (e.g., returned by
\code{\link{dist}} or \code{\link{as.dist}}) or a \code{matrix}
where the entries of the upper and lower triangular matrix
represent pairwise dissimilarities.}

\item{K}{The number of groups or a vector describing the size of
each group.}

\item{solver}{Optional argument; currently supports "lpSolve", 
"glpk", "symphony", and "gurobi". See \code{\link{optimal_anticlustering}}.}

\item{max_dispersion_considered}{Optional argument used for early
stopping. If the dispersion found is equal to or exceeds this
value, a solution having the previous best dispersion is
returned.}

\item{min_dispersion_considered}{Optional argument used for
speeding up the algorithm computation.  If passed, the
dispersion is optimized starting from this value instead the
global minimum distance.}

\item{npartitions}{The number of groupings that are returned, each
having an optimal dispersion value (defaults to 1).}

\item{time_limit}{Time limit in seconds, given to the solver.
Default is there is no time limit.}
}
\value{
A list with four elements:  
   \item{dispersion}{The optimal dispersion}
   \item{groups}{An assignment of elements to groups (vector)}
   \item{edges}{A matrix of 2 columns. Each row contains the indices of 
   elements that had to be investigated to find the dispersion (i.e., each pair
   of elements cannot be part of the same group in order to achieve maximum 
   dispersion).}
   \item{dispersions_considered}{All distances that were tested until the dispersion was found.}
}
\description{
Maximize dispersion for K groups
}
\details{
The dispersion is the minimum distance between two elements
  within the same group. This function implements an optimal method
  to maximize the dispersion. If the data input \code{x} is a
  feature matrix and not a dissimilarity matrix, the pairwise
  Euclidean distance is used. It uses the algorithm OptDispF presented 
  Papenberg, Breuer, et al. (2025). It was originally developed as part of 
  Max Diekhoff's Bachelor thesis at the Computer Science Department
  at Heinrich Heine University Düsseldorf.

  To find out which items are not allowed to be grouped in the same
  cluster for maximum dispersion, the algorithm sequentially builds
  instances of a graph coloring problem, using an integer linear
  programming (ILP) representation. It is possible to specify the ILP solver via the argument
  \code{solver} (See \code{\link{optimal_anticlustering}} for more
  information on this argument). Optimally solving the maximum
  dispersion problem is NP-hard for K > 2 and therefore
  computationally infeasible for larger data sets. For K = 3 and K
  = 4, it seems that this approach scales up to several 100
  elements, or even > 1000 for K = 3 (at least when using the
  Symphony or gurobi solver).  For larger data sets, use the heuristic
  approaches in \code{\link{anticlustering}} or
  \code{\link{bicriterion_anticlustering}}. However, note that for
  K = 2, the optimal approach is usually much faster than the
  heuristics.
  
  In the output, the element \code{edges} defines which elements
  must be in separate clusters in order to achieve maximum
  dispersion. All elements not listed here can be changed
  arbitrarily between clusters without reducing the dispersion.  If
  the maximum possible dispersion corresponds to the minimum
  dispersion in the data set, the output elements \code{edges} and
  \code{groups} are set to \code{NULL} because all possible
  groupings have the same value of dispersion.  In this case the
  output element \code{dispersions_considered} has length 1.
  
  If a \code{time_limit} is set and the function cannot find in the optimal
  dispersion in the given time, it will throw an error.
}
\note{
If the SYMPHONY solver is used, an unfortunate "message" is
    printed to the console when this function terminates:

sym_get_col_solution(): No solution has been stored!

This message is no reason to worry and instead is a direct result
of the algorithm finding the optimal value for the dispersion.
Unfortunately, this message is generated in the C code underlying
the SYMPHONY library (via the printing function \code{printf}),
which cannot be prevented in R.
}
\examples{

N <- 30
M <- 5
K <- 3
data <- matrix(rnorm(N*M), ncol = M)
distances <- dist(data)

opt <- optimal_dispersion(distances, K = K)
opt

# Compare to bicriterion heuristic:
groups_heuristic <- anticlustering(
  distances, 
  K = K,
  method = "brusco", 
  objective = "dispersion", 
  repetitions = 100
)
c(
  OPT = dispersion_objective(distances, opt$groups),
  HEURISTIC = dispersion_objective(distances, groups_heuristic)
)

# Different group sizes are possible:
table(optimal_dispersion(distances, K = c(15, 10, 5))$groups)

# Induce cannot-link constraints by maximizing the dispersion:
solvable <- matrix(1, ncol = 6, nrow = 6)
solvable[2, 1] <- -1
solvable[3, 1] <- -1
solvable[4, 1] <- -1
solvable <- as.dist(solvable)
solvable

# An optimal solution has to put item 1 in a different group than 
# items 2, 3 and 4 -> this is possible for K = 2
optimal_dispersion(solvable, K = 2)$groups

# It no longer works when item 1 can also not be linked with item 5:
# (check out output!)
unsolvable <- as.matrix(solvable)
unsolvable[5, 1] <- -1
unsolvable <- as.dist(unsolvable)
unsolvable
optimal_dispersion(unsolvable, K = 2)
# But:
optimal_dispersion(unsolvable, K = c(2, 4)) # group sizes, not number of groups

}
\references{
Diekhoff (2023). Maximizing dispersion for anticlustering. Retrieved from 
https://www.cs.hhu.de/fileadmin/redaktion/Fakultaeten/Mathematisch-Naturwissenschaftliche_Fakultaet/Informatik/Algorithmische_Bioinformatik/Bachelor-_Masterarbeiten/2831963_ba_ifo_AbschlArbeit_klau_mapap102_madie120_20230203_1815.pdf  

Papenberg, M., Breuer, M., Diekhoff, M., Tran, N. K., & Klau, G. W. (2025). 
Extending the Bicriterion Approach for Anticlustering: Exact and Hybrid 
Approaches. Psychometrika. Advance online publication. https://doi.org/10.1017/psy.2025.10052
}
\seealso{
\code{\link{dispersion_objective}} \code{\link{anticlustering}}
}
\author{
Max Diekhoff

Martin Papenberg \email{martin.papenberg@hhu.de}
}
