https://github.com/juliaapproximation/domainsetscore.jl
An interface package for working with domains as continuous sets of elements
https://github.com/juliaapproximation/domainsetscore.jl
Last synced: 3 months ago
JSON representation
An interface package for working with domains as continuous sets of elements
- Host: GitHub
- URL: https://github.com/juliaapproximation/domainsetscore.jl
- Owner: JuliaApproximation
- License: mit
- Created: 2023-08-07T10:04:08.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2023-11-26T14:36:13.000Z (over 2 years ago)
- Last Synced: 2026-01-22T07:44:41.691Z (5 months ago)
- Language: Julia
- Size: 30.3 KB
- Stars: 0
- Watchers: 6
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[](https://github.com/JuliaApproximation/DomainSetsCore.jl/actions)
[](https://codecov.io/gh/JuliaApproximation/DomainSetsCore.jl)
# DomainSetsCore.jl
An interface package for working with domains as continuous sets of elements.
Examples of domains may be geometric sets such as intervals and triangles,
or the complex plane without the negative real line. However, domains are not
limited to geometry. A domain could also be a collection of vectors or arrays,
such as the set of all orthogonal `3x3` matrices.
Existing types may add the interpretation of being a domain by implementing the
domain interface. They gain the ability to interact with other domains.
## The domain interface
### The `in` function
A domain is a set of elements that is possibly continuous. Continuous sets are
defined mathematically, not by an exhaustive list of their elements. In practice membership of the set is defined by the implementation of `in`. The function
call `in(x, domain)` evaluates to true if the domain contains an element `y`
such that `y == x`.
#### Incompatible element types
In principle, the function `in(x, domain)` should not throw an exception even
if the types seem mathematically nonsensical. In that case, the correct return
value is `false`. This mimicks the behaviour of `in` for finite sets in Julia:
```julia
julia> in(rand(3,3), 1:3)
false
```
Indeed, a `3x3` matrix is not equal to any of the numbers `1`, `2` or `3`.
### The `domaineltype` function
The defining mathematical condition of a continuous set might be satisfied by
variables of different types. Still, the interface defines the `domaineltype`
of a domain. It is a valid type for elements of the set.
Functions that generate elements of the domain should generate elements
of that type. As a consequence, for finite sets such as an `AbstractArray` or `AbstractSet`, the `domaineltype` agrees with the `eltype` of that set. For
intervals on the real line, the `domaineltype` might be `Float64`. When there is
no clear candidate the `domaineltype` might simply be `Any`.
### Minimal formal interface
The domain interface is formally summarised in the following table:
| Required methods | Brief description |
| ---------------- | ----------------- |
| `in(x, d)` | Returns `true` when `x` is an element of the domain, `false` otherwise |
| `DomainStyle(d)` | Returns `IsDomain()` if `d` implements this interface |
Optional methods include:
| Important optional methods | Default definition | Brief description
| --- | --- | --- |
| `domaineltype(d)` | `eltype(d)` | Returns a valid type for elements of the domain |
Several extensions of this minimal interface are defined in the [DomainSets.jl](https://github.com/JuliaApproximation/DomainSets.jl) package.
## Domains as mathematical sets
A domain behaves as much as possible like the mathematical set it represents, irrespective of its type. Thus, for example, two domains should be considered
equal if their membership functions agree.
It is not always possible to realize this intended behaviour in practice. Indeed
it may be difficult to discover automatically whether two domains are equal,
especially when their types are different. Still, the principle serves as a
design goal.
## The Domain supertype and DomainStyle trait
This package defines the abstract type `Domain{T}` of continuous sets with
`domaineltype` equal to `T`. No concrete domain types are defined in this
package.
The package also defines the trait `DomainStyle`. Any type can declare to
implement the domain interface by defining
```julia
DomainSetsCore.DomainStyle(d::MyDomain) = IsDomain()
```
Objects of type `Number`, `AbstractArray` and `AbstractSet` are declared to be
domains in this package.
## Using the domain interface in practice with `DomainRef`
With the exception of subtypes of `Domain`, the set of types implementing the
domain interface is not based on a common abstract supertype. Functions that are
intended to manipulate domains may simply omit the type of the domain in the
function signature. However, functions defined in other packages can not be
extended to work for domains, as there is no common type to dispatch on.
For that reason this package defines the `DomainRef` reference.
In the absence of function ownership, the practice of domain references requires
active intent both by users and by developers. For a user, passing `DomainRef(d)`
to a function indicates that `d` is to be treated as a domain. For a developer,
the implementation `foo(d::DomainRef)` may be used to extend the functionality
of `foo` to domains.
The reference `DomainRef(d)` is not in itself a domain, it is merely a reference.
The developer of `foo(d::DomainRef)` may use `domain(d)` to access the domain
object. More generally, one can implement `foo(d::AnyDomain)` and use
`domain(d)` in the function definition. In that case the user may invoke `foo`
both indirectly with a domain reference and directly with a concrete subtype of
`Domain`.
### Example usage
An example of this practice is the functionality of `union` in the
[DomainSets.jl](https://github.com/JuliaApproximation/DomainSets.jl) package.
First, the package defines a generic function `uniondomain(d1,d2)` with no
restrictions on the types of `d1` and `d2`. The function returns an object that
behaves as the mathematical union of the two arguments. It always interprets the arguments as domains, regardless of their types.
A user wanting to use the standard `∪` syntax for this purpose has to make this intention explicit by writing `DomainRef(d1) ∪ DomainRef(d2)`. The outcome is
equivalent to `uniondomain(d1, d2)`, and could be different from what `d1 ∪ d2`
means in other contexts for the combination of types of `d1` and `d2`. That
original behaviour of `∪`, quite possibly an error in fact, is not changed.
A developer may make the `∪` syntax more accessible to users as follows. As soon
as one of `d1` or `d2` is a `Domain`, or a reference to a domain, the call to
`union` can safely be interpreted as the union of domains. Thus, a developer may
write:
```julia
union(d1::Anydomain, d2) = uniondomain(domain(d1), d2)
union(d1, d2::AnyDomain) = uniondomain(d1, domain(d2))
union(d1::AnyDomain, d2::AnyDomain) = uniondomain(domain(d1),domain(d2))
```
These definitions are safe in the sense that there is no ambiguity and no
possible clash with any existing definition of `union(d1,d2)` in other packages.
## Package interoperability
The goal of the domain interface is to make objects from different packages
interoperable with minimal interaction between packages and, thus, maximal
independence in their development.
Say package A and package B both define a type that can be interpreted as a
domain, respectively `objectA` and `objectB`. Package C may define the domain
interface for `objectA` using the `DomainStyle` trait. Package D may similarly
define the domain interface for `objectB`. Package E could load `DomainSets` and packages C and D. A user of package E can type `uniondomain(objectA,objectB)`.
This construction requires no active collaboration between the developers of
packages A, B, C, D and E. They can all be developed independently. Package C
relies on package A and on `DomainSetsCore`. Package D relies on package B and
on `DomainSetsCore`. Package E relies on packages C, D and `DomainSets`.
Packages C, D and E could be developed as package extensions.
## More functionality with domains
Unions and intersections of domains, as well as many other set operations, are implemented generically in the
[DomainSets.jl](https://github.com/JuliaApproximation/DomainSets.jl) package.
Intervals inheriting from the `Domain` supertype are implemented in
[IntervalSets.jl](https://github.com/JuliaMath/IntervalSets.jl).