Skip to content

Commit

Permalink
LinearAlgebra: Add bareiss det for BigInt Matrices (#40128) :: Take 2 (
Browse files Browse the repository at this point in the history
  • Loading branch information
Pramodh Gopalan V authored and johanmon committed Jul 5, 2021
1 parent c3110ee commit 3e1a95b
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 0 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ Standard library changes
* The shape of an `UpperHessenberg` matrix is preserved under certain arithmetic operations, e.g. when multiplying or dividing by an `UpperTriangular` matrix. ([#40039])
* `cis(A)` now supports matrix arguments ([#40194]).
* `dot` now supports `UniformScaling` with `AbstractMatrix` ([#40250]).
* `det(M::AbstractMatrix{BigInt})` now calls `det_bareiss(M)`, which uses the [Bareiss](https://en.wikipedia.org/wiki/Bareiss_algorithm) algorithm to calculate precise values.([#40868]).

#### Markdown

Expand Down
52 changes: 52 additions & 0 deletions stdlib/LinearAlgebra/src/generic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1558,6 +1558,9 @@ function det(A::AbstractMatrix{T}) where T
end
det(x::Number) = x

# Resolve Issue #40128
det(A::AbstractMatrix{BigInt}) = det_bareiss(A)

"""
logabsdet(M)
Expand Down Expand Up @@ -1620,6 +1623,55 @@ logdet(A) = log(det(A))

const NumberArray{T<:Number} = AbstractArray{T}

exactdiv(a, b) = a/b
exactdiv(a::Integer, b::Integer) = div(a, b)

"""
det_bareiss!(M)
Calculates the determinant of a matrix using the
[Bareiss Algorithm](https://en.wikipedia.org/wiki/Bareiss_algorithm) using
inplace operations.
# Examples
```jldoctest
julia> M = [1 0; 2 2]
2×2 Matrix{Int64}:
1 0
2 2
julia> LinearAlgebra.det_bareiss!(M)
2
```
"""
function det_bareiss!(M)
n = checksquare(M)
sign, prev = Int8(1), one(eltype(M))
for i in 1:n-1
if iszero(M[i,i]) # swap with another col to make nonzero
swapto = findfirst(!iszero, @view M[i,i+1:end])
isnothing(swapto) && return zero(prev)
sign = -sign
Base.swapcols!(M, i, i + swapto)
end
for k in i+1:n, j in i+1:n
M[j,k] = exactdiv(M[j,k]*M[i,i] - M[j,i]*M[i,k], prev)
end
prev = M[i,i]
end
return sign * M[end,end]
end
"""
LinearAlgebra.det_bareiss(M)
Calculates the determinant of a matrix using the
[Bareiss Algorithm](https://en.wikipedia.org/wiki/Bareiss_algorithm).
Also refer to [`det_bareiss!`](@ref).
"""
det_bareiss(M) = det_bareiss!(copy(M))



"""
promote_leaf_eltypes(itr)
Expand Down
5 changes: 5 additions & 0 deletions stdlib/LinearAlgebra/test/generic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,11 @@ end
@test [[1,2, [3,4]], 5.0, [6im, [7.0, 8.0]]] [[1,2, [3,4]], 5.0, [6im, [7.0, 8.0]]]
end

@testset "Issue 40128" begin
@test det(BigInt[9 1 8 0; 0 0 8 7; 7 6 8 3; 2 9 7 7])::BigInt == -1
@test det(BigInt[1 big(2)^65+1; 3 4])::BigInt == (4 - 3*(big(2)^65+1))
end

# Minimal modulo number type - but not subtyping Number
struct ModInt{n}
k
Expand Down

0 comments on commit 3e1a95b

Please sign in to comment.