JuliaApproximation / DomainSets.jl

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

Symbolic ProductDomain and its support #88

Closed ashutosh-b-b closed 1 year ago

ashutosh-b-b commented 3 years ago
using DomainSets
using ModelingToolkit
@parameters x, y
ClosedInterval(1, x) ## this gives out 1..x
ProductDomain(ClosedInterval(1, 10),ClosedInterval(1, x),ClosedInterval(1, y))  #Gives an Error

Stack Trace of the error

TypeError: non-boolean (Num) used in boolean context
infimum at IntervalSets.jl:89 [inlined]
map(f::typeof(infimum), t::Tuple{ClosedInterval{Num}, ClosedInterval{Num}, ClosedInterval{Num}}) at tuple.jl:215
Rectangle(::ClosedInterval{Num}, ::Vararg{ClosedInterval{Num}, N} where N) at cube.jl:174
Rectangle(::ClosedInterval{Int64}, ::Vararg{ClosedInterval{T} where T, N} where N) at cube.jl:173
ProductDomain(::ClosedInterval{Int64}, ::Vararg{ClosedInterval{T} where T, N} where N) at cube.jl:189
top-level scope at lowlevel_test.jl:324
eval at boot.jl:360 [inlined]

Looks like this is because infimum does not work for x::Num

dlfivefifty commented 3 years ago

I think maybe you want to either create a Rectangle directly by specifying the corners, or use a concrete TupleProductDomain to prevent it trying to determine the corners of the rectangle?

ashutosh-b-b commented 3 years ago

Does it allow to have infimum and supremum over the domain?

dlfivefifty commented 3 years ago

Not sure I understand the question. I thought we wanted to avoid calls to infimum and supremum since they aren't defined?

@daanhb why are we calling these instead of first and last?

ashutosh-b-b commented 3 years ago

But, in case of a product domain, if I do use a symbol, I may require an infimum or supremum right? For instance in the second example, The supremum would be [1,x,y]

dlfivefifty commented 3 years ago

supremum only makes sense for real-valued domains

ashutosh-b-b commented 3 years ago

x and y would be Real values once substituted, else in the above case how do I get the upper limit of this ProductDomain?

daanhb commented 3 years ago

Thanks for reporting @ashutosh-b-b, this is an issue. It seems the product domain here attempts to make a Rectangle (because that's what it is here) but the Rectangle constructor uses infimum and supremum to find out the left and right endpoints of the intervals involved. This doesn't work for intervals of Num's. Simply invoking leftendpoint and rightendpoint instead does work, I've checked. I did not encounter a case before where infimum and supremum failed on intervals, but in cases where we're really just after the endpoints it would be better to do so explicitly.

This doesn't completely settle the issue, because you're asking about a way to get the upper limit of a product domain. We do currently use infimum and supremum for that, but that is not really correct in many cases (I'd rather remove this functionality), and it still wouldn't work for Num types. In case of cubes and rectangles, the right thing to do would be:

julia> d = ProductDomain(ClosedInterval(1, 10),ClosedInterval(1, x),ClosedInterval(1, y));

julia> map(leftendpoint, components(d))
3-element StaticArrays.SVector{3, Num} with indices SOneTo(3):
 1
 1
 1

julia> map(rightendpoint, components(d))
3-element StaticArrays.SVector{3, Num} with indices SOneTo(3):
 10
  x
  y

The code above relies on changes to the Rectangle constructor, so it won't work right away. There is also an issue with display currently, something with the hashes of Num doesn't seem to be working. That's why I added a semicolon to the first line above.

daanhb commented 3 years ago

The display issue I mentioned above is due to the following:

julia> using ModelingToolkit, DomainSets

julia> @parameters x, y
2-element Vector{Num}:
 x
 y

julia> 1..x == 1..y
ERROR: TypeError: non-boolean (Num) used in boolean context
Stacktrace:
 [1] ==(A::ClosedInterval{Num}, B::ClosedInterval{Num})
   @ IntervalSets ~/.julia/packages/IntervalSets/VeVgo/src/IntervalSets.jl:190
 [2] top-level scope
   @ REPL[4]:1

julia> x == y
x == y

The package can't compare intervals involving Num's for equality, because x == y does not return a boolean value but an expression. What should the result of 1..x == 1..y be? Is it always false because x is a different parameter from y, or are there situations where the intervals might be equal?

daanhb commented 3 years ago

I've worked around the display issue for now, it is working in v0.5.4. There was a problem computing the hash of a vector of intervals with Num types, due to the way hashes of arrays are computed in Julia. This has changed on Julia master meanwhile, so I expect that in the future the underlying issue will go away.

I've also replaced some calls to infimum and supremum elsewhere, so that you can do:

julia> d = ProductDomain(ClosedInterval(1, 10),ClosedInterval(1, x),ClosedInterval(1, y))
(1..10) × (1..x) × (1..y)

julia> leftendpoint(d)
3-element StaticArrays.SVector{3, Num} with indices SOneTo(3):
 1
 1
 1

julia> rightendpoint(d)
3-element StaticArrays.SVector{3, Num} with indices SOneTo(3):
 10
  x
  y

So the leftendpoint' of a cube is a shorthand formap(leftendpoint, components(d))`.

daanhb commented 2 years ago

@ashutosh-b-b before I close this issue, could you confirm that it is fixed in 0.5.4? I'm sort of expecting more issues along similar lines, please let us know. It makes the code more generic if we fix them, thanks