SCM

[#6810] which(.., arr.ind=TRUE) on lgRMatrix object produces result for transposed object

Date:
2023-06-07 06:24
Priority:
3
State:
Closed
Submitted by:
Hervé Pagès (hpages)
Assigned to:
Martin Maechler (mmaechler)
Hardware:
None
Product:
None
Operating System:
Linux
Component:
None
Version:
None
Severity:
normal
Resolution:
Fixed
URL:
Summary:
which(.., arr.ind=TRUE) on lgRMatrix object produces result for transposed object

Detailed description
Here is how to reproduce:

library(Matrix)
m <- matrix(c(FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE), ncol=2)
lgr <- as(m, "RsparseMatrix")
lgr
# 4 x 2 sparse Matrix of class "lgRMatrix"
#
# [1,] . |
# [2,] . |
# [3,] | .
# [4,] . |

This is correct (same as which(m)):

which(lgr)
# [1] 3 5 6 8

This is not correct:

which(lgr, arr.ind=TRUE)
# row col
# [1,] 1 2
# [2,] 2 2
# [3,] 3 1
# [4,] 4 2

The array-indices are correct but they are listed in the wrong order (they're listed row by row instead of column by column).

The correct answer is:

which(m, arr.ind=TRUE)
# row col
# [1,] 3 1
# [2,] 1 2
# [3,] 2 2
# [4,] 4 2

This is with Matrix 1.5-4.1 and R 4.3.0 on a 64-bit Intel machine running Ubuntu 23.04.

Best,
H.

Comments:

Message  ↓
Date: 2023-06-09 06:42
Sender: Hervé Pagès

Great! Thanks

Date: 2023-06-09 05:28
Sender: Mikael Jagan

Fixed now ... which(<Matrix>) and which(<matrix>) should now behave identically, i.e., consistently with help("which") ...

Notably which(<[CRT]sparseMatrix>) now coerces to sparseVector to get a result in column-major order, and that coercion now happens in C, for speed.

Date: 2023-06-07 18:45
Sender: Hervé Pagès

> it is *NOT* the result for the transposed matrix

Sorry I meant to say "which(.., arr.ind=TRUE) on lgRMatrix object produces result in order of transposed object". I don't know how to edit the title of the issue.

Anyways, it should not do that. As Mikael Jagan pointed out below, the contract as described in the man page is that 'which(m, arr.ind=TRUE)' should be equivalent to 'arrayInd(which(m, arr.ind=FALSE), dim(m), dimnames(m))'. This implies that 'arr.ind' should not affect the order in which the indices are returned.

Thanks

Date: 2023-06-07 11:15
Sender: Mikael Jagan

help("which") states:

========
Basically, the result is '(1:length(x))[x]' in typical cases; more generally, including when 'x' has 'NA''s, 'which(x)' is 'seq_along(x)[!is.na(x) & x]' plus 'names' when 'x' has.

If 'arr.ind == TRUE' and 'x' is an 'array' (has a 'dim' attribute), the result is 'arrayInd(which(x), dim(x), dimnames(x))', namely a matrix whose rows each are the indices of one element of 'x'; see Examples below.
========

hence I am inclined to agree that we must change (somehow) ... I can look later ...

Date: 2023-06-07 10:34
Sender: Martin Maechler

I can confirm what you see. However the result is just a
row-ordered version of what we get for "base matrix".
It is still correct and it is *NOT* the result for the transposed matrix.
The main property that which() promises is satisfied:
The resulting 2-column corresponds to cbind(i, j)
where <matrix>[ i[k], j[k] ] is TRUE (or non-0).

Why should we be more base-compatible here? Returning the result the way we do is most efficient for Rsparse matrices, and I don't think we promise anything about the ordering of the returned (i,j) indices?

Attached Files:

Changes

Field Old Value Date By
Severitymajor2023-06-09 05:28jaganmn
ResolutionNone2023-06-09 05:28jaganmn
status_idOpen2023-06-09 05:28jaganmn
close_dateNone2023-06-09 05:28jaganmn
assigned_tonone2023-06-07 10:34mmaechler
Thanks to:
Vienna University of Economics and Business Powered By FusionForge