---
title: "The `kantorovich` package"
author: "Stéphane Laurent"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{The `kantorovich` package}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

The `kantorovich` package has two main features:

* It computes the extreme joinings of two probability measures $\mu$ and $\nu$ on a finite set;
* It computes the Kantorovich distance between these two measures, for a given distance on their finite state space.


# Exact results 

With the help of the `rccd` and `gmp` packages, the `kantorovich` package can return the *exact* values of the extreme joinings and of the Kantorovich distance. 

## Quick example 

As an example, take $\mu$ and $\nu$ the uniform probability measures on a finite set having three elements.

```{r}
mu <- nu <- c(1/3, 1/3, 1/3)
```

The `ejoinings` function returns the extreme joinings of $\mu$ and $\nu$. In this case these are the $6!$ permutation matrices:

```{r}
library(kantorovich)
ejoinings(mu, nu)
```

Since `mu` and `nu` were unnamed, the vector names `c(1,2,3)` has been automatically assigned to them. 
The Kantorovich distance between $\mu$ and $\nu$ is relative to a given distance on the state space of $\mu$ and $\nu$, represented by their vector names. By default, the `kantorovich` package takes the discrete $0\mathrm{-}1$ distance. Obviously the Kantorovich distance is $0$ on this example, because $\mu=\nu$. 

```{r}
kantorovich(mu, nu)
```

Note the message returned by both the `ejoinings` and the `kantorovich` functions. In order to get exact results, use rational numbers with the `gmp` package:

```{r, message=FALSE, warning=FALSE}
library(gmp)
mu <- nu <- as.bigq(c(1,1,1), c(3,3,3)) # shorter: as.bigq(c(1,1,1), 3) 
ejoinings(mu, nu)
```

## User-specified distance 

Let us try an example with a user-specified distance. 
Let's say that the state space of $\mu$ and $\nu$ is $\{a, b, c\}$, 
and then we use `c("a","b","c")` as the vector names.

```{r}
mu <- as.bigq(c(1,2,4), 7)
nu <- as.bigq(c(3,1,5), 9)
names(mu) <- names(nu) <- c("a", "b", "c")
```


### Define distance as a matrix 

The distance can be specified as a matrix. 

Assume the distance $\rho$ is given by $\rho(a,b)=1$, $\rho(a,c)=2$ and $\rho(b,c)=4$. 
The `bigq` matrices offered by the `gmp` package do not handle dimension names. 
But, in our example, the distance $\rho$ takes only integer values, 
 therefore one can use a numerical matrix:

```{r}
M <- matrix(
  c(
    c(0, 1, 2),
    c(1, 0, 4),
    c(2, 4, 0)
  ), 
  byrow = TRUE, nrow = 3,
  dimnames = list(c("a","b","c"), c("a","b","c")))
kantorovich(mu, nu, dist=M)
```

If the distance takes rational values, one can proceed as before with a character matrix:

```{r}
M <- matrix(
  c(
    c("0", "3/13", "2/13"),
    c("1/13", "0", "4/13"),
    c("2/13", "4/13", "0")
  ), 
  byrow = TRUE, nrow = 3,
  dimnames = list(c("a","b","c"), c("a","b","c")))
kantorovich(mu, nu, dist=M)
```

### Define distance as a function 

One can enter the distance as a function. In such an example, this does not sound convenient:

```{r}
rho <- function(x,y){
  if(x==y) {
    return(0)
  } else {
    if(x=="a" && y=="b") return(1)
    if(x=="a" && y=="c") return(2)
    if(x=="b" && y=="c") return(4)
    return(rho(y,x))
  } 
}
kantorovich(mu, nu, dist=rho)
```

Using a function could be more convenient in the case when the names are numbers:

```{r}
names(mu) <- names(nu) <- 1:3
```

But one has to be aware that there are in character mode:

```{r}
names(mu)
```

Thus, one can define a distance function as follows, for example with  $\rho(x,y)=\frac{|x-y|}{1+|x-y|}$:

```{r}
rho <- function(x,y){
  x <- as.numeric(x); y <- as.numeric(y)
  return(as.bigq(abs(x-y), 1+abs(x-y)))
}
kantorovich(mu, nu, dist=rho)
```


## A non-square example 

The `kantorovich` package also handles the case when `mu` and `nu` have different lengths, such as this example:

```{r}
mu <- as.bigq(c(1,2,4), 7)
nu <- as.bigq(c(3,1), 4)
names(mu) <- c("a", "b", "c") 
names(nu) <- c("b", "c")
ejoinings(mu, nu)
kantorovich(mu, nu)
```

Note the caution message.  The `kantorovich` package has to handle the fact that `mu` is given on the set $\{a,b,c\}$ while `nu` is given on the set $\{b,c\}$. It detects that the second set is included in the first one, and then treats `nu` on the bigger set $\{a,b,c\}$ by assigning $\nu(a)=0$. To avoid this caution message, the user has to enter this $0$ value:

```{r}
nu <- as.bigq(c(0,3,1), 4)
names(nu) <- c("a", "b", "c") 
```


# Other solvers 

The `kantorovich` package provides three other functions to compute the Kantorovich distance:

- `kantorovich_lp`, which uses the [lp_solve](http://web.mit.edu/lpsolve/doc/) solver with the help of the `lpSolve` package;

- `kantorovich_glpk`, which uses the [GLPK](http://www.gnu.org/software/glpk/) solver with the help of the `Rglpk` package. 

- `kantorovich_CVX`, which uses the [ECOS](https://web.stanford.edu/~boyd/papers/ecos.html) solver with the help of the `CVXR` package. 

Contrary to the `kantorovich` function, these two functions do not take care of the names of the two vectors `mu` and `nu` representing the two probability measures $\mu$ and $\nu$, and the distance to be minimized on average must be given as a matrix only, not a function. 

A better precision is achieved by `kantorovich_glpk`. For instance, take the previous example for which we found $13/63$ as the exact Kantorovich distance:

```{r, collapse=TRUE}
mu <- c(1,2,4)/7
nu <- c(3,1,5)/9
M <- matrix(
  c(
    c(0, 1, 2),
    c(1, 0, 4),
    c(2, 4, 0)
  ), 
  byrow = TRUE, nrow = 3)
kanto_lp <- kantorovich_lp(mu, nu, dist=M)
kanto_glpk <- kantorovich_glpk(mu, nu, dist=M)
kanto_CVX <- kantorovich_CVX(mu, nu, dist=M)
```

Then `kantorovich_lp` and `kantorovich_CVX` do not return the better decimal approximation of $13/63$:

```{r, collapse=TRUE}
print(kanto_lp, digits=22)
print(kanto_glpk, digits=22)
print(kanto_CVX, digits=22)
print(13/63, digits=22)
```

But `kantorovich_CVX` is the fastest one, and it handles the case when the 
marginal probability measures `mu` and `nu` have a large support.
