From murdoch.duncan at gmail.com  Tue Aug 12 15:47:01 2014
From: murdoch.duncan at gmail.com (Duncan Murdoch)
Date: Tue, 12 Aug 2014 09:47:01 -0400
Subject: [Rd] RFC: diag(x, n)  not preserving integer and logical x
In-Reply-To: <21480.53934.34861.185682@stat.math.ethz.ch>
References: <21475.15911.157158.65610@stat.math.ethz.ch>	<53E4E3DE.8050001@gmail.com>
	<21480.53934.34861.185682@stat.math.ethz.ch>
Message-ID: <53EA1AD5.1000808@gmail.com>

On 11/08/2014, 10:26 AM, Martin Maechler wrote:
>>>>>> Duncan Murdoch <murdoch.duncan at gmail.com>
>>>>>>     on Fri, 8 Aug 2014 10:51:10 -0400 writes:
> 
> Thank you, Duncan (read inline) 
> 
>     > On 07/08/2014, 4:51 AM, Martin Maechler wrote:
>     >> This is not at all something new(*). As maintainer of the
>     >> Matrix package, I don't like this inconsistency of base
>     >> R's diag().  We have had the following -- forever, almost
>     >> surely inherited from S and S+ :
>     >> 
>     >> diag(x) preserves the storage mode of x for 'complex' and
>     >> 'double' precision, but converts integer and logicals to
>     >> double :
>     >> 
>     >> > storage.mode(x <- 1i + 1:7); storage.mode(diag(x)) [1]
>     >> "complex" [1] "complex" > storage.mode(x <- 0 + 1:7);
>     >> storage.mode(diag(x)) [1] "double" [1] "double"
>     >> 
>     >> > storage.mode(x <- 1:7); storage.mode(diag(x)) [1]
>     >> "integer" [1] "double" > storage.mode(x <- 1:7 > 3);
>     >> storage.mode(diag(x)) [1] "logical" [1] "double"
>     >> 
>     >> and so it is actually a bit cumbersome (and a memory
>     >> waste in the case of large matrices) to create a diagonal
>     >> integer or logical matrix.
>     >> 
>     >> The help page does not mention the current behavior,
>     >> though you may say it alludes to the fact that logicals
>     >> are treated as 0/1 implicitly (**)
>     >> 
> 
>     > I think the change to preserve integer makes sense, but
>     > preserving logical does not.  A diagonal matrix has zeros
>     > off the diagonal, and they are not logical.  
> 
> That's true if you come from the usual mathematical thinking
> about matrices; and the same would extend to triangular
> matrices, too.

I'm not objecting to having a logical matrix, I'm objecting to saying
that a matrix with FALSE off the diagonal is a diagonal matrix.  A
diagonal matrix is one with zeros off the diagonal.

> 
> In (S and) R however, matrices and array()s have always been
> more general than in applied math (and have allowed any atomic (and even
> more general) content).
> 
>     > Having diag() sometimes return a matrix with FALSE off the diagonal just
>     > looks wrong.
> 
> [... if you have never seen them ..]
> OTOH, sparse matrices (in the Matrix package) and also sparse
> and dense triangular matrices (all with their classes) have
> always (in the Matrix package) had their logical counter parts,
> 
>   > Diagonal(5)
>   5 x 5 diagonal matrix of class "ddiMatrix"
>        [,1] [,2] [,3] [,4] [,5]
>   [1,]    1    .    .    .    .
>   [2,]    .    1    .    .    .
>   [3,]    .    .    1    .    .
>   [4,]    .    .    .    1    .
>   [5,]    .    .    .    .    1
>   > Diagonal(5) > 0
>   5 x 5 diagonal matrix of class "ldiMatrix"
>        [,1] [,2] [,3] [,4] [,5]
>   [1,] TRUE    .    .    .    .
>   [2,]    . TRUE    .    .    .
>   [3,]    .    . TRUE    .    .
>   [4,]    .    .    . TRUE    .
>   [5,]    .    .    .    . TRUE

That is completely different, and I have no objection to it.  Where I
would have an objection is if you got that result from

diag(rep(TRUE, 5))

or

Diagonal(rep(TRUE, 5))

Duncan Murdoch

>   > 
> 
> and if you consider any sparseness for logical matrices, typical
> application cases would have the TRUE to be rare rather than the
> FALSE... and then of course, we have had the  as.numeric(<logical>)
> behavior of S and R, all this leading to 
> the usual  FALSE <==> 0  mapping 
> 
> 
>     >> If I change this behavior such that logical and integer x
>     >> are preserved,
>     >> 
>     >> make check-all
>     >> 
>     >> which includes all checks, including those of all
>     >> recommended packages (including Matrix!) successfully
>     >> runs through; so at least base + Recommended R never
>     >> relies on the current behavior, nor should any "well
>     >> programmed" R code ...
>     >> 
>     >> Hence my proposal, somewhat tentative for now, to change
>     >> this diag(.) behavior.
>     >> 
>     >> Martin Maechler
>     >> 
>     >> *) and possibly something we "can not" change in R,
>     >> because too much code implicitely may be depending on it,
>     >> but now I hope we can still...
>     >> 
>     >> **) BTW, also including the somewhat amusing case of
>     >> diag(c("A","B")).
>     >> 
>     >> ______________________________________________
>     >> R-devel at r-project.org mailing list
>     >> https://stat.ethz.ch/mailman/listinfo/r-devel
>     >> 
>



[Rd] RFC: diag(x, n) not preserving integer and logical x
Duncan Murdoch