#### Triangular Sparse Matrices in compressed column-oriented format

setAs("dtCMatrix", "ltCMatrix",
      function(from) new("ltCMatrix", i = from@i, p = from@p,
			 uplo = from@uplo, diag = from@diag,
                         x = as.logical(from@x),
			 ## FIXME?: use from@factors smartly
			 Dim = from@Dim, Dimnames = from@Dimnames))
setAs("dtCMatrix", "ntCMatrix", # just drop 'x' slot:
      function(from) new("ntCMatrix", i = from@i, p = from@p,
			 uplo = from@uplo, diag = from@diag,
			 ## FIXME?: use from@factors smartly
			 Dim = from@Dim, Dimnames = from@Dimnames))


setAs("matrix", "dtCMatrix",
      function(from) as(as(from, "dtTMatrix"), "dtCMatrix"))

setAs("dtCMatrix", "dgCMatrix",
      function(from) {
          if (from@diag == "U")
              from <- .Call(Csparse_diagU2N, from)
          ## new("dgCMatrix",
          ##     i = from@i, p = from@p, x = from@x,
          ##     Dim = from@Dim, Dimnames = from@Dimnames)
          ## ---> Rather faster, no checking:
          copyClass(from, "dgCMatrix",
                    sNames = c("i", "p", "x", "Dim", "Dimnames"), check = FALSE)
      })

setAs("dtCMatrix", "dsCMatrix", function(from) as(from, "symmetricMatrix"))

setAs("dtCMatrix", "dgTMatrix",
      function(from) {
          if (from@diag == "U") from <- .Call(Csparse_diagU2N, from)
          ## ignore triangularity in conversion to TsparseMatrix
          .Call(Csparse_to_Tsparse, from, FALSE)
      })

## FIXME: make more efficient
## -----  and  as(., "triangularMatrix") is even worse via as_Sp()
setAs("dgCMatrix", "dtCMatrix", # to triangular, needed for triu,..
      function(from) as(.Call(Csparse_to_Tsparse, from, FALSE), "dtCMatrix"))

setAs("dtCMatrix", "dgeMatrix",
      function(from) as(as(from, "dgTMatrix"), "dgeMatrix"))

## These are all needed because cholmod doesn't support triangular:
## (see end of ./Csparse.R ), e.g. for triu()
setAs("dtCMatrix", "dtTMatrix",
      function(from) .Call(Csparse_to_Tsparse, from, TRUE))
##   {# and this is not elegant:
##           x <- as(from, "dgTMatrix")
##  	  if (from@diag == "U") { ## drop diagonal entries '1':
##  	      i <- x@i; j <- x@j
##  	      nonD <- i != j
##  	      xx <- x@x[nonD] ; i <- i[nonD] ; j <- j[nonD]
##  	  } else {
##  	      xx <- x@x; i <- x@i; j <- x@j
##  	  }
##  	  new("dtTMatrix", x = xx, i = i, j = j, Dim = x@Dim,
##  	      Dimnames = x@Dimnames, uplo = from@uplo, diag = from@diag)
##       })

## Now that we support triangular matrices use the inherited method.
## setAs("dtCMatrix", "TsparseMatrix", function(from) as(from, "dtTMatrix"))

setAs("dtCMatrix", "dtrMatrix",
      function(from) as(as(from, "dtTMatrix"), "dtrMatrix"))

setMethod("determinant", signature(x = "dtCMatrix", logarithm = "logical"),
	  function(x, logarithm = TRUE, ...) {
	      if(x@diag == "N")
		  mkDet(diag(x), logarithm)
	      else
		  structure(list(modulus = structure(if (logarithm) 0 else 1,
				 "logarithm" = logarithm),
				 sign = 1L),
			    class = "det")
	  })


setMethod("solve", signature(a = "dtCMatrix", b = "missing"),
	  function(a, b, ...) {
	      stopifnot((n <- nrow(a)) == ncol(a))
	      as(.Call(dtCMatrix_sparse_solve, a, .trDiagonal(n, unitri=FALSE)),
                 "dtCMatrix")
          }, valueClass = "dtCMatrix")

setMethod("solve", signature(a = "dtCMatrix", b = "dgeMatrix"),
	  function(a, b, ...) .Call(dtCMatrix_matrix_solve, a, b, TRUE),
	  valueClass = "dgeMatrix")

setMethod("solve", signature(a = "dtCMatrix", b = "CsparseMatrix"),
	  function(a, b, ...) .sortCsparse(.Call(dtCMatrix_sparse_solve, a, b)),
	  ##                  ------------ TODO: both in C code
	  valueClass = "dgCMatrix")

setMethod("solve", signature(a = "dtCMatrix", b = "matrix"),
	  function(a, b, ...) {
            storage.mode(b) <- "double"
            .Call(dtCMatrix_matrix_solve, a, b, FALSE)
	  }, valueClass = "dgeMatrix")

## Isn't this case handled by the method for (a = "Matrix', b =
## "numeric") in ./Matrix.R? Or is this method defined here for
## the as.double coercion?
setMethod("solve", signature(a = "dtCMatrix", b = "numeric"),
	  function(a, b, ...) .Call(dtCMatrix_matrix_solve, a,
				    cbind(as.double(b), deparse.level=0L), FALSE),
          valueClass = "dgeMatrix")

if(FALSE)## still not working
setMethod("diag", "dtCMatrix",
	  function(x, nrow, ncol) .Call(diag_tC, x, "diag"))


## no pivoting here, use  L or U
setMethod("lu", "dtCMatrix",
	  function(x, ...) {
	      n <- (d <- x@Dim)[1L]
	      p <- 0:(n-1L)
	      if(x@uplo == "U")
		  new("sparseLU",
		      L = .trDiagonal(n, uplo="L"),
		      U = x,
		      p = p, q = p, Dim = d)
	      else { ## "L" :  x = L = L I
		  d <- diag(x)
		  new("sparseLU",
		      L = x %*% Diagonal(n, 1/d),
		      U = .trDiagonal(n, x = d),
		      p = p, q = p, Dim = d)
	      }
	  })


