Skip to content

Inconsistent behavior in assignment to sparse matrices of Dual numbers #542

Closed
@moyner

Description

@moyner

Let us say that we have a sparse matrix where the entries are Dual numbers.

using ForwardDiff, SparseArrays
d = ForwardDiff.Dual(1.0, 2.0)
a = sparse([0 d])

Let us define two zero values with different partials. One with zero partials (true zero) and one with non-zero partials (false zero):

# 0, with ∂ = 1
d_false_zero = ForwardDiff.Dual(0.0, 1.0)
# 0, with ∂ = 0
d_true_zero = ForwardDiff.Dual(0.0, 0.0)

If we replace the existing entry at [2], everything is well:

## Insertion into existing element keeps partials
a[2] = d_false_zero
println("Existing element:")
println(a[2].partials == d_false_zero.partials)

This gives the expected output:

Existing element:
true

Now let us try to insert our false zero into the first position, which we know isn't yet stored:

## Insertion into unstored element drops partials
a[1] = d_false_zero
println("Zero element:")
println(a[1].partials == d_false_zero.partials)
Zero element:
false

The partials were lost, due to the iszero check here in SparseArrays: https://github.com/JuliaLang/julia/blob/cb30aa7a089f4d5f1c9f834d96c3788f2e93ebcc/stdlib/SparseArrays/src/sparsematrix.jl#L2652

Some quick and ugly type piracy can fix this, but may have other unintended consequences:

import Base.iszero
Base.iszero(d::ForwardDiff.Dual) = iszero(d.value) && iszero(d.partials)

I'm not sure what the intended behavior should be, since the entry is technically zero, but not a neutral element for addition of Duals.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions