function(x, model = "b", k = 2, method = "wl1fit", drawplot = F, alpha = 1, tol
	 = 0.0001, iter = 50, orth = T)
{
#
# C. Croux (Brussels, Belgium) and P. Filzmoser (Vienna, Austria)
#
# Final version for "Robust fit of two-way tables"
#
#
# x ......... data matrix
# model ..... "a"=additive, "m"=multiplicative, "b"=both (additive and multiplicative)
# k ......... dimension of multiplicative model fit (has no effect for model="a")
# method .... regression method: "lsfit", "l1fit", "wl1fit","lmsreg","ltsreg", "rreg", ...
# drawplot .. if TRUE, a plots will be drawn
# alpha ..... adjusting constant for biplot representation
# tol ....... tolerance for convergence
# iter ...... maximum number of iteration steps
# orth ...... orthogonalize f and l at the end for biplot representation (alpha=1)
#
#
# This program uses the following functions (not implemented in Splus):
#    prcomp.rob
#    weight.wl1
#    
#
# DESCRIPTION: 
#
# A robust additive and/or multiplicative fit of two-way tables can be calculated.
# The bilinear model is defined by 
#
# x_ij = mu + a_i + b_j + sum_{t=1}^{k} (f_it*sigma_t*l_jt) + e_ij
#
# for i=1,...,n and j=1,...,p, 
# with
#       x_ij .... (i,j) of the twoway table
#       mu   .... overall mean  \
#       a_i  .... row effect     >  additive parameters
#       b_j  .... column effect /
#       f_it    .... factor scores \
#       sigma_t .... scaling term   >  multiplicative parameters
#       l_jt    .... loadings      /
#       e_ij .... residuals
#       k .... number of factors.
# The additive model (model="a") includes just the additive parameters, the
# multiplicative model (model="m") includes just the multiplicative parameters.
#
# There are different possibilities for estimating all the parameters in the
# model:
#    method="lsfit" minimizes the sum over the squared residuals, 
#    method="l1fit" minimizes the sum over the absolute residuals, 
#    method="wl1fit" minimizes the sum over the weighted absolute residuals, the
#                    weights for rows and columns are computed by the routine
#                    "weight.wl1", 
# additionally it is possible to select one of "ltsreg", "lmsreg", and "rreg".
# It is suggested to use the methods L1-Regression ("l1fit") or Weighted L1-Regression
# ("wl1fit").
#
#
# OUTPUT:
#
# Depending on the chosen model ("a", "m", and "b"), the output of the procedure
# is:
#    mu        .... estimation of the overall mean
#    a         .... estimation of the row effect (n x 1)
#    b         .... estimation of the column effect (p x 1)
#    sigma     .... estimation of the scaling term (k x 1)
#    loadings  .... estimation of the loadings (p x k)
#    scores    .... estimation of the factor scores (n x k)
#    residuals .... final residuals (n x p)
#
# With the option `drawplot=T', a plot is created which includes 
#   a biplot representation of loadings and scores (for model="m" and "b", and k=2), 
#   a residual plot (for model="a", "m" and "b"), 
#   box plots of the parameters `a' and `b' (for model="a" and "b").
#  
#
# Begin of the procedure:
#
	call <- match.call()
	if(is.matrix(x) == F)
		(stop("x is no matrix."))
	n <- dim(x)[1]
	p <- dim(x)[2]
	if(!length(dimnames(x)[[2]]))
		dimnames(x) <- list(dimnames(x)[[1]], paste("X", 1:p, sep = "")
			)
        x_as.matrix(x)
	if(p > n) {
# take the transposed matrix
		x <- t(x)
		transp <- p
		p <- n
		n <- transp
		transp <- T
	}
	else transp <- F
	vecn0 <- rep(0, n)
	vecn1 <- rep(1, n)
	vecp0 <- rep(0, p)
	vecp1 <- rep(1, p)	#
# weights for Weighted L1 or Rob. Regression
	if((method == "wl1fit") || (method == "rreg")) {
# initialize matrices for row and column weights
		weightr <- matrix(0, n, p)
		weightc <- weightr
	}
# initialize the objective function
	objold <- 100000000000	#
# choice of the regression method
	imethod <- charmatch(method, c("lsfit", "l1fit", "wl1fit", "lmsreg", 
		"ltsreg", "rreg"), nomatch = NA)
	if(!is.na(imethod))
		method <- c("lsfit", "l1fit", "wl1fit", "lmsreg", "ltsreg", 
			"rreg")[imethod]
	if(method == "wl1fit") {
		if((n <= 2 * k) | (p <= 2 * k)) {
			stop("\nThe number of rows and columns should at least be > 2*k for WL1fit !\n"
				)
		}
	}
#
#
# starting values for iteration
#
	if(model != "m") {
		a <- apply(x, 1, median)
		mu <- median(a)
		a <- a - mu
		b <- vecp0
	}
	if(model != "a") {
# starting with robust PCA
		f <- prcomp.rob(x, k, sca = "A", scores = T)$scores[, 1:k]	#
# starting with classical PCA
#		f <- princomp(x)$scores[, 1:k]
# starting with random values
#		f <- matrix(rnorm(n * k, 0, 1), ncol = k)	
#
		if(k == 1) {
# k is the dimension of the multiplicatice terms
			f <- f - median(f)
			sigm <- sqrt(sum(f^2))
			f <- f/sigm
		}
		else {
			f <- f - vecn1 %*% t(apply(f, 2, median))
			sigm <- sqrt(apply(f^2, 2, sum))
			f <- t(t(f)/sigm)	#
# sorting by magnitude
			f <- f[, rev(sort.list(sigm))]
			sigm <- rev(sort(sigm))
		}
		sigmnew <- sigm
		sigmf <- matrix(0, n, k)
		sigml <- matrix(0, p, k)
	}
#
# begin of the iteration
#
	for(it in 1:iter) {
		cat("Iteration  ", it, "\n")	#
#
# regression of the columns
#
		for(j in 1:p) {
			if(method == "rreg") {
				sigmlreg <- switch(model,
				  a = get(method)(vecn1, (x[, j] - mu - a), int
				     = F),
				  m = get(method)(f, x[, j], int = F),
				  b = get(method)(f, (x[, j] - mu - a)))
				weightc1 <- sigmlreg$w
				sigmlreg <- sigmlreg$coef
			}
			if(method == "wl1fit") {
				if(j == 1) {
				  if(model == "a")
				    weightc1 <- vecn1
				  else weightc1 <- weight.wl1(f, n, k)
				}
				sigmlreg <- switch(model,
				  a = l1fit(vecn1, (x[, j] - mu - a), int = F)$
				    coef,
				  m = l1fit(weightc1 * f, weightc1 * (x[, j]), 
				    intercept = F)$coef,
				  b = l1fit(weightc1 * cbind(vecn1, f), 
				    weightc1 * (x[, j] - mu - a), intercept = F
				    )$coef)
			}
			else {
				sigmlreg <- switch(model,
				  a = get(method)(vecn1, (x[, j] - mu - a), int
				     = F)$coef,
				  m = get(method)(f, x[, j], int = F)$coef,
				  b = get(method)(f, (x[, j] - mu - a))$coef)
			}
			if((method == "wl1fit") || (method == "rreg"))
				weightc[, j] <- weightc1
			if(model == "a")
				b[j] <- sigmlreg
			if(model == "m")
				sigml[j,  ] <- t(sigmlreg[1:k])
			if(model == "b") {
				b[j] <- sigmlreg[1]
				sigml[j,  ] <- t(sigmlreg[2:(k + 1)])
			}
		}
# update the parameternestimates according to the model restrictions
		if(model == "a") {
			mb <- median(b)
			b <- b - mb
			ms <- mu + mb
		}
		if(model == "m") {
			if(k == 1) {
				sigm <- sqrt(sum(sigml^2))
				l <- sigml/sigm
				sigm <- as.matrix(sigm)
			}
			else {
				sigm <- sqrt(apply(sigml^2, 2, sum))
				l <- t(t(sigml)/sigm)
				l <- l[, rev(sort.list(sigm))]
				sigm <- rev(sort(sigm))
			}
		}
		if(model == "b") {
			if(k == 1) {
				hl <- median(sigml)
				l <- sigml - hl
				sigm <- sqrt(sum(l^2))
				l <- l/sigm
				a <- as.vector(a + f * hl)
			}
			else {
				hl <- apply(sigml, 2, median)
				l <- sigml - vecp1 %*% t(hl)
				sigm <- sqrt(apply(l^2, 2, sum))
				l <- t(t(l)/sigm)
				l <- l[, rev(sort.list(sigm))]
				sigm <- rev(sort(sigm))
				a <- as.vector(a + f %*% hl)
			}
			ma <- median(a)
			mb <- median(b)
			a <- a - ma
			b <- b - mb
			ms <- mu + ma + mb
		}
#
# regression of the rows
#
		for(i in 1:n) {
			if(method == "rreg") {
				sigmfreg <- switch(model,
				  a = get(method)(vecp1, (x[i,  ] - ms - b), 
				    int = F),
				  m = get(method)(l, x[i,  ], int = F),
				  b = get(method)(l, (x[i,  ] - ms - b)))
				weightr1 <- sigmfreg$w
				sigmfreg <- sigmfreg$coef
			}
			if(method == "wl1fit") {
				if(i == 1) {
				  if(model == "a")
				    weightr1 <- vecp1
				  else weightr1 <- weight.wl1(l, p, k)
				}
				sigmfreg <- switch(model,
				  a = l1fit(vecp1, (x[i,  ] - ms - b), int = F)$
				    coef,
				  m = l1fit(weightr1 * l, weightr1 * (x[i,  ]), 
				    intercept = F)$coef,
				  b = l1fit(weightr1 * cbind(vecp1, l), 
				    weightr1 * (x[i,  ] - ms - b), intercept = 
				    F)$coef)
			}
			else {
				sigmfreg <- switch(model,
				  a = get(method)(vecp1, (x[i,  ] - ms - b), 
				    int = F)$coef,
				  m = get(method)(l, x[i,  ], int = F)$coef,
				  b = get(method)(l, (x[i,  ] - ms - b))$coef)
			}
			if((method == "wl1fit") || (method == "rreg"))
				weightr[i,  ] <- weightr1
			if(model == "a")
				a[i] <- sigmfreg
			if(model == "m")
				sigmf[i,  ] <- t(sigmfreg[1:k])
			if(model == "b") {
				a[i] <- sigmfreg[1]
				sigmf[i,  ] <- t(sigmfreg[2:(k + 1)])
			}
		}
# update the parameter estimates according to the model restrictions
		if(model == "a") {
			ma <- median(a)
			a <- a - ma
			mu <- ms + ma
		}
		if(model == "m") {
			if(k == 1) {
				sigmnew <- sqrt(sum(sigmf^2))
				f <- sigmf/sigmnew
				sigmnew <- as.matrix(sigmnew)
			}
			else {
				f <- sigmf
				sigmnew <- sqrt(apply(sigmf^2, 2, sum))
				f <- t(t(sigmf)/sigmnew)
				f <- f[, rev(sort.list(sigmnew))]
				sigmnew <- rev(sort(sigmnew))
			}
		}
		if(model == "b") {
			if(k == 1) {
				hf <- median(sigmf)
				f <- sigmf - hf
				sigmnew <- sqrt(sum(f^2))
				f <- f/sigmnew
				sigmnew <- as.matrix(sigmnew)
				b <- as.vector(b + l * hf)
			}
			else {
				hf <- apply(sigmf, 2, median)
				f <- sigmf - vecn1 %*% t(hf)
				sigmnew <- sqrt(apply(f^2, 2, sum))
				f <- t(t(f)/sigmnew)
				f <- f[, rev(sort.list(sigmnew))]
				sigmnew <- rev(sort(sigmnew))
				b <- as.vector(b + l %*% hf)
			}
			ma <- median(a)
			mb <- median(b)
			a <- a - ma
			b <- b - mb
			mu <- ms + ma + mb
		}
# calculate the residuals
		if(method == "wl1fit") {
			resid <- switch(model,
				a = x - mu - a %*% t(vecp1) - vecn1 %*% t(b),
				m = x - f %*% diag(sigmnew) %*% t(l),
				b = x - mu - a %*% t(vecp1) - vecn1 %*% t(b) - 
				  f %*% diag(sigmnew) %*% t(l))
		}
		else {
#			cat("f= ")
#			print(f)
#			sigmnew <- as.matrix(sigmnew)
#			cat("diag(sigmnew)= ")
#			print(sigmnew)
#			cat("t(l)= ")
#			print(t(l))
#			cat("f%*%diag(sigmnew) = ")
#			print(f %*% diag(sigmnew))
			resid <- switch(model,
				a = x - mu - a %*% t(vecp1) - vecn1 %*% t(b),
				m = x - f %*% diag(sigmnew) %*% t(l),
				b = x - mu - a %*% t(vecp1) - vecn1 %*% t(b) - 
				  f %*% diag(sigmnew) %*% t(l))
		}
		if(method == "ltsreg") {
			help <- vecp0
			halfn <- floor((n + 1)/2)
			for(j in 1:p) {
				help[j] <- sum(sort(resid[, j]^2)[1:halfn])
			}
		}
		if(method == "lmsreg") {
			help <- vecp0
			halfn <- floor((n + 1)/2)
			for(j in 1:p) {
				help[j] <- sum(sort(abs(resid[, j]))[1:halfn])
			}
		}
		objnew <- switch(method,
			lsfit = sum(resid^2),
			l1fit = sum(abs(resid)),
			wl1fit = sum(abs(resid)),
			lmsreg = sum(sort(help)[1:floor((p + 1)/2)]),
			ltsreg = sum(sort(help)[1:floor((p + 1)/2)]),
			rreg = sum(weightc * weightr * resid^2))
		cat("Convergence criterion = ", objnew, "\n")
		if(model != "m") {
			musav <- mu
			asav <- as.vector(a)
			if(length(dimnames(x)[[1]]))
				names(asav) <- dimnames(x)[[1]]
			bsav <- as.vector(b)
			names(bsav) <- dimnames(x)[[2]]
		}
		if(model != "a") {
			sigmasav <- sigmnew
			fnames <- paste("Fact.", 1:k)
			lsav <- l
			dimnames(lsav) <- list(dimnames(x)[[2]], fnames)
			fsav <- f
			if(length(dimnames(x)[[1]]))
				dimnames(fsav) <- list(dimnames(x)[[1]], fnames
				  )
			else dimnames(fsav) <- list(NULL, fnames)
		}
		ressav <- resid
		objsav <- objnew
		itersav <- it
		if((abs((objold - objnew)/max(objnew, 1)) < tol) || (objnew < 
			tol))
			break
		objold <- objnew
	}
	if(model == "a")
		if(transp == T)
			ans <- list(mu = musav, a = bsav, b = asav, residuals
				 = t(ressav), objective = objsav, iterations = 
				itersav, model = "additive", method = method, 
				call = call)
		else ans <- list(mu = musav, a = asav, b = bsav, residuals = 
				ressav, objective = objsav, iterations = 
				itersav, model = "additive", method = method, 
				call = call)
	if(model == "m")
		if(transp == T)
			ans <- list(sigma = sigmasav, loadings = fsav, scores
				 = lsav, residuals = t(ressav), objective = 
				objsav, iterations = itersav, model = 
				"multiplicative", method = method, call = call)
		else ans <- list(sigma = sigmasav, loadings = lsav, scores = 
				fsav, residuals = ressav, objective = objsav, 
				iterations = itersav, model = "multiplicative", 
				method = method, call = call)
	if(model == "b") {
		if(transp == T)
			ans <- list(mu = musav, a = bsav, b = asav, sigma = 
				sigmasav, loadings = fsav, scores = lsav, 
				residuals = t(ressav), objective = objsav, 
				iterations = itersav, model = "add+mult", 
				method = method, call = call)
		else ans <- list(mu = musav, a = asav, b = bsav, sigma = 
				sigmasav, loadings = lsav, scores = fsav, 
				residuals = ressav, objective = objsav, 
				iterations = itersav, model = "add+mult", 
				method = method, call = call)
	}
# if a plots are desired
	if((drawplot == T) && (model != "a") && (k == 2)) {
		if(model == "m") {
			par(mfrow = c(2, 1))
		}
		else {
			par(mfrow = c(2, 2))
		}
		if((alpha < 0) || (alpha > 1)) {
			warning("alpha for biplot has to be in the interval [0,1] --> it is set to 1"
				)
			alpha <- 1
		}
		if(transp == T) {
			h <- lsav
			lsav <- fsav
			fsav <- h
		}
		if(orth == T) {
# orthogonalize f and l for the biplot
			fo <- svd(fsav)
			lo <- svd(lsav)
			f <- fo$u
			dimnames(f) <- dimnames(fsav)
			l <- lo$u
			dimnames(l) <- dimnames(lsav)
			sigm <- diag(fo$d) %*% t(fo$v) %*% diag(sigmasav) %*% 
				lo$v %*% diag(lo$d)
			biplot.default(f, l %*% t(sigm))
		}
		else biplot.default(fsav %*% diag(sigmasav^(1 - alpha)), lsav %*% 
				diag(sigmasav^alpha))
		title("Biplot")
		persp(ressav)
		title("Residuals")
		if(model == "b") {
			if(transp == T)
				boxplot(bsav)
			else boxplot(asav)
			title("Row Effects")
			if(transp == T)
				boxplot(asav)
			else boxplot(bsav)
			title("Column Effects")
		}
	}
	if((drawplot == T) && (model == "a")) {
		par(mfrow = c(2, 2))
		if(transp == T)
			boxplot(bsav)
		else boxplot(asav)
		title("Row Effects")
		if(transp == T)
			boxplot(asav)
		else boxplot(bsav)
		title("Column Effects")
		persp(ressav)
		title("Residuals")
	}
	ans
}
