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