TuringLang / TuringLang/DynamicPPL.jl

Reconstructing Cholesky variables from their indices gives wrong result in VNT

Open
#1,262 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

data-structures enhancement
Dominant language
Julia
Stars
286
Forks
41
Avg merge
1d 11h
Merged PRs (30d)
34

Description

julia> using DynamicPPL, Distributions

julia> c = rand(LKJCholesky(3, 0.5))
Cholesky{Float64, Matrix{Float64}}
L factor:
3×3 LinearAlgebra.LowerTriangular{Float64, Matrix{Float64}}:
  1.0        ⋅         ⋅
 -0.71428   0.69986    ⋅
  0.255189  0.911365  0.322942

julia> vnt = @vnt begin
           @template c
           c.L[1, 1] := c.L[1, 1]
           c.L[2, 1] := c.L[2, 1]
           c.L[2, 2] := c.L[2, 2]
           c.L[3, 1] := c.L[3, 1]
           c.L[3, 2] := c.L[3, 2]
           c.L[3, 3] := c.L[3, 3]
       end
VarNamedTuple
└─ c => VarNamedTuple
        └─ L => PartialArray size=(3, 3) data::LinearAlgebra.LowerTriangular{Float64, Matrix{Float64}}
                ├─ (1, 1) => 1.0
                ├─ (2, 1) => -0.7142799536546864
                ├─ (3, 1) => 0.25518913641826435
                ├─ (2, 2) => 0.6998600915947837
                ├─ (3, 2) => 0.9113653464249535
                └─ (3, 3) => 0.3229422703670502

Obviously, this doesn't reconstruct the Cholesky sample c despite us passing the template to it.

When does this pathological situation occur? Easy, it's when trying to load samples back into a VNT from MCMCChains.Chains, since Cholesky samples get broken up in MCMCChains.

(with FlexiChains it doesn't break up the sample so you would get something like this and it's a-ok

julia> vnt2 = @vnt begin
           c := c
       end
VarNamedTuple
└─ c => Cholesky{Float64, Matrix{Float64}}([1.0 5.0e-324 0.0; -0.7142799536546864 0.6998600915947837 0.0; 0.25518913641826435 0.9113653464249535 0.3229422703670502], 'L', 0)

)

Now the above issue doesn't yet cause problems because we have this patch for VNT that calls hasvalue(..., dist) and getvalue(..., dist)

https://github.com/TuringLang/DynamicPPL.jl/blob/fd3d2800ba43023d4bed571f467451d7eae61bb2/src/varnamedtuple.jl#L167-L208

However, it is really just wrong to even create a VNT with the wrong structure. That VNT should never be allowed to exist!!! We do have enough info to re-create the correct form of c because we pass the template in, it's just that we're not using it.

There are two Correct Things to do, either of which will allow us to stop creating these wrong VNTs, and thereby remove these hasvalue / getvalue methods:

  1. Use the template to make a PartialCholesky thing, and then fill it in one element by one element.
  2. Stop using MCMCChains, and once we stop using MCMCChains, just declare this as unsupported.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/varnamedtuple.jl at lines 167-208 and trace how @vnt uses the supplied template when reconstructing Cholesky values from MCMCChains.Chains. Compare the two proposed directions—building a PartialCholesky incrementally or dropping MCMCChains support—and confirm that the resulting VNT preserves the Cholesky structure without the hasvalue/getvalue workaround.

Written by the indexing model from the issue text.

Assessment

Tech stack
julia
Domain
backend
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.