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

Conversion Error with Categorical Distribution in ExponentialFamily.jl #202

Closed
Nimrais opened this issue Jul 23, 2024 · 8 comments · Fixed by #203
Closed

Conversion Error with Categorical Distribution in ExponentialFamily.jl #202

Nimrais opened this issue Jul 23, 2024 · 8 comments · Fixed by #203
Labels
bug Something isn't working

Comments

@Nimrais
Copy link
Member

Nimrais commented Jul 23, 2024

When attempting to create and manipulate an ExponentialFamilyDistribution with a Categorical distribution with natural parameters container ArrayPartition. The code fails during conversion. I think it's because NaturalToMean, but maybe it's supposed to be so however such behavior is quite inconvenient.

using RecursiveArrayTools
using ExponentialFamily
using Distributions

nat_params = ArrayPartition([1, 2], [3])
ef  = ExponentialFamilyDistribution(
    Categorical, nat_params, 3, nothing
)

@show ExponentialFamily.isproper(ef)
# true
@show convert(Distribution, ef)

Error

ERROR: MethodError: no method matching (::MeanToNatural{…})(::ExponentialFamilyDistribution{…})

Closest candidates are:
  (::MeanToNatural)(::Any, ::Nothing)
   @ ExponentialFamily ~/repos/ReactiveBayes/ExponentialFamily.jl/src/exponential_family.jl:27
  (::MeanToNatural{T})(::AbstractVector, ::Nothing) where T<:Distribution
   @ ExponentialFamily ~/repos/ReactiveBayes/ExponentialFamily.jl/src/exponential_family.jl:410
  (::MeanToNatural{Categorical{P} where P<:Real})(::Tuple{Any}, ::Any)
   @ ExponentialFamily ~/repos/ReactiveBayes/ExponentialFamily.jl/src/distributions/categorical.jl:48
  ...

Stacktrace:
 [1] macro expansion
   @ show.jl:1181 [inlined]
 [2] top-level scope
   @ ~/repos/ReactiveBayes/ExponentialFamily.jl/categorical_bug.jl:11
Some type information was truncated. Use `show(err)` to see complete types.

ERROR: MethodError: Cannot `convert` an object of type Vector{Float64} to an object of type ArrayPartition{Float64, Tuple{Vector{Float64}, Vector{Float64}}}

Closest candidates are:
  convert(::Type{ArrayPartition{T, S}}, ::ArrayPartition{<:Any, <:Tuple{Vararg{Any, N}}}) where {N, T, S<:Tuple{Vararg{Any, N}}}
   @ RecursiveArrayTools ~/.julia/packages/RecursiveArrayTools/K1bCr/src/array_partition.jl:543
  convert(::Type{T}, ::T) where T
   @ Base Base.jl:84
  convert(::Type{T}, ::T) where T<:AbstractArray
   @ Base abstractarray.jl:16
  ...

Stacktrace:
  [1] Categorical{Float64, ArrayPartition{…}}(xs::Base.OneTo{Int64}, ps::ArrayPartition{Float64, Tuple{…}}; check_args::Bool)
    @ Distributions ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/discretenonparametric.jl:34
  [2] DiscreteNonParametric
    @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/discretenonparametric.jl:24 [inlined]
  [3] #_#115
    @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:31 [inlined]
  [4] DiscreteNonParametric
    @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:29 [inlined]
  [5] DiscreteNonParametric
    @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:34 [inlined]
  [6] convert(::Type{…}, ef::ExponentialFamilyDistribution{…})
    @ ExponentialFamily ~/repos/ReactiveBayes/ExponentialFamily.jl/src/exponential_family.jl:876
  [7] convert
    @ ~/repos/ReactiveBayes/ExponentialFamily.jl/src/exponential_family.jl:849 [inlined]
  [8] mean(ef::ExponentialFamilyDistribution{Categorical{P} where P<:Real, ArrayPartition{Int64, Tuple{…}}, Int64, Nothing})
    @ ExponentialFamily ~/repos/ReactiveBayes/ExponentialFamily.jl/src/exponential_family.jl:910
  [9] macro expansion
    @ show.jl:1181 [inlined]
 [10] top-level scope
    @ ~/repos/ReactiveBayes/ExponentialFamily.jl/categorical_bug.jl:11
Some type information was truncated. Use `show(err)` to see complete types.

ExponentialFamily.isproper(ef) = true
ERROR: MethodError: Cannot `convert` an object of type Vector{Float64} to an object of type ArrayPartition{Float64, Tuple{Vector{Float64}, Vector{Float64}}}

