From 891ea2f1403c56f17479a802f045611549c8f9fd Mon Sep 17 00:00:00 2001 From: Daan Huybrechs Date: Fri, 5 Apr 2024 14:21:03 +0200 Subject: [PATCH] tweaks and docs --- docs/make.jl | 2 +- docs/src/equality.md | 30 ++++++++-- docs/src/examples.md | 4 +- docs/src/geometry.md | 105 ++++++++++++++++++++++++++++++----- docs/src/setoperations.md | 2 +- src/domains/ball.jl | 88 +++++++++++++++++------------ src/domains/simplex.jl | 46 +++++++++------ src/generic/productdomain.jl | 2 +- test/test_domain_simplex.jl | 1 + 9 files changed, 207 insertions(+), 73 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index c2d2fd9..281c504 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -15,13 +15,13 @@ makedocs(; pages=[ "Home" => "index.md", "Examples" => "examples.md", - "Set operations" => "setoperations.md", "Specific domains" => Any[ "Euclidean geometry" => "geometry.md", "Function approximation" => "approximation.md", "Complex analysis" => "complex.md", "Numbers" => "numbers.md" ], + "Set operations" => "setoperations.md", "Design principles" => Any[ "The domain interface" => "interface.md", "Equality of domains" => "equality.md", diff --git a/docs/src/equality.md b/docs/src/equality.md index 9a7ea88..6b62d71 100644 --- a/docs/src/equality.md +++ b/docs/src/equality.md @@ -8,6 +8,10 @@ it may be difficult to discover automatically whether two domains are equal, especially when their types are different. Deciding whether two domains are equal requires supporting implementation, hence the outcome is not always accurate. Still, the principle serves as a design goal. +## The `isequaldomain` function + +Equality of domains is decided by the `isequaldomain` function in general, and +simply by `==` for subtypes of the `Domain` supertype. ```julia julia> UnitInterval() == UnitSimplex{Float64}() == 0..1 true @@ -15,14 +19,30 @@ true julia> ChebyshevInterval() == UnitBall{Float64}() == -1 .. 1 true ``` +The methodology behind this example is explained in the section on +[Canonical domains](@ref). + +!!! note + If two domains are equal according to `==`, then their hashes are also equal. + This allows the use of domains as keys in a `Dict`, if one is so inclined. -Equality of domains is decided by the `isequaldomain` function in general, and -simply by `==` for subtypes of the `Domain` supertype. ```@docs; canonical=false isequaldomain ``` -!!! note - If two domains are equal according to `==`, then their hashes are also equal. - This allows the use of domains as keys in a `Dict`, if one is so inclined. + +## Types versus mathematical sets + +In some cases the notion of a set is more interesting than the functionality +provided by the membership function. A concrete type offers a representation of +a notion. Having a type for the real numbers (see [`ℝ`](@ref)) allows one to +specify the domain of a function of a real variable. + +A type can also be convenient for other reasons. Although a ball with center and radius can be represented in terms of an affine map and a unit ball, not all affine maps +map the unit ball to a ball. Thus, in Julia, such a representation does not allow one to dispatch on the property of being a ball. + +Yet, having more types also comes with disadvantages. Dispatching on the type of +a domain such as an `Interval` does not make a function apply to all intervals - because a scalar unit ball has a different type but mathematically is also an interval. + +This tension is not resolved in the package. Still, deciding whether two domains are equal is a relevant aspect. diff --git a/docs/src/examples.md b/docs/src/examples.md index 2aa99ac..4456f5e 100644 --- a/docs/src/examples.md +++ b/docs/src/examples.md @@ -2,7 +2,7 @@ These are the same examples as those in the README of the package repository. -## Intervals +## Intervals from IntervalSets DomainSets.jl uses [IntervalSets.jl](https://github.com/JuliaMath/IntervalSets.jl) for closed and open intervals. In addition, it defines a few standard intervals. @@ -101,7 +101,7 @@ the 3-dimensional open unit ball ``` -## Product domains +## Cartesian products The cartesian product of domains is constructed with the `ProductDomain` or `ProductDomain{T}` constructor. This abstract constructor returns concrete types diff --git a/docs/src/geometry.md b/docs/src/geometry.md index 3ee1720..d179bf2 100644 --- a/docs/src/geometry.md +++ b/docs/src/geometry.md @@ -3,14 +3,26 @@ Domains appearing in geometry are an important special case. A small number of primitive domains are implemented. +Several of these may be open or closed. + DomainSets favours the definition of canonical types without state, which can -be implemented as singleton types without fields. It is made easy to map the +be implemented as singleton types without fields or data. It is made easy to map the canonical domain to a more specific one, often using -an affine map. See: [Canonical domains](@ref), and in particular the functions [`mapfrom_canonical`](@ref) and [`mapto_canonical`](@ref). +an affine map. See: [Canonical domains](@ref). + +## A note on Euclidean dimension -For example, each ball, with any given radius and any center, -can be obtained as the translation and scaling of a unit ball with radius one -centered at the origin. +The Euclidean dimension of a domain can be implicit in the element type, if it +is scalar or a static vector. One could have `T=Float64` or +`T = SVector{3,Float64}` for 3D domains. The dimension can also be variable, if the element type is a `Vector{T}`. In the latter case the dimension is typically +explicitly stored in a field of the type. In the former case the dimension is implicit in the type and the type itself can be stateless. + +!!! note + `DomainSets` imposes no preference and enables both representations. Among other + things, this leads to having more types, sometimes with funny or unexpected names. + For example, `StaticUnitBall{T}` is a singleton type, + whose dimension is fixed by the element type `T`. The word "static" in the name of the type refers to this aspect of dimensionality being known at compile-time. + The alternative is `DynamicUnitBall{T}`. This is a domain with element type `Vector{T}`, whose dimension is explicitly stored in a field. ## Intervals @@ -28,24 +40,91 @@ A number of intervals with fixed endpoints, known at compile-time, are added in ## Rectangles and cubes +Rectangles and cubes are implemented as a `ProductDomain` (see [Product domains](@ref)). +They can be obtained by passing closed intervals to the `ProductDomain` constructor, +or by invoking the `Rectangle` constructor. +Two special cases are the `UnitSquare` and `UnitCube` types. These types have no state. -## Balls and spheres +Some examples: +```julia +julia> ProductDomain(1.5..2.5, 3.5..6.0) +(1.5 .. 2.5) × (3.5 .. 6.0) -The type hierarchy is as follows: +julia> [0.5,0.3] ∈ UnitSquare() +true + +julia> [0.5,0.3,0.1] ∈ UnitCube() +true + +julia> ProductDomain(UnitInterval(), UnitInterval()) +UnitSquare() + +julia> Rectangle([0.0,1.0,2.0], [1.0,4.0,6.0]) +(0.0 .. 1.0) × (1.0 .. 4.0) × (2.0 .. 6.0) ``` -abstract Ball -|-> abstract UnitBall: radius is 1 - |-> StaticUnitBall: dimension is part of type - |-> DynamicUnitBall: dimension is specified by int field -|-> GenericBall: stores center and radius. Here, the dimension can be - obtained from the center, so there is only one type. + +##### Relevant functions + +```@docs; canonical=false +Rectangle +UnitSquare +UnitCube ``` +## Balls and spheres + +The unit ball in a space is the volume consisting of all points `x` for which +`norm(x) < 1` or `norm(x) ≤ 1`, depending on whether the ball is open or closed. +The sphere is the boundary of the volume, i.e., the set of points for which +`norm(x) = 1`. + +The canonical ball is a `UnitBall`, which can either have a dimension determined +by the element type `T` or, in case of `Vector` elements, a dimension that is +specified explicitly. + +The constructor of the abstract type `Ball` returns a suitable concrete type depending on the arguments. + +Types and syntax for spheres are analogous to those of balls. +```julia +julia> UnitBall() +UnitBall() + +julia> Ball(3.0) +Ball(3.0, [0.0, 0.0, 0.0]) + +julia> Ball(3.0, [0.4, 2.0, 5.0]) +Ball(3.0, [0.4, 2.0, 5.0]) + +julia> Ball{SVector{3,Float64}}(3, [0, 1, 2]) +Ball(3.0, [0.0, 1.0, 2.0]) + +julia> eltype(ans) +SVector{3, Float64} +``` + +##### Relevant functions ```@docs; canonical=false Ball() Sphere() +UnitBall() +UnitSphere() +``` + +The unit disk and unit circle are special cases in 2D. +```@docs; canonical=false +UnitDisk +UnitCircle ``` + ## Simplices + +The type hierarchy is similar to that of balls. The abstract supertype +`UnitSimplex` has a constructor which returns a suitable concrete subtype +depending on the arguments. + +```@docs; canonical=false +UnitSimplex() +``` diff --git a/docs/src/setoperations.md b/docs/src/setoperations.md index a26ab1e..661d01d 100644 --- a/docs/src/setoperations.md +++ b/docs/src/setoperations.md @@ -115,7 +115,7 @@ TupleProductDomain Rectangle ``` -## Union of sets +## Set union The mathematical union of two sets is guaranteed by `uniondomain`, while a lazy union is returned by `UnionDomain`. diff --git a/src/domains/ball.jl b/src/domains/ball.jl index 5e1a06f..ff8923c 100644 --- a/src/domains/ball.jl +++ b/src/domains/ball.jl @@ -11,8 +11,10 @@ # EuclideanUnitBall (StaticUnitBall), VectorUnitBall (DynamicUnitBall). """ -Supertype of balls for which elements satisfy `norm(x) < radius(ball)` (open ball) -or `norm(x) <= radius(ball)` (closed ball). + Ball{T,C} <: Domain{T} + +Abstract supertype for volumes of elements satisfying `norm(x-center(ball)) < radius(ball)` +(open ball) or `norm(x-center(ball)) <= radius(ball)` (closed ball). """ abstract type Ball{T,C} <: Domain{T} end @@ -98,30 +100,30 @@ distance_to(d::Ball, x) = x ∈ d ? zero(prectype(d)) : norm(x-center(d))-radius choice(d::Ball) = center(d) +abstract type UnitBall{T,C} <: Ball{T,C} end + +radius(::UnitBall) = 1 +center(d::UnitBall{T}) where {T<:StaticTypes} = zero(T) + """ UnitBall([dim::Int]) UnitBall{T}([dim::Int]) UnitBall{T,C=:closed}([dim::Int]) -The volume of all points of type `T`. +The open or closed volume of all points of type `T` with norm smaller than (or equal to) 1. """ -abstract type UnitBall{T,C} <: Ball{T,C} end - -radius(::UnitBall) = 1 -center(d::UnitBall{T}) where {T<:StaticTypes} = zero(T) - -UnitBall(n::Int) = DynamicUnitBall(n) UnitBall(::Val{N} = Val(3)) where {N} = EuclideanUnitBall{N}() +UnitBall(dim::Int) = DynamicUnitBall(dim) -UnitBall{T}(n::Int) where {T <: StaticTypes} = StaticUnitBall{T}(n) +UnitBall{T}(dim::Int) where {T <: StaticTypes} = StaticUnitBall{T}(dim) UnitBall{T}(::Val{N}) where {N,T} = StaticUnitBall{T}(Val(N)) UnitBall{T}() where {T <: StaticTypes} = StaticUnitBall{T}() -UnitBall{T}(n::Int) where {T} = DynamicUnitBall{T}(n) +UnitBall{T}(dim::Int) where {T} = DynamicUnitBall{T}(dim) -UnitBall{T,C}(n::Int) where {T <: StaticTypes,C} = StaticUnitBall{T,C}(n) +UnitBall{T,C}(dim::Int) where {T <: StaticTypes,C} = StaticUnitBall{T,C}(dim) UnitBall{T,C}(::Val{N}) where {N,T,C} = StaticUnitBall{T,C}(Val(N)) UnitBall{T,C}() where {T <: StaticTypes,C} = StaticUnitBall{T,C}() -UnitBall{T,C}(n::Int) where {T,C} = DynamicUnitBall{T,C}(n) +UnitBall{T,C}(dim::Int) where {T,C} = DynamicUnitBall{T,C}(dim) const ClosedUnitBall{T} = UnitBall{T,:closed} const OpenUnitBall{T} = UnitBall{T,:open} @@ -160,13 +162,13 @@ StaticUnitBall(::Val{N}) where {N} = StaticUnitBall{SVector{N,Float64}}() StaticUnitBall{T}() where {T} = StaticUnitBall{T,:closed}() -StaticUnitBall{T}(n::Int) where {T} = - (@assert n == euclideandimension(T); StaticUnitBall{T}()) +StaticUnitBall{T}(dim::Int) where {T} = + (@assert dim == euclideandimension(T); StaticUnitBall{T}()) StaticUnitBall{T}(::Val{N}) where {N,T} = (@assert N == euclideandimension(T); StaticUnitBall{T}()) -StaticUnitBall{T,C}(n::Int) where {T,C} = - (@assert n == euclideandimension(T); StaticUnitBall{T,C}()) +StaticUnitBall{T,C}(dim::Int) where {T,C} = + (@assert dim == euclideandimension(T); StaticUnitBall{T,C}()) StaticUnitBall{T,C}(::Val{N}) where {N,T,C} = (@assert N == euclideandimension(T); StaticUnitBall{T,C}()) @@ -181,6 +183,12 @@ similardomain(d::StaticUnitBall{S,C}, ::Type{T}) where {S,C,T<:StaticTypes} = similardomain(d::StaticUnitBall{S,C}, ::Type{T}) where {S,C,T} = DynamicUnitBall{T,C}(dimension(d)) +""" + UnitDisk() + UnitDisk{T=Float64}() + +The closed unit disk in 2D, with element type `SVector{2,T}`. +""" const UnitDisk{T} = UnitBall{SVector{2,T},:closed} UnitDisk() = UnitDisk{Float64}() @@ -213,13 +221,13 @@ type is a `Vector{T}` and `dim` specifies the length of the vectors. struct DynamicUnitBall{T,C} <: UnitBall{T,C} dimension :: Int - DynamicUnitBall{T,C}(n::Int) where {T,C} = new(n) - DynamicUnitBall{T,C}(n::Int) where {T<:StaticTypes,C} = - (@assert n == euclideandimension(T); new(n)) + DynamicUnitBall{T,C}(dim::Int) where {T,C} = new(dim) + DynamicUnitBall{T,C}(dim::Int) where {T<:StaticTypes,C} = + (@assert dim == euclideandimension(T); new(dim)) end -DynamicUnitBall(n::Int) = DynamicUnitBall{Vector{Float64}}(n) -DynamicUnitBall{T}(n::Int) where {T} = DynamicUnitBall{T,:closed}(n) +DynamicUnitBall(dim::Int) = DynamicUnitBall{Vector{Float64}}(dim) +DynamicUnitBall{T}(dim::Int) where {T} = DynamicUnitBall{T,:closed}(dim) dimension(d::DynamicUnitBall) = d.dimension @@ -228,7 +236,7 @@ center(d::DynamicUnitBall{T}) where {T} = zeros(eltype(T), dimension(d)) "The unit ball with vector elements of a given dimension." const VectorUnitBall{T,C} = DynamicUnitBall{Vector{T},C} -VectorUnitBall(n::Int = 3) = VectorUnitBall{Float64}(n) +VectorUnitBall(dim::Int = 3) = VectorUnitBall{Float64}(dim) VectorUnitDisk() = VectorUnitBall(2) similardomain(d::DynamicUnitBall{S,C}, ::Type{T}) where {S,C,T} = @@ -384,13 +392,20 @@ approx_indomain(x, d::UnitSphere, tolerance) = 1-tolerance <= norm(x) <= 1+tolerance -UnitSphere(n::Int) = DynamicUnitSphere(n) +""" + UnitSphere([dim::Int]) + UnitSphere{T}([dim::Int]) + UnitSphere{T,C=:closed}([dim::Int]) + +The set of all points of type `T` with norm 1. +""" UnitSphere(::Val{N} = Val(3)) where {N} = EuclideanUnitSphere{N}() +UnitSphere(dim::Int) = DynamicUnitSphere(dim) -UnitSphere{T}(n::Int) where {T <: StaticTypes} = StaticUnitSphere{T}(n) +UnitSphere{T}(dim::Int) where {T <: StaticTypes} = StaticUnitSphere{T}(dim) UnitSphere{T}(::Val{N}) where {N,T} = StaticUnitSphere{T}(Val(N)) UnitSphere{T}() where {T <: StaticTypes} = StaticUnitSphere{T}() -UnitSphere{T}(n::Int) where {T} = DynamicUnitSphere{T}(n) +UnitSphere{T}(dim::Int) where {T} = DynamicUnitSphere{T}(dim) isequaldomain(d1::UnitSphere, d2::UnitSphere) = dimension(d1)==dimension(d2) @@ -408,8 +423,8 @@ end StaticUnitSphere() = StaticUnitSphere{Float64}() StaticUnitSphere(::Val{N}) where {N} = StaticUnitSphere{SVector{N,Float64}}() -StaticUnitSphere{T}(n::Int) where {T} = - (@assert n == euclideandimension(T); StaticUnitSphere{T}()) +StaticUnitSphere{T}(dim::Int) where {T} = + (@assert dim == euclideandimension(T); StaticUnitSphere{T}()) StaticUnitSphere{T}(::Val{N}) where {N,T} = (@assert N == euclideandimension(T); StaticUnitSphere{T}()) @@ -425,7 +440,12 @@ const EuclideanUnitSphere{N,T} = StaticUnitSphere{SVector{N,T}} EuclideanUnitSphere{N}() where {N} = EuclideanUnitSphere{N,Float64}() -"The unit circle in 2D." +""" + UnitCircle() + UnitCircle{T=Float64}() + +The unit circle in 2D, with element type `SVector{2,T}`. +""" const UnitCircle{T} = UnitSphere{SVector{2,T}} UnitCircle() = UnitCircle{Float64}() @@ -437,12 +457,12 @@ mapfrom_canonical(::Parameterization, d::UnitCircle{T}) where {T} = UnitCircleMa struct DynamicUnitSphere{T} <: UnitSphere{T} dimension :: Int - DynamicUnitSphere{T}(n::Int) where {T} = new(n) - DynamicUnitSphere{T}(n::Int) where {T<:StaticTypes} = - (@assert n == euclideandimension(T); new(n)) + DynamicUnitSphere{T}(dim::Int) where {T} = new(dim) + DynamicUnitSphere{T}(dim::Int) where {T<:StaticTypes} = + (@assert dim == euclideandimension(T); new(dim)) end -DynamicUnitSphere(n::Int) = DynamicUnitSphere{Vector{Float64}}(n) +DynamicUnitSphere(dim::Int) = DynamicUnitSphere{Vector{Float64}}(dim) dimension(d::DynamicUnitSphere) = d.dimension @@ -451,7 +471,7 @@ center(d::DynamicUnitSphere{T}) where {T} = zeros(eltype(T), dimension(d)) "The unit sphere with vector elements of a given dimension." const VectorUnitSphere{T} = DynamicUnitSphere{Vector{T}} -VectorUnitSphere(n::Int = 3) = VectorUnitSphere{Float64}(n) +VectorUnitSphere(dim::Int = 3) = VectorUnitSphere{Float64}(dim) VectorUnitCircle() = VectorUnitSphere(2) similardomain(d::DynamicUnitSphere, ::Type{T}) where {T} = diff --git a/src/domains/simplex.jl b/src/domains/simplex.jl index 90caa8f..8dbe8cf 100644 --- a/src/domains/simplex.jl +++ b/src/domains/simplex.jl @@ -11,24 +11,38 @@ isclosedset(::Simplex{T,:open}) where {T} = false isopenset(d::Simplex) = !isclosedset(d) -"The unit simplex is a polytope with the origin and all unit vectors as vertices." +""" + UnitSimplex{T,C} + +A polytope with the origin and all unit vectors as vertices. +""" abstract type UnitSimplex{T,C} <: Simplex{T,C} end const ClosedUnitSimplex{T} = UnitSimplex{T,:closed} const OpenUnitSimplex{T} = UnitSimplex{T,:open} -UnitSimplex(n::Int) = DynamicUnitSimplex(n) -UnitSimplex(::Val{N}) where {N} = EuclideanUnitSimplex{N}() +""" + UnitSimplex([dim::Int]) + UnitSimplex{T}([dim::Int]) + UnitSimplex{T,C=:closed}([dim::Int]) + +The open or closed volume of all points of type `x`, for which the sum of +components is smaller than (or equal to) 1. + +The unit simplex has the origin and all Euclidean unit vector as vertices. +""" +UnitSimplex(::Val{N} = Val(3)) where {N} = EuclideanUnitSimplex{N}() +UnitSimplex(dim::Int) = DynamicUnitSimplex(dim) -UnitSimplex{T}(n::Int) where {T <: StaticTypes} = StaticUnitSimplex{T}(n) +UnitSimplex{T}(dim::Int) where {T <: StaticTypes} = StaticUnitSimplex{T}(dim) UnitSimplex{T}(::Val{N}) where {N,T} = StaticUnitSimplex{T}(Val(N)) UnitSimplex{T}() where {T <: StaticTypes} = StaticUnitSimplex{T}() -UnitSimplex{T}(n::Int) where {T} = DynamicUnitSimplex{T}(n) +UnitSimplex{T}(dim::Int) where {T} = DynamicUnitSimplex{T}(dim) -UnitSimplex{T,C}(n::Int) where {T <: StaticTypes,C} = StaticUnitSimplex{T,C}(n) +UnitSimplex{T,C}(dim::Int) where {T <: StaticTypes,C} = StaticUnitSimplex{T,C}(dim) UnitSimplex{T,C}(::Val{N}) where {N,T,C} = StaticUnitSimplex{T,C}(Val(N)) UnitSimplex{T,C}() where {T <: StaticTypes,C} = StaticUnitSimplex{T,C}() -UnitSimplex{T,C}(n::Int) where {T,C} = DynamicUnitSimplex{T,C}(n) +UnitSimplex{T,C}(dim::Int) where {T,C} = DynamicUnitSimplex{T,C}(dim) insimplex_closed(x) = mapreduce( t-> t >= 0, &, x) && norm(x,1) <= 1 insimplex_open(x) = mapreduce( t-> t > 0, &, x) && norm(x,1) < 1 @@ -72,13 +86,13 @@ StaticUnitSimplex(::Val{N}) where {N} = StaticUnitSimplex{SVector{N,Float64}}() StaticUnitSimplex{T}() where {T} = StaticUnitSimplex{T,:closed}() -StaticUnitSimplex{T}(n::Int) where {T} = - (@assert n == euclideandimension(T); StaticUnitSimplex{T}()) +StaticUnitSimplex{T}(dim::Int) where {T} = + (@assert dim == euclideandimension(T); StaticUnitSimplex{T}()) StaticUnitSimplex{T}(::Val{N}) where {N,T} = (@assert N == euclideandimension(T); StaticUnitSimplex{T}()) -StaticUnitSimplex{T,C}(n::Int) where {T,C} = - (@assert n == euclideandimension(T); StaticUnitSimplex{T,C}()) +StaticUnitSimplex{T,C}(dim::Int) where {T,C} = + (@assert dim == euclideandimension(T); StaticUnitSimplex{T,C}()) StaticUnitSimplex{T,C}(::Val{N}) where {N,T,C} = (@assert N == euclideandimension(T); StaticUnitSimplex{T,C}()) @@ -103,13 +117,13 @@ boundary(d::StaticUnitSimplex{T}) where {T<:Number} = boundary(AbstractInterval( struct DynamicUnitSimplex{T,C} <: UnitSimplex{T,C} dimension :: Int - DynamicUnitSimplex{T,C}(n::Int) where {T,C} = new(n) - DynamicUnitSimplex{T,C}(n::Int) where {T<:StaticTypes,C} = - (@assert n == euclideandimension(T); new(n)) + DynamicUnitSimplex{T,C}(dim::Int) where {T,C} = new(dim) + DynamicUnitSimplex{T,C}(dim::Int) where {T<:StaticTypes,C} = + (@assert dim == euclideandimension(T); new(dim)) end -DynamicUnitSimplex(n::Int) = DynamicUnitSimplex{Vector{Float64}}(n) -DynamicUnitSimplex{T}(n::Int) where {T} = DynamicUnitSimplex{T,:closed}(n) +DynamicUnitSimplex(dim::Int) = DynamicUnitSimplex{Vector{Float64}}(dim) +DynamicUnitSimplex{T}(dim::Int) where {T} = DynamicUnitSimplex{T,:closed}(dim) dimension(d::DynamicUnitSimplex) = d.dimension diff --git a/src/generic/productdomain.jl b/src/generic/productdomain.jl index ae42e93..272d473 100644 --- a/src/generic/productdomain.jl +++ b/src/generic/productdomain.jl @@ -2,7 +2,7 @@ """ abstract type ProductDomain{T} -A `ProductDomain` represents the cartesian product of other domains. +Represents the cartesian product of other domains. """ abstract type ProductDomain{T} <: CompositeDomain{T} end diff --git a/test/test_domain_simplex.jl b/test/test_domain_simplex.jl index 4e5884a..20d8104 100644 --- a/test/test_domain_simplex.jl +++ b/test/test_domain_simplex.jl @@ -1,4 +1,5 @@ function test_simplex() + @test UnitSimplex() isa EuclideanUnitSimplex{3,Float64} @test UnitSimplex(2) isa VectorUnitSimplex{Float64} @test UnitSimplex(Val(2)) isa EuclideanUnitSimplex{2,Float64} @test UnitSimplex{Float64}() isa StaticUnitSimplex{Float64}