Constructing Algebraic Matrices

There are several functions for creating matrices – in each case you need to indicate the ring to which the matrix elements belong, unless this is already unambiguously indicated by the ring to which the arguments belong. Here we present several of the basic functions for constructing matrices.

Why Julia matrices are not sufficient

Unfortunately, Julia's matrices cannot be used in our context due to two independent problems:

  • In empty matrices (0 rows or columns) all that is known about a Julia matrix is the type of its entries,

however for advanced algebraic types, this information is insufficient to create elements, hence zero(T) or friends cannot work.

  • Many Julia functions (e.g. det) assume that all types used embed into the real or complex numbers. For

instance, in Julia det(ones(Int, (1,1))) == 1.0, so the fact that the determinant is exactly the integer 1 is lost. Furthermore, more general rings cannot be embedded into the reals at all.

For this reason, the matrix constructors below must accept (or infer) the ring in which all entries of the matrix reside.

Constructing matrices from entries

AbstractAlgebra.matrixMethod
matrix(R::NCRing, arr::AbstractMatrix{T}) where {T}

Return the matrix over the ring R with entries as in the Julia AbstractMatrix arr. All entries of arr must be coercible into R.

Examples

julia> matrix(GF(3), [1 2 ; 3 4])
[1   2]
[0   1]

julia> matrix(ZZ, BigInt[3 1 2; 2 0 1])
[3   1   2]
[2   0   1]
source
AbstractAlgebra.matrixMethod
matrix(R::NCRing, r::Int, c::Int, arr::AbstractVecOrMat{T}) where {T}

Return the r by c matrix over the ring R from the entries of arr.

If arr is a vector, its entries are read row-wise, so the $(i, j)$ entry is given by arr[c*(i - 1) + j]. All entries must be coercible into R.

If arr is a matrix, this is equivalent to matrix(R, arr).

Examples

julia> matrix(ZZ, 3, 2, BigInt[3, 1, 2, 2, 0, 1])
[3   1]
[2   2]
[0   1]
source

Several other signatures are supported:

matrix(arr::AbstractMatrix{T}) where {T<:NCRingElement}
matrix(arr::AbstractVector{T}) where {T<:NCRingElement}
matrix(arr::AbstractVector{<:AbstractVector{T}}) where {T<:NCRingElement}

Nested vectors can also be used to construct matrices over a specified base ring:

matrix(R::NCRing, arr::AbstractVector{<:AbstractVector})

Constructing matrices from existing matrices

Changing the base ring

Matrices can be converted to another base ring using change_base_ring.

AbstractAlgebra.change_base_ringMethod
change_base_ring(R::NCRing, M::MatrixElem{T}) where {T <: NCRingElement}

Return a new matrix over R by coercing each entry of M into R.

The input matrix is not modified.

Examples

julia> M = matrix(ZZ, [1 2; 3 4])
[1   2]
[3   4]