Closest candidates are:
  convert(::Type{ArrayPartition{T, S}}, ::ArrayPartition{<:Any, <:Tuple{Vararg{Any, N}}}) where {N, T, S<:Tuple{Vararg{Any, N}}}
   @ RecursiveArrayTools ~/.julia/packages/RecursiveArrayTools/K1bCr/src/array_partition.jl:543
  convert(::Type{T}, ::T) where T
   @ Base Base.jl:84
  convert(::Type{T}, ::T) where T<:AbstractArray
   @ Base abstractarray.jl:16
  ...

Stacktrace:
  [1] Categorical{Float64, ArrayPartition{…}}(xs::Base.OneTo{Int64}, ps::ArrayPartition{Float64, Tuple{…}}; check_args::Bool)
    @ Distributions ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/discretenonparametric.jl:34
  [2] DiscreteNonParametric
    @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/discretenonparametric.jl:24 [inlined]
  [3] #_#115
    @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:31 [inlined]
  [4] DiscreteNonParametric
    @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:29 [inlined]
  [5] DiscreteNonParametric
    @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:34 [inlined]
  [6] convert(::Type{…}, ef::ExponentialFamilyDistribution{…})
    @ ExponentialFamily ~/repos/ReactiveBayes/ExponentialFamily.jl/src/exponential_family.jl:876
  [7] convert
    @ ~/repos/ReactiveBayes/ExponentialFamily.jl/src/exponential_family.jl:849 [inlined]
  [8] mean(ef::ExponentialFamilyDistribution{Categorical{P} where P<:Real, ArrayPartition{Int64, Tuple{…}}, Int64, Nothing})
    @ ExponentialFamily ~/repos/ReactiveBayes/ExponentialFamily.jl/src/exponential_family.jl:910
  [9] macro expansion
    @ show.jl:1181 [inlined]
 [10] top-level scope
    @ ~/repos/ReactiveBayes/ExponentialFamily.jl/categorical_bug.jl:11
Some type information was truncated. Use `show(err)` to see complete types.

ExponentialFamily.isproper(ef) = true
ERROR: MethodError: Cannot `convert` an object of type Vector{Float64} to an object of type ArrayPartition{Float64, Tuple{Vector{Float64}, Vector{Float64}}}

Closest candidates are:
  convert(::Type{ArrayPartition{T, S}}, ::ArrayPartition{<:Any, <:Tuple{Vararg{Any, N}}}) where {N, T, S<:Tuple{Vararg{Any, N}}}
   @ RecursiveArrayTools ~/.julia/packages/RecursiveArrayTools/K1bCr/src/array_partition.jl:543
  convert(::Type{T}, ::T) where T
   @ Base Base.jl:84
  convert(::Type{T}, ::T) where T<:AbstractArray
   @ Base abstractarray.jl:16
  ...

Stacktrace:
  [1] Categorical{Float64, ArrayPartition{…}}(xs::Base.OneTo{Int64}, ps::ArrayPartition{Float64, Tuple{…}}; check_args::Bool)
    @ Distributions ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/discretenonparametric.jl:34
  [2] DiscreteNonParametric
    @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/discretenonparametric.jl:24 [inlined]
  [3] #_#115
    @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:31 [inlined]
  [4] DiscreteNonParametric
    @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:29 [inlined]
  [5] DiscreteNonParametric
    @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:34 [inlined]
  [6] convert(::Type{…}, ef::ExponentialFamilyDistribution{…})
    @ ExponentialFamily ~/repos/ReactiveBayes/ExponentialFamily.jl/src/exponential_family.jl:876
  [7] convert
    @ ~/repos/ReactiveBayes/ExponentialFamily.jl/src/exponential_family.jl:849 [inlined]
  [8] mean(ef::ExponentialFamilyDistribution{Categorical{P} where P<:Real, ArrayPartition{Int64, Tuple{…}}, Int64, Nothing})
    @ ExponentialFamily ~/repos/ReactiveBayes/ExponentialFamily.jl/src/exponential_family.jl:910
  [9] macro expansion
    @ show.jl:1181 [inlined]
 [10] top-level scope
    @ ~/repos/ReactiveBayes/ExponentialFamily.jl/categorical_bug.jl:11
Some type information was truncated. Use `show(err)` to see complete types.

ExponentialFamily.isproper(ef) = true
ERROR: MethodError: Cannot `convert` an object of type Vector{Float64} to an object of type ArrayPartition{Float64, Tuple{Vector{Float64}, Vector{Float64}}}

