Orthotope grid type (generalization of AbstractRange)

So, I’ve found that in several separate packages I need something like an Orthotope type

struct Orthotope{N,T}
    min::SVector{N,T}
    max::SVector{N,T}
end

Or in other words, a hyper-rectangle, specified by minimum and maximum bounds.

struct Orthogrid{N,T}
    x::Orthotope{N,T}
    n::SVector{N,Int}
end

In addition to that, I need to specify a number of grid points in each dimension. That’s what the second wrapping type is for, thus Orthogrid contains the grid sizes and the Orthotope value.

However, I’m really not sure where to put this type. I’m planning to use it in various ways in multiple different packages. All the packages that I need this for are built on my Grassmann.jl package, so I am considering just adding it into that package. However, it doesn’t quite make sense to put it in there contextually I think, but I also don’t necessarily want to make a separate package for it.

I’m not really sure how to organize this type yet. It could go into GeometryBasics but I don’t want to load that as a dependency in my packages (only as an optional dependency).

It’s kind of like a generalization of an AbstractRange but for more than 1 dimension.

2 Likes

Before adding this to Grassmann.jl, developing it separately may simplify focus and allow more of whatever is behind the reason for this facility to shine through. It is much easier to bring cleanly a small pkg into a larger home than vice versa.

fyi: Vectorized … tessellations of d-orthotopes and their faces with high-order orthotopes or simplicial elements

1 Like

Figured it out, Orthotpe is essentially a multi-dimensional generalization of AbstractRange types.

julia> dump(0:1)
UnitRange{Int64}
  start: Int64 0
  stop: Int64 1

The base range objects are constructed with start and stop of elements that are Real.

However, what’s really needed is a generalization of that for SVector inputs.

(::Base.Colon)(min::SVector{N,T},max::SVector{N,T}) where {N,T} = Orthotope{N,T}(min,max)

In higher dimensions, what’s needed is simply an SVector specifying the min and max range.

julia> SVector(0,0,0):SVector(1,1,1)
Orthotope{3,Int64}([0, 0, 0], [1, 1, 1])

So why don’t we have that in Julia yet? Should it be in the base language maybe?

SVector(0,0,0):SVector(0.1,0.1,0.1):SVector(1,1,1)

Also, having a 3 argument version would specify the number of grid points or interval lengths.

Either, this needs to be added to StaticArrays package to define the : constructor method without type piracy, or I need to add it to Grassmann and use my own vector input types for it.

Most likely, I’ll just add it to Grassmann since that has the least friction workflow for me, but if anyone else is interested, I can consider making a pull request to StaticArrays package.

Have you looked to GeometryBasics.jl for this? IRC, it has hyper rectangles and I make extensive use of StaticArrays

Did you read my original post? I only use GeometryBasics as an optional dependency, because I have my own geometry defined in Grassmann and it would be superfluous to load GeometryBasics by default every time I use Grassmann.

I think it’s fairly clear that this would belong into StaticArrays due to type piracy of :, or I would define it on my own types in Grassmann.

I only use GeometryBasics as an optional dependency, because I have my own geometry defined in Grassmann and it would be superfluous to load GeometryBasics by default every time I use Grassmann .

I’m just saying that GeometryBasics.jl may already have what you need and you don’t need to make it elsewhere or add it to GeometryBasics.

I think it’s fairly clear that this would belong into StaticArrays due to type piracy of : , or I would define it on my own types in Grassmann .

SVector:SVector:SVector seems like a pretty specialized use of :. You could just map(:, ::SVector...) to accomplish basically the same thing and wrap it in whatever type you want to do stuff with.

1 Like
julia> using Grassmann; basis"3"
(⟨+++⟩, v, v₁, v₂, v₃, v₁₂, v₁₃, v₂₃, v₁₂₃)

julia> OG = Chain(1.0v1):(0.2v2+0.2v3):(1.0v1+v2+v3)
(1.0v₁ + 0.0v₂ + 0.0v₃):(0.0v₁ + 0.2v₂ + 0.2v₃):(1.0v₁ + 1.0v₂ + 1.0v₃)

CartesianIndices in Base represents multidimensional ranges, but of course only for UnitRange{Int}, and they can be created as range of two CartesianIndex instances e.g.

julia> CartesianIndices((1:5,3:8,1:7)) == CartesianIndex(1,3,1):CartesianIndex(5,8,7)
true

I think there was a time that this was called CartesianRange, but I don’t think it every supported anything beyond UnitRange. How about Base.Iterators.product(range1, range2, range3)?

2 Likes

Fun fact, you can actually use any AbstractUnitRange{Int} for CartesianIndices

1 Like