[R] Re : Generate a random bistochastic matrix

Ravi Varadhan rvaradhan at jhmi.edu
Tue Oct 17 00:54:16 CEST 2006


Martin,

I don't think that a doubly stochastic matrix can be obtained from an
arbitrary positive rectangular matrix.  There is a theorem by Sinkhorn (Am
Math Month 1967) on the diagonal equivalence of matrices with prescribed row
and column sums.  It shows that given a positive matrix A(m x n), there is a
unique matrix DAE (where D and E are m x m and n x n diagonal matrices) with
rows, k*r_i (i = 1, ..., m), and column sums, c_j (j=1,...,n) such that k =
\sum_j c_j / \sum_i r_i.  Therefore, the alternative row and column
normalization algorithm (same as the iterative proportional fitting
algorithm for contingency tables) will alternate between row and column sums
being unity, while the other sum alternates between k and 1/k.

Here is a slight modification of your algorithm for the rectangular case:

bistochMat.rect <- function(m,n, tol = 1e-7, maxit = 1000) {
    ## Purpose: Random bistochastic *square* matrix (M_{ij}):
    ##	        M_{ij} >= 0;  sum_i M_{ij} = sum_j M_{ij} = 1   (for all i,
j)
    ##
----------------------------------------------------------------------
    ## Arguments: n: (n * n) matrix dimension;
    ##
----------------------------------------------------------------------
    ## Author: Martin Maechler, Date: 16 Oct 2006, 14:47
    stopifnot(maxit >= 1, tol >= 0)
    M <- matrix(runif(m*n), m,n)
    for(i in 1:maxit) {
	rM <- rowSum(M)
	M <- M / rep((rM),n)
	cM <- colSum(M)
	M <- M / rep((cM),each=m)
	if(all(abs(c(rM,cM) - 1) < tol))
	    break
    }
    ## cat("needed", i, "iterations\n")
    ## or rather
    attr(M, "iter") <- i
    M
}

Using this algorithm we get for an 8 x 4 matrix, for example, we get:

> M <- bistochMat.rect(8,4)
> apply(M,1,sum)
[1] 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
> apply(M,2,sum)
[1] 1 1 1 1
>
Clearly the algorithm didn't converge according to your convergence
criterion, but the row sums oscillate between 1 and 0.5, and the column sums
oscillate between 2 and 1, respectively.

It is interesting to note that the above algorithm converges if we use the
infinity norm, instead of the 1-norm, to scale the rows and columns, i.e. we
divide rows and columns by their maxima.


Best,
Ravi.

----------------------------------------------------------------------------
-------

Ravi Varadhan, Ph.D.

Assistant Professor, The Center on Aging and Health

Division of Geriatric Medicine and Gerontology 

Johns Hopkins University

Ph: (410) 502-2619

Fax: (410) 614-9625

Email: rvaradhan at jhmi.edu

Webpage:  http://www.jhsph.edu/agingandhealth/People/Faculty/Varadhan.html

 

----------------------------------------------------------------------------
--------


-----Original Message-----
From: r-help-bounces at stat.math.ethz.ch
[mailto:r-help-bounces at stat.math.ethz.ch] On Behalf Of Martin Maechler
Sent: Monday, October 16, 2006 10:30 AM
To: Florent Bresson
Cc: r-help at stat.math.ethz.ch
Subject: Re: [R] Re : Generate a random bistochastic matrix

A simpler approach --- as in similar problems ---
is to use an iterative solution  which works quite fast for any 'n'.
Interestingly, the number of necessary iterations seems to
*decrease* for increasing 'n' :

bistochMat <- function(n, tol = 1e-7, maxit = 1000)
{
    ## Purpose: Random bistochastic *square* matrix (M_{ij}):
    ##	        M_{ij} >= 0;  sum_i M_{ij} = sum_j M_{ij} = 1   (for all i,
j)
    ##
----------------------------------------------------------------------
    ## Arguments: n: (n * n) matrix dimension;
    ##
----------------------------------------------------------------------
    ## Author: Martin Maechler, Date: 16 Oct 2006, 14:47
    stopifnot(maxit >= 1, tol >= 0)
    M <- matrix(runif(n*n), n,n)
    for(i in 1:maxit) {
	M <- M / outer((rM <- rowSums(M)), (cM <- colSums(M))) * sum(rM) / n
	if(all(abs(c(rM,cM) - 1) < tol))
	    break
    }
    ## cat("needed", i, "iterations\n")
    ## or rather
    attr(M, "iter") <- i
    M
}

attr(M <- bistochMat(70), "iter")
## typically:
## [1] 8

attr(M <- bistochMat(10), "iter")
## -> 13, 16, 15, 17, ...

set.seed(101) ; attr(M <- bistochMat(10), "iter")             ## 15
set.seed(101) ; attr(M <- bistochMat(10, tol = 1e-15), "iter")## 32

------------------------

Initially, I tried to solve the general [ n x m ] case.
It seems that needs a slightly smarter "bias correction"
instead of just 'sum(M) / n'.
If someone figures that out, please post your solution!

Regards,
Martin Maechler, ETH Zurich

______________________________________________
R-help at stat.math.ethz.ch mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.



More information about the R-help mailing list