Compiler doesn't know the type of real.(vec) in compile time

How to make the cc function type stable?

function cc(
  model::Type{<:CepstralCoeffModel},
  tseries::AbstractVector,
  p::Integer,
  n::Integer;
  normalize::Bool=false
)
  series = tseries
  normalize && begin
    series = copy(tseries)
    normalizer!(series)
  end
  α = fit_arima(series, p)
  coefs = cepscoef(model, α, p, n)
  return real.(coefs)
end

function cepscoef(::Type{RealCepstral}, series::AbstractVector, p::Integer, n::Int)
  p≥n || ArgumentError("`p` must be equal to or greater than `n` when using `RealCepstral`. \
  Passed $p and $n.") |> throw
  res = series |> fft .|> abs .|> log |> ifft
  return res[1:n]
end

julia> using YFinance
julia> series2019 = get_prices("INTC", startdt="2019-10-29", enddt="2020-01-28")["adjclose"];

julia> @code_warntype cc(RealCepstral, series2019, 5, 5)
MethodInstance for Main.CepstralClustering.cc(::Type{RealCepstral}, ::Vector{Float64}, ::Int64, ::Int64)
  from cc(model::Type{<:Main.CepstralClustering.CepstralCoeffModel}, tseries::AbstractVector, p::Integer, n::Integer; normalize) @ Main.CepstralClustering e:\Julia Forks\TimeSeries-Cepstral-Clustering\src\CepstralClustering.jl:53
Arguments
  #self#::Core.Const(Main.CepstralClustering.cc)
  model::Core.Const(RealCepstral)
  tseries::Vector{Float64}       
  p::Int64
  n::Int64
Body::Any
1 ─ %1 = Main.CepstralClustering.:(var"#cc#4")(false, #self#, model, tseries, p, n)::Any
└──      return %1

GitHub - JuliaDebug/Cthulhu.jl: The slow descent into madness holds the answer

You didn’t provide a reproducer, but maybe try making model a type parameter of the method.

Full code:

using FFTW, ARCHModels
abstract type CepstralCoeffModel end
struct RealCepstral <: CepstralCoeffModel end

function cc(
  model::Type{<:CepstralCoeffModel},
  tseries::AbstractVector,
  p::Integer,
  n::Integer
)
  series = tseries
  normalize && begin
    series = copy(tseries)
    normalizer!(series)
  end
  α = fit_arima(series, p)
  coefs = cepscoef(model, α, p, n)
  return real.(coefs)
end

normalizer!(series::AbstractVector) = series .= (series .- mean(series)) ./ std(series)

function fit_arima(series::AbstractVector, p::Integer)
  model = fit(ARMA{p, 0}, series)
  return model.meanspec.coefs[2:end]
end

function cepscoef(::Type{RealCepstral}, series::AbstractVector, p::Integer, n::Int)
  p≥n || ArgumentError("`p` must be equal to or greater than `n` when using `RealCepstral`. \
  Passed $p and $n.") |> throw
  res = series |> fft .|> abs .|> log |> ifft
  return res[1:n]
end

Sorry for any inconvenience, @nsajko, @cjdoris.
The complete script is provided above.

Thank you for the great advice. I found out there is an internal problem with ARCHModels.jl.

The root of the problem derives from model = fit(ARMA{p, 0}, series) in my code. The Cthulhu shows:

Which is related to this line of code:

According to Cthulhu, another problem arises from here:

Sorry for going off topic, but for cases like the above, there’s the if-construct, which is more idiomatic, and also briefer:

if normalize
    series = copy(tseries)
    normalizer!(series)
end
2 Likes

Oh, come on! Any time!! Thank you so much!!

Yes, you’re right! I barely use begin in my deployed codes. Thank you for your reminder. :rose:

The problem that I mentioned in the original post:

Handled by using type assertions in the definition of the fit_arima function. The former version of the function:

The new version:

function fit_arima(series::AbstractVector{T}, p::Integer) where T
  model = fit(ARMA{p, 0}, series)
  return model.meanspec.coefs[2:end]::Vector{T}
end

And the problem gets solved. Credits belong to my friend, @eliascarv. Thank you so much :rose:

P.S.: The problem with the type instability of the ARCHModels.jl still exists. There are several technical issues with the source code that I will hopefully manage to fix through some PRs.

2 Likes