julia> N = change_base_ring(QQ, M)
[1//1   2//1]
[3//1   4//1]

julia> base_ring(N)
Rationals
source

The same conversion can also be performed using the following constructors:

matrix(R::NCRing, arr::MatElem)
matrix(R::NCRing, arr::MatRingElem)

Copying

An independent copy of an existing matrix can be created.

matrix(mat::MatElem{T}) where {T<:NCRingElement}

Zero matrices

Base.zeroMethod
zero(x::MatElem{T}, R::NCRing, r::Int, c::Int) where {T <: NCRingElement}
zero(x::MatElem{T}, r::Int, c::Int) where {T <: NCRingElement}
zero(x::MatElem{T}, R::NCRing) where T <: {NCRingElement}
zero(x::MatElem{T}) where {T <: NCRingElement}

Create a zero matrix with the same implementation type as the given matrix x.

By default, the base ring and dimensions are inherited from x, but they can also be specified explicitly.

source

Identity matrices

AbstractAlgebra.identity_matrixMethod
identity_matrix(M::MatElem{T}) where {T <: NCRingElement}

Return the identity matrix with the same base ring and dimensions as the given abstract matrix M. The matrix M must be square.

This is an alias for one(M).

Examples

julia> M = matrix(ZZ, [1 2; 3 4])
[1   2]
[3   4]

julia> identity_matrix(M)
[1   0]
[0   1]
source
AbstractAlgebra.identity_matrixMethod
identity_matrix(M::MatElem{T}, n::Int) where {T <: NCRingElement}

Return the identity $n \times n$ matrix over the same base ring as the given abstract matrix M.

source
Base.oneMethod
one(a::MatElem{T}) where {T <: NCRingElement}

Return the identity matrix with the same base ring and dimensions as a.

The matrix a must be square.

source

Uninitialized matrices

Base.similarMethod
similar(x::MatElem{T}, R::NCRing, r::Int, c::Int) where T <: NCRingElement
similar(x::MatElem{T}, R::NCRing) where T <: NCRingElement
similar(x::MatElem{T}, r::Int, c::Int) where T <: NCRingElement
similar(x::MatElem{T}) where T <: NCRingElement

Create an uninitialized matrix with the same implementation type as x.

By default, the base ring and dimensions are inherited from x, but they can also be specified explicitly.

This method is useful when implementing algorithms which create new matrices whose entries will be filled in later.

Despite the name, similar is not related to similarity transformations or similar matrices in the mathematical sense.

Examples

julia> M = matrix(ZZ, [1 2 3; 4 5 6])
[1   2   3]
[4   5   6]

julia> similar(M)
[#undef   #undef   #undef]
[#undef   #undef   #undef]

julia> similar(M, 2, 2)
[#undef   #undef]
[#undef   #undef]
source

Concatenation

Matrices can be constructed from existing matrices by concatenating them horizontally or vertically.

Base.hcatMethod
Base.hcat(A::MatElem...)

Return the horizontal concatenation of the matrices in $A$.

All component matrices must have the same base ring and the same number of rows.

Examples

julia> M = matrix(ZZ, BigInt[1 2 3; 2 3 4; 3 4 5])
[1   2   3]
[2   3   4]
[3   4   5]

julia> N = matrix(ZZ, BigInt[1 0 1; 0 1 0; 1 0 1])
[1   0   1]
[0   1   0]
[1   0   1]

julia> hcat(M, N)
[1   2   3   1   0   1]
[2   3   4   0   1   0]
[3   4   5   1   0   1]
source
Base.vcatMethod
Base.vcat(A::MatElem...)

Return the vertical concatenation of the matrices in $A$.

All component matrices must have the same base ring and the same number of columns.

Examples

julia> M = matrix(ZZ, BigInt[1 2 3; 2 3 4; 3 4 5])
[1   2   3]
[2   3   4]
[3   4   5]

julia> N = matrix(ZZ, BigInt[1 0 1; 0 1 0; 1 0 1])
[1   0   1]
[0   1   0]
[1   0   1]

julia> vcat(M, N)
[1   2   3]
[2   3   4]
[3   4   5]
[1   0   1]
[0   1   0]
[1   0   1]
source

Submatrices and views

Submatrices can be constructed using Julia indexing syntax. By default, this creates a new matrix containing the selected entries.

To avoid copying entries, one can instead construct a view using Julia's @view syntax. Views are particularly useful for working with small regions of large matrices, as modifications to a view also modify the original matrix.

Examples

julia> M = matrix(ZZ, [1 2 3; 2 3 4; 3 4 5])
[1   2   3]
[2   3   4]
[3   4   5]

julia> M[1:2, 1:2]
[1   2]
[2   3]

julia> N = @view M[1:2, 1:2]
[1   2]
[2   3]

julia> N[1, 1] = 10
10

julia> M
[10   2   3]
[ 2   3   4]
[ 3   4   5]

Special constructors

The zero matrix

AbstractAlgebra.zero_matrixMethod
zero_matrix(R::NCRing, r::Int, c::Int)

Return the $r \times c$ matrix over the ring R whose entries are all zero.

Examples

julia> P = zero_matrix(ZZ, 3, 2)
[0   0]
[0   0]
[0   0]
source

The ones matrix

AbstractAlgebra.ones_matrixMethod
ones_matrix(R::NCRing, r::Int, c::Int)

Return the $r \times c$ matrix over the ring R whose entries are all equal to the multiplicative identity of R.

Examples

julia> ones_matrix(ZZ, 3, 2)
[1   1]
[1   1]
[1   1]
source

The identity matrix

AbstractAlgebra.identity_matrixMethod
identity_matrix(R::NCRing, n::Int)

Return the $n \times n$ identity matrix over the ring R.

Examples

julia> identity_matrix(ZZ, 2)
[1   0]
[0   1]
source

Scalar matrices

AbstractAlgebra.scalar_matrixMethod
scalar_matrix(R::NCRing, n::Int, a::NCRingElement)

Return the $n \times n$ diagonal matrix over the ring R whose diagonal entries are all equal to the ring element a of R.

Examples

julia> scalar_matrix(QQ, 3, 1//2)
[1//2   0//1   0//1]
[0//1   1//2   0//1]
[0//1   0//1   1//2]
source
AbstractAlgebra.scalar_matrixMethod
scalar_matrix(n::Int, a::NCRingElement)

Return the $n \times n$ diagonal matrix over parent(a) whose diagonal entries are all equal to the ring element a.

Examples

julia> scalar_matrix(3, ZZ(5))
[5   0   0]
[0   5   0]
[0   0   5]
source

Diagonal matrices

AbstractAlgebra.diagonal_matrixFunction
diagonal_matrix(x::NCRingElement, m::Int, n::Int = m)

Return the $m \times n$ matrix over the ring parent(x) with x along the main diagonal and zeros elsewhere. If n is omitted, return an $m \times m$ matrix.

Examples

julia> diagonal_matrix(ZZ(2), 2, 3)
[2   0   0]
[0   2   0]

julia> diagonal_matrix(QQ(-1), 3)
[-1//1    0//1    0//1]
[ 0//1   -1//1    0//1]
[ 0//1    0//1   -1//1]
source
AbstractAlgebra.diagonal_matrixMethod
diagonal_matrix(R::NCRing, entries::AbstractVector{<:NCRingElement})
diagonal_matrix(entries::AbstractVector{<:NCRingElement})
diagonal_matrix(x::T, xs::T...) where {T<:NCRingElement}

Return a diagonal matrix with the given entries on the main diagonal.

For the vector forms, the diagonal entries are the elements of entries. For the vararg form, the diagonal entries are x, xs....

If the ring R is given, the entries are coerced into R. Otherwise, the base ring is inferred from the entries.

Examples

julia> diagonal_matrix(ZZ(1), ZZ(2))
[1   0]
[0   2]

julia> diagonal_matrix(ZZ, [5, 6])
[5   0]
[0   6]

julia> diagonal_matrix([ZZ(3), ZZ(4)])
[3   0]
[0   4]
source

Diagonal matrices can also be constructed from matrix blocks. This is an alias for block_diagonal_matrix.

AbstractAlgebra.diagonal_matrixMethod
diagonal_matrix(V::Vector{T}) where {T <: MatElem}
diagonal_matrix(R::NCRing, V::Vector{<:MatElem})
diagonal_matrix(x::T, xs::T...) where {T <: MatElem}

Return the block diagonal matrix whose diagonal blocks are the given matrices.

For the vector forms, the diagonal blocks are the elements of V. For the vararg form, the diagonal blocks are x, xs....

If the ring R is given, the entries of the blocks are coerced into R.

These constructors use the corresponding block_diagonal_matrix functionality.

Examples

julia> A = matrix(ZZ, [1 2; 3 4])
[1   2]
[3   4]

julia> B = matrix(ZZ, [5 6])
[5   6]

julia> diagonal_matrix([A, B])
[1   2   0   0]
[3   4   0   0]
[0   0   5   6]

julia> diagonal_matrix(QQ, [A, B])
[1//1   2//1   0//1   0//1]
[3//1   4//1   0//1   0//1]
[0//1   0//1   5//1   6//1]

julia> diagonal_matrix(B, A)
[5   6   0   0]
[0   0   1   2]
[0   0   3   4]
source

Block diagonal matrix constructors

AbstractAlgebra.block_diagonal_matrixMethod
block_diagonal_matrix(V::Vector{<:MatElem{T}}) where {T <: NCRingElement}

Return the block diagonal matrix whose diagonal blocks are the matrices in V.

The vector V must be non-empty, since otherwise the base ring cannot be inferred.

Examples

julia> M = matrix(ZZ, [1 2; 3 4])
[1   2]
[3   4]

julia> N = matrix(ZZ, [4 5 6; 7 8 9])
[4   5   6]
[7   8   9]

julia> block_diagonal_matrix([M, N])
[1   2   0   0   0]
[3   4   0   0   0]
[0   0   4   5   6]
[0   0   7   8   9]
source
AbstractAlgebra.block_diagonal_matrixMethod
block_diagonal_matrix(R::NCRing, V::Vector{<:Matrix{T}}) where {T <: NCRingElement}

Return the block diagonal matrix over the ring R whose diagonal blocks are the matrices in V.

The entries of the blocks are coerced into R. If V is empty, the $0 \times 0$ zero matrix over R is returned.

Examples

julia> block_diagonal_matrix(ZZ, [[1 2; 3 4], [4 5 6; 7 8 9]])
[1   2   0   0   0]
[3   4   0   0   0]
[0   0   4   5   6]
[0   0   7   8   9]
source

Triangular matrices

AbstractAlgebra.lower_triangular_matrixMethod
lower_triangular_matrix(L::AbstractVector{T}) where {T <: NCRingElement}

Return the $n \times n$ lower triangular matrix whose entries on and below the main diagonal are given by the elements of L. The entries are filled row by row.

The size $n$ is determined by the condition that L has length $n(n + 1)/2$. An exception is thrown if no such integer $n$ exists.

Examples

julia> lower_triangular_matrix([1, 2, 3])
[1   0]
[2   3]
source
AbstractAlgebra.upper_triangular_matrixMethod
upper_triangular_matrix(L::AbstractVector{T}) where {T <: NCRingElement}

Return the $n \times n$ upper triangular matrix whose entries on and below the main diagonal are given by the elements of L. The entries are filled row by row.

The size $n$ is determined by the condition that L has length $n(n + 1)/2$. An exception is thrown if no such integer $n$ exists.

Examples

julia> upper_triangular_matrix([1, 2, 3])
[1   2]
[0   3]
source
AbstractAlgebra.strictly_lower_triangular_matrixMethod
strictly_lower_triangular_matrix(L::AbstractVector{T}) where {T <: NCRingElement}

Return the $n \times n$ strictly lower triangular matrix whose entries below the main diagonal are given by the elements of L. The entries are filled row by row.

The size $n$ is determined by the condition that L has length $n(n - 1)/2$. An exception is thrown if no such integer $n$ exists.

Examples

julia> strictly_lower_triangular_matrix([1, 2, 3])
[0   0   0]
[1   0   0]
[2   3   0]
source
AbstractAlgebra.strictly_upper_triangular_matrixMethod
strictly_upper_triangular_matrix(L::AbstractVector{T}) where {T <: NCRingElement}

Return the $n \times n$ strictly upper triangular matrix whose entries above the main diagonal are given by the elements of L. The entries are filled row by row.

The size $n$ is determined by the condition that L has length $n(n - 1)/2$. An exception is thrown if no such integer $n$ exists.

Examples

julia> strictly_upper_triangular_matrix([1, 2, 3])
[0   1   2]
[0   0   3]
[0   0   0]
source