|
1 |
| -function LinearAlgebra.det(M::Matrix{<:AbstractPolynomialLike}) |
2 |
| - m = size(M)[1] |
3 |
| - if m > 2 |
4 |
| - return sum( |
5 |
| - (-1)^(i - 1) * M[i, 1] * LinearAlgebra.det(M[1:end.!=i, 2:end]) for |
6 |
| - i in 1:m |
7 |
| - ) |
8 |
| - elseif m == 2 |
9 |
| - return M[1, 1] * M[2, 2] - M[2, 1] * M[1, 2] |
| 1 | +# Scalar determinant, used for recursive computation of the determinant |
| 2 | +LinearAlgebra.det(p::AbstractPolynomialLike{<:Number}) = p |
| 3 | + |
| 4 | +# Matrix determinant by cofactor expansion, adapted from |
| 5 | +# `LinearAlgebraX.cofactor_det`. |
| 6 | +function det_impl(A::AbstractMatrix{T}) where {T} |
| 7 | + get_elem = let A = A |
| 8 | + (i, j) -> LinearAlgebra.det(A[i, j]) |
| 9 | + end |
| 10 | + r = first(size(A)) |
| 11 | + if 1 < r |
| 12 | + total = LinearAlgebra.det(zero(T)) |
| 13 | + for i in Base.OneTo(r) |
| 14 | + a = get_elem(i, 1) |
| 15 | + if !iszero(a) |
| 16 | + ii = Base.OneTo(r) .!= i |
| 17 | + jj = 2:r |
| 18 | + B = A[ii, jj] |
| 19 | + x = det_impl(B) |
| 20 | + x = MA.operate!!(*, x, a) |
| 21 | + if iseven(i) |
| 22 | + x = MA.operate!!(-, x) |
| 23 | + end |
| 24 | + total = MA.operate!!(+, total, x) |
| 25 | + end |
| 26 | + end |
| 27 | + total |
| 28 | + elseif isone(r) |
| 29 | + MA.copy_if_mutable(get_elem(1, 1)) |
| 30 | + else |
| 31 | + error("unexpected") |
| 32 | + end |
| 33 | +end |
| 34 | + |
| 35 | +collect_if_not_already_matrix(m::Matrix) = m |
| 36 | +collect_if_not_already_matrix(m::AbstractMatrix) = collect(m) |
| 37 | + |
| 38 | +function det_impl_outer(m::AbstractMatrix{T}) where {T} |
| 39 | + if 0 < LinearAlgebra.checksquare(m) |
| 40 | + det_impl(collect_if_not_already_matrix(m)) |
10 | 41 | else
|
11 |
| - return M[1, 1] |
| 42 | + LinearAlgebra.det(one(T)) |
12 | 43 | end
|
13 | 44 | end
|
| 45 | + |
| 46 | +# Determinants of narrow integer type: `LinearAlgebra` seems to |
| 47 | +# promote these to `Float64` to prevent them from overflowing. We |
| 48 | +# instead promote to `BigInt` to keep things exact. In the case of |
| 49 | +# `Bool` we also need to promote for type stability. |
| 50 | + |
| 51 | +const NarrowIntegerTypes = |
| 52 | + Union{Bool,UInt8,Int8,UInt16,Int16,UInt32,Int32,UInt64,Int64,UInt128,Int128} |
| 53 | + |
| 54 | +const NarrowIntegerPolynomialLike = |
| 55 | + AbstractPolynomialLike{T} where {T<:NarrowIntegerTypes} |
| 56 | + |
| 57 | +promote_if_narrow(m::AbstractMatrix{<:AbstractPolynomialLike}) = m |
| 58 | + |
| 59 | +function promote_if_narrow(m::AbstractMatrix{<:NarrowIntegerPolynomialLike}) |
| 60 | + return map((p -> polynomial(p, BigInt)), m) |
| 61 | +end |
| 62 | + |
| 63 | +# For type stability, we want to promote termlikes to polynomiallikes |
| 64 | +# before attempting to calculate the determinant. |
| 65 | +promote_if_termlike(m::AbstractMatrix{<:AbstractPolynomialLike}) = m |
| 66 | +promote_if_termlike(m::AbstractMatrix{<:AbstractTermLike}) = map(polynomial, m) |
| 67 | + |
| 68 | +promote_if_necessary(m) = promote_if_termlike(promote_if_narrow(m)) |
| 69 | + |
| 70 | +function LinearAlgebra.det(m::AbstractMatrix{<:AbstractPolynomialLike}) |
| 71 | + return det_impl_outer(promote_if_necessary(m)) |
| 72 | +end |
0 commit comments