Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LinearAlgebra: Add bareiss det for BigInt Matrices (#40128) :: Take 2 #40868

Merged
merged 3 commits into from
May 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't put the LinearAlgebra. in the docstring, I think.

Copy link
Contributor Author

@Pramodh-G Pramodh-G May 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change it, butLinearAlgebra.jl contains docstrings like

LinearAlgebra.peakflops()

This is the one example I could find though, should I change this too?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would leave the peakflops case out of this PR.


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