# Set operations

DomainSets implements a number of standard set operations. In some cases the operation can be performed analytically and a concrete domain is returned. More often than not, however, the operation results in a lazy structure.

Functions like `uniondomain`

and `intersectdomain`

are not restricted to arguments of type `Domain`

. Thus, one can construct the lazy union of any two objects, regardless of their types.

A distinction is made for set operations between functions in lowercase, such as `uniondomain`

, and capitalized functions, in this case `UnionDomain`

. The former attempts to simplify the arguments (see Canonical domains) and returns a domain that is mathematically equivalent to the union of the two domains. The latter is the constructor of a type and hence always returns an instance of `UnionDomain`

.

For concrete subtypes of `Domain`

one can use standard Julia operators and functions for common set operations. The relevant symbols and functions are `∪`

(union), `∩`

(intersect) and `∖`

(setdiff). For example:

```
julia> UnitBall(3) ∩ Point([0,0,0])
Point([0.0, 0.0, 0.0])
```

Set operations in DomainSets are often **not type-stable**. For example, by convention `uniondomain(d1,d2)`

returns a domain of the simplest type that is mathematically equivalent to the union of `d1`

and `d2`

. The union of two overlapping intervals is a single interval, but the union of non-overlapping intervals is a `UnionDomain`

:

```
julia> uniondomain(1..3, 2..4)
1 .. 4
julia> uniondomain(1..3, 5..7)
(1 .. 3) ∪ (5 .. 7)
```

When type-safety is important, use the corresponding constructor:

```
julia> UnionDomain(1..3, 2..4)
(1 .. 3) ∪ (2 .. 4)
```

## Product domains

Product domains are created most easily by invoking the `ProductDomain`

constructor. The constructor of the associated abstract type `ProductDomain`

returns an instance of a suitable concrete subtype. In many cases a user need not be aware of which type is being returned by `ProductDomain`

, as it always behaves like the requested domain.

`DomainSets.ProductDomain`

— Method```
ProductDomain(domains...)
ProductDomain{T}(domains...)
```

Return a concrete subtype of `ProductDomain`

which agrees mathematically with the cartesian product of the given domains.

The concrete subtype being returned depends on `T`

. If `T`

is provided, it will be the eltype of the product domain. If `T`

is not provided, a suitable choice is deduced from the arguments.

See also: `VcatDomain`

, `VectorProductDomain`

, `TupleProductDomain`

, `Rectangle(a,b)`

.

A number of concrete product domain types are implemented. They differ in what the `eltype`

of the product domain is. In the most generic case `T`

is a tuple, with each element representing the element type of the corresponding factor. A `VcatDomain`

is a special case for product domains of Euclidean type, i.e., one in which each factor has a scalar or statically-sized vector as element type. Finally, a `VectorProductDomain`

has a `Vector`

element type whose dimension is determined by the number of factors. The `ProductDomain`

aims to return the most specialized type of domain, but the individual constructors may be invoked to ensure a specific one.

```
julia> ProductDomain(2..4.5, 3.0..5.0)
(2.0 .. 4.5) × (3.0 .. 5.0)
julia> eltype(ProductDomain(2..4.5, 3.0..5.0))
SVector{2, Float64}
julia> [2.4, 4] ∈ ProductDomain(2..4.5, 3.0..5.0)
true
julia> TupleProductDomain(2..4.5, 3.0..5.0)
(2.0 .. 4.5) × (3.0 .. 5.0)
julia> eltype(TupleProductDomain(2..4.5, 3.0..5.0))
Tuple{Float64, Float64}
julia> (2.4, 4) ∈ TupleProductDomain(2..4.5, 3.0..5.0)
true
julia> ProductDomain([ i..i+1.0 for i in 1:10])
(1.0 .. 2.0) × (2.0 .. 3.0) × (3.0 .. 4.0) × ... × (10.0 .. 11.0)
julia> eltype(ProductDomain([ i..i+1.0 for i in 1:10]))
Vector{Float64}
julia> 1:10 ∈ ProductDomain([ i..i+1.0 for i in 1:10])
true
```

It is noteworthy that a `VcatDomain`

can cope with the concatenation of scalars and vectors. In the example below, a cylinder is represented as the product of a two-dimensional disk with a one-dimensional interval.

```
julia> using DomainSets: ×
julia> cylinder = UnitDisk() × UnitInterval()
UnitDisk() × (0.0 .. 1.0 (Unit))
julia> eltype(cylinder)
SVector{3, Float64}
julia> [0.4,0.2,0.6] ∈ cylinder
true
```

A number of concrete product domains are implemented in `DomainSets`

.

`DomainSets.VcatDomain`

— TypeA `VcatDomain`

concatenates the element types of its member domains in a single static vector.

`DomainSets.VectorProductDomain`

— TypeA `VectorProductDomain`

is a product domain of arbitrary dimension where the element type is a vector, and all member domains have the same element type.

`DomainSets.TupleProductDomain`

— TypeA `TupleProductDomain`

is a product domain that concatenates the elements of its member domains in a tuple.

`DomainSets.Rectangle`

— Type```
Rectangle(a, b)
Rectangle(domains::ClosedInterval...)
Rectangle{T}(domains::ClosedInterval...)
```

A rectangular domain in `n`

dimensions with extrema determined by the vectors or points `a`

and `b`

or by the endpoints of the given intervals.

## Set union

The mathematical union of two sets is guaranteed by `uniondomain`

, while a lazy union is returned by `UnionDomain`

.

For vectors and sets in Julia, `uniondomain`

returns precisely what the standard `union`

operation would do, while `UnionDomain`

returns a lazy construct:

```
julia> uniondomain(1:3, 10)
4-element Vector{Int64}:
1
2
3
10
julia> UnionDomain(1:3, 10)
1:3 ∪ 10
julia> 10 ∈ ans
true
```

`DomainSets.uniondomain`

— Function`uniondomain(domains...)`

Return a domain that agrees with the mathematical union of the arguments.

See also: `UnionDomain`

.

`DomainSets.UnionDomain`

— Type```
UnionDomain(domains...)
UnionDomain{T}(domains...)
```

The lazy union of the given domains.

See also: `uniondomain`

.

## Set intersection

The mathematical intersection of two sets is guaranteed by `intersectdomain`

, while a lazy intersection is returned by `IntersectDomain`

.

`DomainSets.intersectdomain`

— Function`intersectdomain(domains...)`

Return a domain which agrees with the mathematical intersection of the given domains.

See also: `IntersectDomain`

.

`DomainSets.IntersectDomain`

— Type```
IntersectDomain(domains...)
IntersectDomain{T}(domains...)
```

The lazy intersection of an iterable list of domains.

See also: `intersectdomain`

.

## Set difference

The mathematical difference of two sets is guaranteed by `setdiffdomain`

, while a lazy difference is returned by `SetdiffDomain`

.

`DomainSets.setdiffdomain`

— Function`setdiffdomain(d1, d2)`

Return a domain which agrees with the mathematical difference of the given domains.

See also: `SetdiffDomain`

.

`DomainSets.SetdiffDomain`

— Type```
SetdiffDomain(d1, d2)
SetdiffDomain{T}(d1, d2)
```

The lazy set difference of the given domains.

See also: `setdiffdomain`

.