# Type instability in complex schurfact

**URL:** <https://discourse.julialang.org/t/type-instability-in-complex-schurfact/12566>\
**Category:** Performance\
**Tags:** linearalgebra\
**Created:** [July 21, 2018, 6:06pm UTC](https://discourse.julialang.org/t/type-instability-in-complex-schurfact/12566 "2018-07-21T18:06:40Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![BenjaminBorn](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/benjaminborn/32/4910_2.png) [@BenjaminBorn](https://discourse.julialang.org/u/BenjaminBorn)\
**Post date:** [July 21, 2018, 6:06pm UTC](https://discourse.julialang.org/t/type-instability-in-complex-schurfact/12566/1 "2018-07-21T18:06:40Z")

</div>

Hello everyone,

I’m trying to use a complex Schur decomposition and retrieve the generalized eigenvalues. A very much simplified example is here:

```julia
const A = complex(randn(10,10))
const B = complex(randn(10,10))

function schur_test(A, B)
    F = schurfact(A, B)
    gen_ev = F[:values]
    return gen_ev
end

gen_ev = schur_test(A, B)

```

However, the type of `F[:values]` can’t be inferred.

```julia
@code_warntype schur_test(A, B)

Variables:
  #self# <optimized out>
  A::Array{Complex{Float64},2}
  B::Array{Complex{Float64},2}
  F::Base.LinAlg.GeneralizedSchur{Complex{Float64},Array{Complex{Float64},2}}
  gen_ev::Any

Body:
  begin
      $(Expr(:inbounds, false))
      # meta: location linalg/schur.jl schurfact 197
      SSAValue(1) = $(Expr(:foreigncall, :(:jl_array_copy), Ref{Array{Complex{Float64},2}}, svec(Any), :(A), 0))
      SSAValue(0) = $(Expr(:foreigncall, :(:jl_array_copy), Ref{Array{Complex{Float64},2}}, svec(Any), :(B), 0))
      # meta: location linalg/schur.jl schurfact! 184
      SSAValue(2) = $(Expr(:invoke, MethodInstance for gges!(::Char, ::Char, ::Array{Complex{Float64},2}, ::Array{Complex{Float64},2}), :($(QuoteNode(Base.LinAlg.LAPACK.gges!))), 'V', 'V', SSAValue(1), SSAValue(0)))
      # meta: pop location
      # meta: pop location
      $(Expr(:inbounds, :pop))
      F::Base.LinAlg.GeneralizedSchur{Complex{Float64},Array{Complex{Float64},2}} = $(Expr(:new, Base.LinAlg.GeneralizedSchur{Complex{Float64},Array{Complex{Float64},2}},:((Core.getfield)(SSAValue(2), 1)::Array{Complex{Float64},2}), :((Core.getfield)(SSAValue(2), 2)::Array{Complex{Float64},2}), :((Core.getfield)(SSAValue(2), 3)::Array{Complex{Float64},1}), :((Core.getfield)(SSAValue(2), 4)::Array{Complex{Float64},1}), :((Core.getfield)(SSAValue(2), 5)::Array{Complex{Float64},2}), :((Core.getfield)(SSAValue(2), 6)::Array{Complex{Float64},2}))) # line 145:
      gen_ev::Any = $(Expr(:invoke, MethodInstance for getindex(::Base.LinAlg.GeneralizedSchur{Complex{Float64},Array{Complex{Float64},2}}, ::Symbol), :(Main.getindex), :(F), :(:values))) # line 146:
      return gen_ev::Any
  end::Any

```

Putting type information on the function arguments or on `gen_ev = Array{Complex{Float64},1}(F[:values])` doesn’t change the fact that `gen_env` and any variables that I want to construct using it are not type stable.

Any hints are very much appreciated.

Thanks, Benjamin

System:

```julia
Julia Version 0.6.4
Commit 9d11f62bcb (2018-07-09 19:09 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin17.7.0)
  CPU: Intel(R) Core(TM) i7-6567U CPU @ 3.30GHz
  WORD_SIZE: 64
  BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell MAX_THREADS=16)
  LAPACK: libopenblas64_
  LIBM: libopenlibm
  LLVM: libLLVM-3.9.1 (ORCJIT, skylake)

```

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [July 21, 2018, 7:00pm UTC](https://discourse.julialang.org/t/type-instability-in-complex-schurfact/12566/2 "2018-07-21T19:00:01Z")

</div>

[https://github.com/JuliaLang/julia/blob/v0.6.4/base/linalg/schur.jl](https://github.com/JuliaLang/julia/blob/v0.6.4/base/linalg/schur.jl)

Basically, in the GeneralizedSchur object, `alpha` is not a concrete type:

```julia
struct GeneralizedSchur{Ty,M<:AbstractMatrix} <: Factorization{Ty}
    S::M
    T::M
    alpha::Vector
    beta::Vector{Ty}
    Q::M
    Z::M
    function GeneralizedSchur{Ty,M}(S::AbstractMatrix{Ty}, T::AbstractMatrix{Ty}, alpha::Vector,
                                    beta::Vector{Ty}, Q::AbstractMatrix{Ty}, Z::AbstractMatrix{Ty}) where {Ty,M}
        new(S, T, alpha, beta, Q, Z)
    end
end

```

and getindex is defined as `F.alpha ./ F.beta`:

```julia
function getindex(F::GeneralizedSchur, d::Symbol)
    if d == :S
        return F.S
    elseif d == :T
        return F.T
    elseif d == :alpha
        return F.alpha
    elseif d == :beta
        return F.beta
    elseif d == :values
        return F.alpha./F.beta
    elseif d == :Q || d == :left
        return F.Q
    elseif d == :Z || d == :right
        return F.Z
    else
        throw(KeyError(d))
    end
end

```

So, you could do something like this:

```julia
function schur_test(A, B)
    F = schurfact(A, B)
    alpha::Vector{complex(promote_type(eltype(A),eltype(B)))} = F.alpha
    return alpha ./ F.beta
end

```

You could simplify the `complex(promote_type(eltype(A),eltype(B))`, but I tried to make it fairly generic.

---

<div class="post-metadata">

**Author:** ![BenjaminBorn](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/benjaminborn/32/4910_2.png) [@BenjaminBorn](https://discourse.julialang.org/u/BenjaminBorn)\
**Post date:** [July 22, 2018, 9:53am UTC](https://discourse.julialang.org/t/type-instability-in-complex-schurfact/12566/3 "2018-07-22T09:53:40Z")

</div>

Thanks a lot Chris. That solved it.

Just a follow up question to understand this. Why is your solution not type stable if I exchange `F.alpha` and `F.beta` by `F[:alpha]` and `F[:beta]`?

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [July 22, 2018, 10:31am UTC](https://discourse.julialang.org/t/type-instability-in-complex-schurfact/12566/4 "2018-07-22T10:31:08Z")

</div>

Because in the “getindex” function I showed above, the return type is dependent on the value of the symbol `d`, not the type.  
I think similar code should be type stable on Julia 0.7, because of better constant propagation.

However, in 0.7 you’ll be forced to use the `F.beta` syntax instead of `F[:beta]`, because it dropped the `getindex` notation, replacing it with getproperty overloading.  
[https://github.com/JuliaLang/julia/blob/master/stdlib/LinearAlgebra/src/schur.jl](https://github.com/JuliaLang/julia/blob/master/stdlib/LinearAlgebra/src/schur.jl)

---

<div class="post-metadata">

**Author:** ![antoine-levitt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/antoine-levitt/32/4008_2.png) [@antoine-levitt](https://discourse.julialang.org/u/antoine-levitt)\
**Post date:** [July 22, 2018, 11:27am UTC](https://discourse.julialang.org/t/type-instability-in-complex-schurfact/12566/5 "2018-07-22T11:27:27Z")

</div>

I think the type instability is intentional in the real case, because you don’t know if the eigenvalues are real or not. In the complex case however, it should be possible to make it type stable. Probably worth opening an issue.
