% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/lap_solve.R
\name{sinkhorn}
\alias{sinkhorn}
\title{'Sinkhorn-Knopp' optimal transport solver}
\usage{
sinkhorn(
  cost,
  lambda = 10,
  tol = 1e-09,
  max_iter = 1000,
  r_weights = NULL,
  c_weights = NULL
)
}
\arguments{
\item{cost}{Numeric matrix of transport costs. \code{NA} or \code{Inf} entries are
treated as very high cost (effectively forbidden).}

\item{lambda}{Regularization parameter (default 10). Higher values produce
sharper (more deterministic) transport plans; lower values produce smoother
distributions. Typical range: 1-100.}

\item{tol}{Convergence tolerance (default 1e-9).}

\item{max_iter}{Maximum iterations (default 1000).}

\item{r_weights}{Optional numeric vector of row marginals (source distribution).
Default is uniform. Will be normalized to sum to 1.}

\item{c_weights}{Optional numeric vector of column marginals (target distribution).
Default is uniform. Will be normalized to sum to 1.}
}
\value{
A list with elements:
\itemize{
\item \code{transport_plan} — numeric matrix, the optimal transport plan P.
Row sums approximate r_weights, column sums approximate c_weights.
\item \code{cost} — the transport cost <C, P> (without entropy term).
\item \code{u}, \code{v} — scaling vectors (P = diag(u) * K * diag(v) where K = exp(-lambda*C)).
\item \code{converged} — logical, whether the algorithm converged.
\item \code{iterations} — number of iterations used.
\item \code{lambda} — the regularization parameter used.
}
}
\description{
Compute an entropy-regularized optimal transport plan using the 'Sinkhorn-Knopp'
algorithm. Unlike other LAP solvers that return a hard 1-to-1 assignment,
this returns a soft assignment (doubly stochastic matrix).
}
\details{
The 'Sinkhorn-Knopp' algorithm solves the entropy-regularized optimal transport
problem:

\deqn{P^* = \arg\min_P \langle C, P \rangle - \frac{1}{\lambda} H(P)}

subject to row sums = r_weights and column sums = c_weights.

The entropy term H(P) encourages spread in the transport plan. As lambda -> Inf,
the solution approaches the standard (unregularized) optimal transport.

\strong{Key differences from standard LAP solvers:}
\itemize{
\item Returns a soft assignment (probabilities) not a hard 1-to-1 matching
\item Supports unequal marginals (weighted distributions)
\item Differentiable, making it useful in ML pipelines
\item Very fast: O(n^2) per iteration with typically O(1/tol^2) iterations
}

Use \code{\link[=sinkhorn_to_assignment]{sinkhorn_to_assignment()}} to round the soft assignment to a hard matching.
}
\examples{
cost <- matrix(c(1, 2, 3, 4, 5, 6, 7, 8, 9), nrow = 3, byrow = TRUE)

# Soft assignment with default parameters
result <- sinkhorn(cost)
print(round(result$transport_plan, 3))

# Sharper assignment (higher lambda)
result_sharp <- sinkhorn(cost, lambda = 50)
print(round(result_sharp$transport_plan, 3))

# With custom marginals (more mass from row 1)
result_weighted <- sinkhorn(cost, r_weights = c(0.5, 0.25, 0.25))
print(round(result_weighted$transport_plan, 3))

# Round to hard assignment
hard_match <- sinkhorn_to_assignment(result)
print(hard_match)

}
\references{
Cuturi, M. (2013). 'Sinkhorn Distances': Lightspeed Computation of Optimal
Transport. \emph{Advances in Neural Information Processing Systems}, 26.
}
\seealso{
\code{\link[=assignment]{assignment()}} for hard 1-to-1 matching, \code{\link[=sinkhorn_to_assignment]{sinkhorn_to_assignment()}}
to round soft assignments.
}
