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

Remove BangBang.possible #579

Merged
merged 11 commits into from
Apr 18, 2024
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "DynamicPPL"
uuid = "366bfd00-2699-11ea-058f-f148b4cae6d8"
version = "0.24.7"
version = "0.24.8"

[deps]
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
Expand Down Expand Up @@ -28,7 +28,7 @@ ZygoteRules = "700de1a5-db45-46bc-99cf-38207098b444"
ADTypes = "0.2"
AbstractMCMC = "5"
AbstractPPL = "0.7"
BangBang = "0.3"
BangBang = "0.4.1"
Bijectors = "0.13"
ChainRulesCore = "1"
Compat = "4"
Expand Down
2 changes: 0 additions & 2 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
LogDensityProblems = "6fdf6af0-433a-55f7-b3ed-c6c6e0b8df7c"
MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d"
MLUtils = "f1d291b0-491e-4a28-83b9-f70985020b54"
Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46"
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"

Expand All @@ -16,6 +15,5 @@ Documenter = "1"
FillArrays = "0.13, 1"
LogDensityProblems = "2"
MCMCChains = "5, 6"
MLUtils = "0.3, 0.4"
Setfield = "0.7.1, 0.8, 1"
StableRNGs = "1"
20 changes: 16 additions & 4 deletions docs/src/tutorials/prob-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,11 @@ To give an example of the probability interface in use, we can use it to estimat
In cross-validation, we split the dataset into several equal parts.
Then, we choose one of these sets to serve as the validation set.
Here, we measure fit using the cross entropy (Bayes loss).[^1]
(For the sake of simplicity, in the following code, we enforce that `nfolds` )
sunxd3 marked this conversation as resolved.
Show resolved Hide resolved

```@example probinterface
using MLUtils

function cross_val(
dataset::AbstractVector{<:Real};
dataset::Vector{<:Real};
nfolds::Int=5,
nsamples::Int=1_000,
rng::Random.AbstractRNG=Random.default_rng(),
Expand All @@ -121,7 +120,20 @@ function cross_val(
model = gdemo(1) | (x=[first(dataset)],)
loss = zero(logjoint(model, rand(rng, model)))

for (train, validation) in kfolds(dataset, nfolds)
# prepare the K-folds
yebai marked this conversation as resolved.
Show resolved Hide resolved
fold_size = div(length(dataset), nfolds)
if length(dataset) % nfolds != 0
sunxd3 marked this conversation as resolved.
Show resolved Hide resolved
error("The number of folds must divide the number of data points.")
end
splits = Vector{Tuple{SubArray, SubArray}}(undef, nfolds)

sunxd3 marked this conversation as resolved.
Show resolved Hide resolved
for i in 1:nfolds
start_idx, end_idx = (i-1)*fold_size + 1, i*fold_size
train_set_indices = [1:start_idx-1; end_idx+1:length(dataset)]
sunxd3 marked this conversation as resolved.
Show resolved Hide resolved
splits[i] = (view(dataset, train_set_indices), view(dataset, start_idx:end_idx))
end

for (train, validation) in splits
# First, we train the model on the training set, i.e., we obtain samples from the posterior.
# For normally-distributed data, the posterior can be computed in closed form.
# For general models, however, typically samples will be generated using MCMC with Turing.
Expand Down
37 changes: 0 additions & 37 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -539,43 +539,6 @@ function remove_parent_lens(vn_parent::VarName{sym}, vn_child::VarName{sym}) whe
return child
end

# HACK: All of these are related to https://github.com/JuliaFolds/BangBang.jl/issues/233
# and https://github.com/JuliaFolds/BangBang.jl/pull/238, https://github.com/JuliaFolds2/BangBang.jl/pull/16.
# This avoids type-instability in `dot_assume` for `SimpleVarInfo`.
# The following code a copy from https://github.com/JuliaFolds2/BangBang.jl/pull/16 authored by torfjelde
# Default implementation for `_setindex!` with `AbstractArray`.
# But this will return `false` even in cases such as
#
# setindex!!([1, 2, 3], [4, 5, 6], :)
#
# because `promote_type(eltype(C), T) <: eltype(C)` is `false`.
# To address this, we specialize on the case where `T<:AbstractArray`.
# In addition, we need to support a wide range of indexing behaviors:
#
# We also need to ensure that the dimensionality of the index is
# valid, i.e. that we're not returning `true` in cases such as
#
# setindex!!([1, 2, 3], [4, 5], 1)
#
# which should return `false`.
_index_dimension(::Any) = 0
_index_dimension(::Colon) = 1
_index_dimension(::AbstractVector) = 1
_index_dimension(indices::Tuple) = sum(map(_index_dimension, indices))

function BangBang.possible(
::typeof(BangBang._setindex!), ::C, ::T, indices::Vararg
) where {M,C<:AbstractArray{<:Real},T<:AbstractArray{<:Real,M}}
return BangBang.implements(setindex!, C) &&
promote_type(eltype(C), eltype(T)) <: eltype(C) &&
# This will still return `false` for scenarios such as
#
# setindex!!([1, 2, 3], [4, 5, 6], :, 1)
#
# which are in fact valid. However, this cases are rare.
(_index_dimension(indices) == M || _index_dimension(indices) == 1)
end

# HACK(torfjelde): This makes it so it works on iterators, etc. by default.
# TODO(torfjelde): Do better.
"""
Expand Down
115 changes: 0 additions & 115 deletions test/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,119 +48,4 @@
x = rand(dist)
@test vectorize(dist, x) == vec(x.UL)
end

@testset "BangBang.possible" begin
using DynamicPPL.BangBang: setindex!!

# Some utility methods for testing `setindex!`.
test_linear_index_only(::Tuple, ::AbstractArray) = false
test_linear_index_only(inds::NTuple{1}, ::AbstractArray) = true
test_linear_index_only(inds::NTuple{1}, ::AbstractVector) = false

function replace_colon_with_axis(inds::Tuple, x)
ntuple(length(inds)) do i
inds[i] isa Colon ? axes(x, i) : inds[i]
end
end
function replace_colon_with_vector(inds::Tuple, x)
ntuple(length(inds)) do i
inds[i] isa Colon ? collect(axes(x, i)) : inds[i]
end
end
function replace_colon_with_range(inds::Tuple, x)
ntuple(length(inds)) do i
inds[i] isa Colon ? (1:size(x, i)) : inds[i]
end
end
function replace_colon_with_booleans(inds::Tuple, x)
ntuple(length(inds)) do i
inds[i] isa Colon ? trues(size(x, i)) : inds[i]
end
end

function replace_colon_with_range_linear(inds::NTuple{1}, x::AbstractArray)
return inds[1] isa Colon ? (1:length(x),) : inds
end

@testset begin
@test setindex!!((1, 2, 3), :two, 2) === (1, :two, 3)
@test setindex!!((a=1, b=2, c=3), :two, :b) === (a=1, b=:two, c=3)
@test setindex!!([1, 2, 3], :two, 2) == [1, :two, 3]
@test setindex!!(Dict{Symbol,Int}(:a => 1, :b => 2), 10, :a) ==
Dict(:a => 10, :b => 2)
@test setindex!!(Dict{Symbol,Int}(:a => 1, :b => 2), 3, "c") ==
Dict(:a => 1, :b => 2, "c" => 3)
end

@testset "mutation" begin
@testset "without type expansion" begin
for args in [([1, 2, 3], 20, 2), (Dict(:a => 1, :b => 2), 10, :a)]
@test setindex!!(args...) === args[1]
end
end

@testset "with type expansion" begin
@test setindex!!([1, 2, 3], [4, 5], 1) == [[4, 5], 2, 3]
@test setindex!!([1, 2, 3], [4, 5, 6], :, 1) == [4, 5, 6]
end
end

@testset "slices" begin
@testset "$(typeof(x)) with $(src_idx)" for (x, src_idx) in [
# Vector.
(randn(2), (:,)),
(randn(2), (1:2,)),
# Matrix.
(randn(2, 3), (:,)),
(randn(2, 3), (:, 1)),
(randn(2, 3), (:, 1:3)),
# 3D array.
(randn(2, 3, 4), (:, 1, :)),
(randn(2, 3, 4), (:, 1:3, :)),
(randn(2, 3, 4), (1, 1:3, :)),
]
# Base case.
@test @inferred(setindex!!(x, x[src_idx...], src_idx...)) === x

# If we have `Colon` in the index, we replace this with other equivalent indices.
if any(Base.Fix2(isa, Colon), src_idx)
if test_linear_index_only(src_idx, x)
# With range instead of `Colon`.
@test @inferred(
setindex!!(
x,
x[src_idx...],
replace_colon_with_range_linear(src_idx, x)...,
)
) === x
else
# With axis instead of `Colon`.
@test @inferred(
setindex!!(
x, x[src_idx...], replace_colon_with_axis(src_idx, x)...
)
) === x
# With range instead of `Colon`.
@test @inferred(
setindex!!(
x, x[src_idx...], replace_colon_with_range(src_idx, x)...
)
) === x
# With vectors instead of `Colon`.
@test @inferred(
setindex!!(
x, x[src_idx...], replace_colon_with_vector(src_idx, x)...
)
) === x
# With boolean index instead of `Colon`.
@test @inferred(
setindex!!(
x, x[src_idx...], replace_colon_with_booleans(src_idx, x)...
)
) === x
end
end
end
end
end
end
Loading