Skip to content

Violating assumptions about Dual comparisons #609

Closed
@gpeairs

Description

@gpeairs

There are already a few issues talking about #481 (#606, #607) and related problems (#480). I've been running into breakage hinted at in this comment and this workaround where

julia> x, y = 1, ForwardDiff.Dual(1,1);

julia> x < y || x > y || x == y
false

julia> x >= y && x <= y
true

This seems to be an issue for piecewise functions and wrapper types that assume x <= y is equivalent to x == y || x < y.

For example, something like this previously worked:

import ForwardDiff

struct WrappedNumber{T<:Number}
    value::T
end
for op in (:isless, :(==))
    @eval begin
        Base.$op(x::WrappedNumber, y::WrappedNumber) = ($op)(x.value, y.value)
        Base.$op(x::Number, y::WrappedNumber) = ($op)(x, y.value)
        Base.$op(x::WrappedNumber, y::Number) = ($op)(x.value, y)
    end
end
for op in (:*, :+, :-)
    @eval begin
        Base.$op(x::WrappedNumber, y::WrappedNumber) = WrappedNumber(($op)(x.value, y.value))
        Base.$op(x::Number, y::WrappedNumber) = WrappedNumber(($op)(x, y.value))
        Base.$op(x::WrappedNumber, y::Number) = WrappedNumber(($op)(x.value, y))
    end
end

function f_piecewise(x)
    lb = WrappedNumber(0.0)
    ub = WrappedNumber(1.0)
    (lb <= x < ub) && return 0.5*x*x
    x >= ub && return 0.5*ub*ub + (x - ub)
    return 0.0*x
end

function ForwardDiff.derivative(f, x::WrappedNumber{T}) where T
    r = f(WrappedNumber(ForwardDiff.Dual(x.value, one(T))))
    return ForwardDiff.partials(r.value)[1]
end

And now:

julia> ForwardDiff.derivative(f_piecewise, WrappedNumber(0.99))
0.99

julia> ForwardDiff.derivative(f_piecewise, WrappedNumber(1.01))
1.0

julia> ForwardDiff.derivative(f_piecewise, WrappedNumber(1.0))
0.0 # Used to be 1.0

Maybe I'm not supposed to do this. But it's been very convenient, and I suspect this isn't the only case with problems of this kind. Or maybe the issue is just a matter of following through on the changes to == and isequal for other comparisons?

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