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

complex skew tridiagonal #24

Closed
stevengj opened this issue Aug 9, 2022 · 2 comments
Closed

complex skew tridiagonal #24

stevengj opened this issue Aug 9, 2022 · 2 comments

Comments

@stevengj
Copy link
Member

stevengj commented Aug 9, 2022

Your current SkewHermTridiagonal only stores the lower diagonal ev, but this is only correct for real skew-tridiagonal. For complex skew-tridiagonal matrices, the diagonal may be nonzero (albeit purely imaginary).

To fix this, you need to add an optional field to store the diagonal imaginary parts if T is complex. Something like:

struct SkewHermTridiagonal{T, V<:AbstractVector{T}, Vim<:Union{AbstractVector{<:Real},Nothing}} <: AbstractMatrix{T}
    ev::V                        # subdiagonal
    dvim::Vim               # diagonal imaginary parts (may be nothing if T is real)
    function SkewHermTridiagonal{T, V, Vim}(ev, dvim) where {T, V<:AbstractVector{T}, Vim}
        LA.require_one_based_indexing(ev)
        if Vim !== Nothing
            LA.require_one_based_indexing(dvim)
            eltype(dvim) === real(T) || throw(ArgumentError("mismatch between $(real(T)) and $(eltype(dvim))"))
        end
        new{T, V, Vim}(ev, dvim)
    end
end

# real skew-symmetric case
SkewHermTridiagonal(ev::AbstractVector{T}) where {T<:Real} = SkewHermTridiagonal{T, typeof(ev), Nothing}(ev, nothing)
SkewHermTridiagonal{T}(ev::AbstractVector) where {T<:Real} =
    SkewHermTridiagonal(convert(AbstractVector{T}, ev)::AbstractVector{T})

# complex skew-hermitian case
SkewHermTridiagonal(ev::AbstractVector{Complex{T}}, dvim::AbstractVector{T}) where T = SkewHermTridiagonal{Complex{T}, typeof(ev), typeof(dvim)}(ev, dvim)
SkewHermTridiagonal{Complex{T}}(ev::AbstractVector, dvim::AbstractVector) where T =
    SkewHermTridiagonal(convert(AbstractVector{Complex{T}}, ev)::AbstractVector{Complex{T}}, convert(AbstractVector{T}, dvim)::AbstractVector{T})

and then you would need to specialize getindex and other functions, e.g.

Base.@propagate_inbounds function Base.getindex(A::SkewHermTridiagonal{T}, i::Integer, j::Integer) where T
    @boundscheck checkbounds(A, i, j)
    if i == j + 1
        return @inbounds A.ev[j]
    elseif i + 1 == j
        return @inbounds -A.ev[i]'
    elseif T <: Complex && i == j
        return complex(zero(real(T)), A.dvim[i])
    else
        return zero(T)
    end
end

(Note the compiler will optimize out the T <: Complex check.)

@smataigne
Copy link
Collaborator

I forgot about the imaginary diagonal elements! I will correct this quickly. Thanks a lot!

@smataigne
Copy link
Collaborator

This is fixed. I must just correct the copyeigtype function

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants