Sparse vectors and BigFloat Heisenbug

I have in some weird side effect with structs of sparse vectors of BigFloats, where operating on a copy of the sum seems to change the struct itself.

In spirit, the structure of the code looks like below. After a copying step from y to x, the value of active_set itself.

** NoTe ** this example sadly does not reproduce the bug (yet), I haven’t managed to extract what is going on.


using SparseArrays
using LinearAlgebra

n = 10_000
a1_indices = Int[]
a2_indices = [160, 162, 166, 264, 381, 594, 629, 640, 646, 651, 656, 696, 804, 851, 1021, 1040, 1091, 1176, 1185, 1210, 1377, 1424, 1603, 1607, 1770, 1826, 2087, 2156, 2292, 2371, 2465, 2484, 2521, 2556, 2605, 2658, 2741, 2743, 3204, 3216, 3423, 3478, 3666, 3740, 3748, 3758, 3770, 3815, 4032, 4177, 4206, 4225, 4559, 4564, 4597, 4723, 4816, 4840, 4848, 5221, 5530, 5561, 5573, 5877, 6046, 6066, 6241, 6243, 6246, 6255, 6378, 6468, 6595, 6679, 6761, 6955, 6979, 7006, 7029, 7302, 7373, 7522, 7562, 7591, 7890, 7940, 8009, 8025, 8037, 8249, 8716, 8778, 8943, 9077, 9221, 9685, 9721, 9813, 9835, 9857]

a1_vals = BigFloat[]
a2_vals = BigFloat[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]

active_set = (
    weights = [0.999755859375, 0.000244140625],
    atoms = [
        SparseVector(n, a1_indices, a1_vals),
        SparseVector(n, a2_indices, a2_vals),
    ]
)

function compute_active_set_iterate(active_set)
    return sum(λi * ai for (λi, ai) in zip(active_set.weights, active_set.atoms))
end

@show norm(compute_active_set_iterate(active_set))

x = spzeros(BigFloat, length(active_set.atoms[1]))

function do_stuff!(x, active_set)
    x .= 0
    SparseArrays.dropzeros!(x)
    y = compute_active_set_iterate(active_set)
    @info "$(norm(compute_active_set_iterate(active_set)))"
    @info "$(norm(y))"
    # HERE, the two values above are identical
    x .= y
    # NOW, the result below is different
    @info "$(norm(compute_active_set_iterate(active_set)))"
    # the two displayed norms diverge 
    return x
end

x = compute_active_set_iterate(active_set)

for _ in 1:5
    x = if rand(Bool)
        do_stuff!(x, active_set)
    else
        compute_active_set_iterate(active_set)
    end
    @info "$(norm(compute_active_set_iterate(active_set)))"
    @info "$(norm(x))"
end

What version? I can’t reproduce this on 1.5.3.

No the example above does not reproduce the problem, I will add an edit to make it explicit. The bug is in the same spirit, but happens several functions call deep in a package, I haven’t managed to pull off a reproducible example yet.

Maybe I missed it but what is the effect of the bug in you original code? Do you get an error message? Or just a wrong result?

1 Like

Sorry indeed, I was so deep down in this thing I forgot to specify what happened, I added some comments to show what happened. Basically the two values returned by compute_active_set_iterate(active_set) before and after assigning to x are different