Closest candidates are:
  convert(::Type{ArrayPartition{T, S}}, ::ArrayPartition{<:Any, <:Tuple{Vararg{Any, N}}}) where {N, T, S<:Tuple{Vararg{Any, N}}}
   @ RecursiveArrayTools ~/.julia/packages/RecursiveArrayTools/K1bCr/src/array_partition.jl:543
  convert(::Type{T}, ::T) where T
   @ Base Base.jl:84
  convert(::Type{T}, ::T) where T<:AbstractArray
   @ Base abstractarray.jl:16
  ...

Stacktrace:
 [1] Categorical{Float64, ArrayPartition{…}}(xs::Base.OneTo{Int64}, ps::ArrayPartition{Float64, Tuple{…}}; check_args::Bool)
   @ Distributions ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/discretenonparametric.jl:34
 [2] DiscreteNonParametric
   @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/discretenonparametric.jl:24 [inlined]
 [3] #_#115
   @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:31 [inlined]
 [4] DiscreteNonParametric
   @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:29 [inlined]
 [5] DiscreteNonParametric
   @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:34 [inlined]
 [6] convert(::Type{…}, ef::ExponentialFamilyDistribution{…})
   @ ExponentialFamily ~/repos/ReactiveBayes/ExponentialFamily.jl/src/exponential_family.jl:876
 [7] macro expansion
   @ show.jl:1181 [inlined]
 [8] top-level scope
   @ ~/repos/ReactiveBayes/ExponentialFamily.jl/categorical_bug.jl:11
Some type information was truncated. Use `show(err)` to see complete types.
@Nimrais Nimrais added the bug Something isn't working label Jul 23, 2024
@Nimrais
Copy link
Member Author

Nimrais commented Jul 23, 2024

Or maybe it's rather because convert propagate also the natural parameters container type.

@bvdmitri
Copy link
Member

Good catch @Nimrais ! To me it seems like Categorical from Distributions.jl cannot be constructed from ArrayPartition, can you try that directly with just Distributions.jl?

also I see another bug in your example, the natural parameters are actually not proper (the last parameter must always be zero)

@Nimrais
Copy link
Member Author

Nimrais commented Jul 23, 2024

yeah, sure there more then one bug :)

@bvdmitri
Copy link
Member

The solution would be to write a specialized convert method specifically for Categorical that would call ‘collect’ on the parameters before passing it to the constructor from Distributions.jl

@Nimrais
Copy link
Member Author

Nimrais commented Jul 23, 2024

Yeah seems you are right.

julia> Categorical(ArrayPartition([1/3, 1/3], [1/3]))
ERROR: MethodError: Cannot `convert` an object of type Vector{Float64} to an object of type ArrayPartition{Float64, Tuple{Vector{Float64}, Vector{Float64}}}

Closest candidates are:
  convert(::Type{ArrayPartition{T, S}}, ::ArrayPartition{<:Any, <:Tuple{Vararg{Any, N}}}) where {N, T, S<:Tuple{Vararg{Any, N}}}
   @ RecursiveArrayTools ~/.julia/packages/RecursiveArrayTools/K1bCr/src/array_partition.jl:543
  convert(::Type{T}, ::T) where T
   @ Base Base.jl:84
  convert(::Type{T}, ::T) where T<:AbstractArray
   @ Base abstractarray.jl:16
  ...

Stacktrace:
 [1] Categorical{Float64, ArrayPartition{…}}(xs::Base.OneTo{Int64}, ps::ArrayPartition{Float64, Tuple{…}}; check_args::Bool)
   @ Distributions ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/discretenonparametric.jl:34
 [2] DiscreteNonParametric
   @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/discretenonparametric.jl:24 [inlined]
 [3] #_#115
   @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:31 [inlined]
 [4] DiscreteNonParametric
   @ ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:29 [inlined]
 [5] (Categorical{P} where P<:Real)(p::ArrayPartition{Float64, Tuple{Vector{Float64}, Vector{Float64}}})
   @ Distributions ~/.julia/packages/Distributions/ji8PW/src/univariate/discrete/categorical.jl:34
 [6] top-level scope
   @ REPL[1]:1
Some type information was truncated. Use `show(err)` to see complete types.

@Nimrais
Copy link
Member Author

Nimrais commented Jul 23, 2024

I think we can also open a bug in Distributions.jl because it seems strange that one can not create a distribution with an ArrayPartition parameters.

@Nimrais
Copy link
Member Author

Nimrais commented Jul 23, 2024

I have opened an issue there JuliaStats/Distributions.jl#1878

@Nimrais
Copy link
Member Author

Nimrais commented Jul 23, 2024

The solution would be to write a specialized convert method specifically for Categorical that would call ‘collect’ on the parameters before passing it to the constructor from Distributions.jl

Yeah we can do it, and once Distributions.jl will start to support ArrayPartition we would be able to remove it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants