Minor matrix


#1

in R, I can use negative indices to construct a minor matrix easily, like:

> M <- matrix(1:9, nr = 3L);
> M
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
> M[-1L, -2L];
     [,1] [,2]
[1,]    2    8
[2,]    3    9

however, how to construct a minor matrix in Julia (I cannot find one in docs)? More generally, how to exclude some elements in indexing of Julia (negative indexing is used for counting from the end)?

Thanks!


#2

You can use setdiff. For example:

julia> M = reshape(1:9, 3,3)
3×3 reshape(::UnitRange{Int64}, 3, 3) with eltype Int64:
 1  4  7
 2  5  8
 3  6  9

julia> M[setdiff(1:end, 1), setdiff(1:end, 2)]
2×2 Array{Int64,2}:
 2  8
 3  9

Even more efficient would be to write a specialized function for this, which avoids allocating index arrays:

julia> function minor(A, i, j)
           m, n = size(A)
           B = similar(A, m-1, n-1)
           for j′=1:j-1, i′=1:i-1; B[i′,j′]=A[i′,j′]; end
           for j′=1:j-1, i′=i+1:m; B[i′-1,j′]=A[i′,j′]; end
           for j′=j+1:n, i′=1:i-1; B[i′,j′-1]=A[i′,j′]; end
           for j′=j+1:n, i′=i+1:m; B[i′-1,j′-1]=A[i′,j′]; end
           return B
       end

julia> minor(M, 1, 2)
2×2 Array{Int64,2}:
 2  8
 3  9

A nice thing about Julia is that you are not limited to digging through “built-in” functions hoping to find one that does just what you want — there is no performance problem with user-written loops, so in critical cases you can write your own function.


#3
julia> struct SkipRange <: AbstractVector{Int}
       start::Int
       stop::Int
       skip::Int
       end

julia> Base.length(s::SkipRange)=s.stop-s.start-1;

julia> Base.size(s::SkipRange) = (length(s),)

julia> Base.getindex(s::SkipRange, i) = s.start+i-1 < s.skip ? s.start+i-1 : s.start+i

julia> A=reshape(collect(1:25), 5, 5)
5×5 Array{Int64,2}:
 1   6  11  16  21
 2   7  12  17  22
 3   8  13  18  23
 4   9  14  19  24
 5  10  15  20  25

julia> sx=SkipRange(1,5,2); sy = SkipRange(1,5,1);

julia> A[sx,sy]
4×4 Array{Int64,2}:
  6  11  16  21
  8  13  18  23
  9  14  19  24
 10  15  20  25

julia> view(A,sx,sy)
4×4 view(::Array{Int64,2}, [1, 3, 4, 5], [2, 3, 4, 5]) with eltype Int64:
  6  11  16  21
  8  13  18  23
  9  14  19  24
 10  15  20  25

julia> typeof(view(A,sx,sy))
SubArray{Int64,2,Array{Int64,2},Tuple{SkipRange,SkipRange},false}

Pulling a copy instead of a view may be more efficient for many linear algebra operations (use BLAS instead of fallback), but sometimes you need to operate inplace.


#4

corrections of terminology:
minor should be a scalar: it’s the determinant of a submatrix (i.e. that “minor” I called) of a matrix with a row and a column deleted.


#5

It’s standard, if technically imprecise, to refer to both the determinant of the submatrix and the submatrix itself as “minor”, by metonymy.