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

Should intersect_interval (or hull) return always trv decoration? #624

Closed
lbenet opened this issue Feb 2, 2024 · 7 comments · Fixed by #632
Closed

Should intersect_interval (or hull) return always trv decoration? #624

lbenet opened this issue Feb 2, 2024 · 7 comments · Fixed by #632

Comments

@lbenet
Copy link
Member

lbenet commented Feb 2, 2024

I'd like to open the title of this issue for discussion.

The current implementation, as stated in the docstrings, and following the standard (sect 11.7.1), returns trv as the decoration. (I haven't found the motivation why this is so.) Yet, there are certain cases which I think the trv decoration could be "higher" in the decoration order. The following are examples for which I find "trv" too restrictive.

julia> x = interval(0.5,1)
[0.5, 1.0]_com

# _com should be ok here
julia> intersect_interval(x,x) 
[0.5, 1.0]_trv

julia> hull(x,x) 
[0.5, 1.0]_trv

julia> x = entireinterval()
(-∞, ∞)_dac

# _dac should be ok here
julia> intersect_interval(x,x)
(-∞, ∞)_trv

julia> hull(x,x)
(-∞, ∞)_trv

Actually, the standard (sect 11.5.2) mentions the function "setDec(x, d)" which returns the interval "x" decorated with the decoration "d". Quoting the end of that subsection: "NOTE—Careless use of the setDec function can negate the aims of the decoration system and lead to false conclusions that violate the FTDIA. It is provided for expert users, who might need it, e.g., to decorate the output of functions whose definition involves the intersection and convexHull operations." While we don't have setdec (and I am not proposing to have it!), I propose we should have in our implementation of intersect_interval and hull a mechanism which resembles the implementation of some function, e.g. log (or sqrt). These functions apriori require a check if the interval x is inside the actual domain of this functions. Cleverly, this is not done through a naive intersect_interval evaluation (which otherwise would lower the decoration to trv), but by evaluating if the bareinterval is inside the domain: it it is not, the the decoration is trv (if it is, the decoration is evaluated as the min from the decoration of the original interval and the resulting interval).... truly, very nice!

So, what about having that same check in intersect_interval and hull?

@OlivierHnt
Copy link
Member

OlivierHnt commented Feb 2, 2024

If I recall correctly, @Kolaru also complained about this default trv decoration for IntervalRootFinding.jl.

But if we change it, how do we preserve compliance with the standard? In particular, with the ITF1788 test suite? Cf. https://github.com/JuliaIntervals/IntervalArithmetic.jl/blob/7c46049a7455305991647115328942f0d2331239/test/ITF1788_tests/libieeep1788_set.jl#L15C1-L27C4

The setDec function may be exactly what can solve this issue. Currently one can have a similar behaviour to setDec by using the internal unsafe constructor _unsafe_interval; so we could have

setdecoration(x::Interval, d::Decoration) = _unsafe_interval(bareinterval(x), d, isguaranteed(x))

@Kolaru
Copy link
Collaborator

Kolaru commented Feb 2, 2024

Well yes this trv is a pain.

As I understand it, it means that this interval does not result from the the interval extension of a well behaved function. Which is fair in that case.

I think we could have the more sensible behavior as intersect_interval and have another one (like intersect_interval_trv or intersect_interval_burn_the_standard) for the required behavior. We would be compliant, and still propose our favorite behavior.

@lbenet
Copy link
Member Author

lbenet commented Feb 2, 2024

The setdecoration function seems a resonable addition to me! 👍

@lbenet
Copy link
Member Author

lbenet commented Feb 2, 2024

I fully agree with @Kolaru.

My proposal is having an internal helper funcion at least, say _intersect_bareinterval(bx::BareInterval, by::BareInterval) (only acting on BareIntervals!), where bx is the BareInterval part of the argument x passed to the function (think we are computing log(x)), and by corresponds to the (bareinterval) domain of the function. That function should compute the min decorations attributed to bx and by and check if bx is inside the domain by, returning the bareinterval intersection and the decoration:

function _intersect_bareinterval_nontrv(bx::BareInterval, by::BareInterval)
    bx = intersect_interval(bx, by)
    d = min(decoration(bx), decoration(by))
    d = min(d, felse(isinterior(bx, by), d, trv))
    return bx, d
end

This could allow us to avoid some code which is repeated (changing perhaps the domain) and use it elsewhere without trivializing the results of intersect_interval.

@lbenet
Copy link
Member Author

lbenet commented Feb 2, 2024

One could also return _unsafe_interval(bx, d, isguaranteed(bx))...

@lbenet
Copy link
Member Author

lbenet commented Feb 2, 2024

I think the following is more useful

function _intersect_bareinterval_nontrv(bx::BareInterval, by::BareInterval)
    bx = intersect_interval(bx, by)
    d = decoration(bx)
    d = min(d, felse(isinterior(bx, by), d, trv))
    return _unsafe_interval(bx, d, isguaranteed(bx))
end

@OlivierHnt
Copy link
Member

OlivierHnt commented Feb 3, 2024

Do you mean

function _intersect_bareinterval_nontrv(x::Interval, domain::BareInterval)
    bx = bareinterval(x)
    r = intersect_interval(bx, domain)
    # decoration should not inherit the domain decoration (could be [0, Inf))
    # if `!issubset(bx, domain)`, then `r` is empty and `decoration(r) == trv`
    d = min(decoration(x), decoration(r))
    return _unsafe_interval(r, d, isguaranteed(x))
end

?

I do not think we will be able to refactor code substantially with such an internal function (intersection with the domain and the determination of the decoration is decoupled to avoid intersecting twice).

EDIT: in fact there is an other issue with _intersect_bareinterval_nontrv as sometimes the bounds of the domain (given as a bare interval) are singular points. In this case (e.g. for log), we do need the check isinterior as you did. For other cases (e.g. sqrt), we need the check issubset (see also the code snippet in this comment).

I think we could have the more sensible behavior as intersect_interval and have another one (like intersect_interval_trv or intersect_interval_burn_the_standard) for the required behavior. We would be compliant, and still propose our favorite behavior.

While I am not entirely opposed to this proposal, I find it a bit confusing to have two intersect functions.
I mean intersect_interval_burn_the_standard(x, y) would be the same as setdecoration(intersect_interval(x, y), min(decoration(x), decoration(y))) which to me looks nicer (and is also more general).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants