JuliaApproximation / DomainSets.jl

A Julia package for describing domains as continuous sets of elements
MIT License
72 stars 12 forks source link

add setdiff(::Interval, ::AbstractVector) #85

Closed dlfivefifty closed 5 months ago

dlfivefifty commented 3 years ago
julia> ((1..2) \ 1.5)
(1.0..1.5 (closed–open)) ∪ (1.5..2.0 (open–closed))

julia> ((1..2) \ [1.5])
(1.0..2.0) \ [1.5]
daanhb commented 3 years ago

We could do:

setdiffdomain(d1::Interval, d2::AbstractVector) =
    isempty(d2) ? d1 : setdiffdomain(d1 \ first(d2), d2[2:end])

But that is going to be horribly type-unsafe, and the complexity of the result depends on the length of the vector.

It would work though:

julia> (0.0..10.0) \ (2:6)
(0.0..2.0 (closed–open)) ∪ D₁

D₁ = (2.0..3.0 (open)) ∪ ((3.0..4.0 (open)) ∪ D₂)
D₂ = (4.0..5.0 (open)) ∪ ((5.0..6.0 (open)) ∪ (6.0..10.0 (open–closed)))

julia> typeof(ans)
UnionDomain{Float64, Tuple{Interval{:closed, :open, Float64}, UnionDomain{Float64, Tuple{OpenInterval{Float64}, UnionDomain{Float64, Tuple{OpenInterval{Float64}, UnionDomain{Float64, Tuple{OpenInterval{Float64}, UnionDomain{Float64, Tuple{OpenInterval{Float64}, Interval{:open, :closed, Float64}}}}}}}}}}}

But that type is not looking good. The result seems to be nested, that could probably be avoided.

In contrast currently:

julia> (0.0..10.0) \ (2:6)
(0.0..10.0) \ [2.0, 3.0, 4.0, 5.0, 6.0]

julia> typeof(ans)
SetdiffDomain{Float64, Tuple{ClosedInterval{Float64}, Vector{Float64}}}
dlfivefifty commented 3 years ago

It could make a UnionDomain{Float64,<:Vector} though this won't be type-stable because of the mixed open-closed intervals (there is the possibility of making an AbstractInterval whose clopenness is not part of the type). Though I agree leaving it as a SetdiffDomain is arguably cleaner.

Though perhaps (1..2) \ 1.5 should also be left as a SetdiffDomain?

daanhb commented 3 years ago

I guess that would be more consistent. I think I'm using that elsewhere though, I'd have to check.

In the meantime I changed the example above so it becomes:

julia> (0.0..10.0) \ (2:6)
(0.0..10.0) \ 2.0:1.0:6.0

i.e., updating the eltype of a range now preserves the range (this is pending the resolution of https://github.com/JuliaLang/julia/issues/27138).

daanhb commented 2 years ago

One year later and we still have:

julia> ((1..2) \ 1.5)
(1.0..1.5 (closed–open)) ∪ (1.5..2.0 (open–closed))

julia> ((1..2) \ [1.5])
(1.0..2.0) \ [1.5]

It is near impossible to avoid type instabilities when doing arithmetics with domains. I no longer worry about that, it just shouldn't be part of a time-critical code path. I do use the first kind of behaviour (subtracting a point). That means anybody can implement subtracting an array simply by iterating. So I'm inclined to leave it as is and close the issue.