# Introduction to set6

#### 2021-10-18

set6 is an object-oriented interface for constructing and manipulating mathematical sets using R6. set6 allows a variety of mathematical sets, including Sets, Tuple, Intervals and Fuzzy variants; there are also Conditional sets for creating sets out of complex logical instructions. A full set of tutorials can be found here. In this introductory vignette we briefly demonstrate how to construct a set, access its properties and traits, and some basic algebra of sets.

Before we get started note that by default `set6` uses unicode for printing representations of sets. Whilst this is preferred for neater printing, some machines, operating systems, or R versions may not behave as expected when printing unicode and therefore we allow the option to turn this off.

    useUnicode(FALSE)

This vignette does use the unicode representations.

## Constructing a Set

Classes in `set6` can be split into two groups: set objects, and wrappers. When we refer to sets (lower-case ‘s’) we refer to objects inheriting from the base class `Set`. All sets in `set6` inherit from `Set`, meaning that, at a very minimum, they share the same methods and fields as `Set`.

The simplest set of all is the empty set, we can see how even this has methods for printing and summarising, as well as a list of properties and traits.

    empty = Set$new()
    empty
    #> ∅
    summary(empty)
    #> Set
    #>  ∅
    #> Traits:
    #>  Crisp
    #> Properties:
    #>  Empty
    #>  Cardinality = 0  -  countably finite
    #>  Closed
    empty$properties
    #> $empty
    #> [1] TRUE
    #>
    #> $singleton
    #> [1] FALSE
    #>
    #> $cardinality
    #> [1] 0
    #>
    #> $countability
    #> [1] "countably finite"
    #>
    #> $closure
    #> [1] "closed"
    empty$traits
    #> $crisp
    #> [1] TRUE

Sets can contain any object in R that has a valid `as.character` dispatch method that ensures uniqueness in objects. This is a requirement as internally string representations are used to compare sets.

    Set$new(1,2,3)
    #> {1, 2, 3}
    Set$new(letters[1:5])
    #> {a, b,...,d, e}
    Set$new(1, 2i, "a", Set$new(1))
    #> {0+2i, 1, a, {1}}

## The different kind of sets

Each set class has its own unique mathematical properties, we will not cover these extensively here but summarise each with a short example.

    # A Set cannot have duplicated elements, and ordering does not matter
    Set$new(1,2,2,3) == Set$new(3,2,1)
    #> [1] TRUE

    # A Tuple can have duplicated elements, and ordering does matter
    Tuple$new(1,2,2,3) != Tuple$new(1,2,3)
    #> [1] TRUE
    Tuple$new(1,3) != Tuple$new(3,1)
    #> [1] TRUE

    # An interval can be an interval of integers or numerics, but must be continuous
    Interval$new(1, 10, class = "integer")
    #> {1,...,10}
    Interval$new(1, 10) # numeric is default
    #> [1,10]
    # `type` is used to specify the interval upper and lower closure
    Interval$new(1, 10, type = "()")
    #> (1,10)

    # SpecialSets are useful for common 'special' mathematical sets
    # Use listSpecialSets() to see which are available.
    Reals$new()
    #> ℝ
    PosIntegers$new()
    #> ℤ+

    # ConditionalSets are user-built sets from logical statements.
    # For example, the set of even numbers.
    ConditionalSet$new(function(x) x %% 2 == 0)
    #> {x ∈ 𝕍 : x%%2 == 0}

    # Finally FuzzySets and FuzzyTuples expand Sets and Tuples to allow for partial
    # membership of elements. These have two constructors, either by specifying the elements
    # and membership alternatively, or by passing these separately to the given arguments.
    FuzzySet$new(1, 0.1, 2, 0.2, "a", 0.3) ==
      FuzzySet$new(elements = c(1,2,"a"), membership = c(0.1,0.2,0.3))
    #> [1] TRUE

## Comparisons and Containedness

Every set has methods for comparing it to other sets, as well as for checking which elements are contained within in. Operators are overloaded where possible, and where not other infix operators are defined, these are:

- `$isSubset(x, proper = TRUE)` (`<`) - Is `x` a proper subset of `self`
- `$isSubset(x, proper = FALSE)` (`<=`) - Is `x` a (non-proper) subset of `self`
- `$isSubset(x, proper = TRUE)` (`>`) - Is `self` a proper subset of `x`
- `$isSubset(x, proper = FALSE)` (`>=`) - Is `self` a (non-proper) subset of `x`
- `$equals(x)` (`==`) - Is `x` (mathematically) equal to `self`
- `!($equals(x))` (`!=`) - Is `x` (mathematically) not equal to `self`
- `$contains(x)` (`%inset%`) - Is `x` contained in `self`

All methods are vectorized for multiple testing.

    s = Set$new(1,2,3)
    s$contains(1)
    #> [1] TRUE
    s$contains(2, 4)
    #> [1] TRUE
    c(2, 4) %inset% s
    #> [1]  TRUE FALSE

    s$isSubset(Set$new(1,2,3), proper = FALSE)
    #> [1] TRUE
    s$isSubset(Set$new(1,2,3), proper = TRUE)
    #> [1] FALSE
    c(Set$new(1), Set$new(4, 5)) < s
    #> [1]  TRUE FALSE

    # Sets are FuzzySets with membership = 1
    s$equals(FuzzySet$new(elements = 1:3, membership = 1))
    #> [1] TRUE
    s$equals(FuzzySet$new(elements = 1:3, membership = 0.1))
    #> [1] FALSE
    s == Set$new(1, 2, 3)
    #> [1] TRUE
    s != c(Set$new(1,2,3), Set$new(1, 2))
    #> [1] FALSE  TRUE

    1:10 %inset% ConditionalSet$new(function(x) x %% 2 == 0)
    #>  [1] FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE

    # The `bound` argument in `isSubset` is used for specifying
    #   how open interval containedness should be checked
    i = Interval$new(1, 10, type = "(]")
    i$contains(Set$new(1), bound = FALSE)
    #> [1] FALSE
    i$contains(Set$new(10), bound = FALSE)
    #> [1] FALSE
    i$contains(Set$new(1), bound = TRUE)
    #> [1] FALSE
    i$contains(Set$new(10), bound = TRUE)
    #> [1] FALSE

## Algebra of Sets

`set6` includes the following operations:

- `setunion` (`+`) - Union of multiple sets
- `powerset` - Powerset of a given set
- `setpower` (`^`) - n-ary cartesian product of a given set
- `setcomplement` (`-`) - Relative complement, or set difference, of two sets
- `setintersect` (`&`) - Intersection of two sets
- `setproduct` (`*`) - Cartesian product of multiple sets
- `setsymdiff` (`%-%`) - Symmetric difference of two sets

We will look at the most common of these below.

### Union of Sets

The union of sets is defined the as the set of elements in all the sets of interest.

    Set$new(1) + Set$new(2) + Set$new(3)
    #> {1, 2, 3}
    Interval$new(1, 10) + Set$new(1) # no effect
    #> [1,10]
    setunion(Set$new(1,2), Interval$new(3, 10), Set$new(16))
    #> {1,...,2} ∪ [3,10] ∪ {16,...,16}

    PosReals$new() + NegReals$new()
    #> ℝ

### Relative Complement

The relative complement of two sets, \(A-B\), is defined as the set of elements in \(A\) but not in \(B\).

    Set$new(elements = 1:10) - Set$new(elements = 4:10)
    #> {1, 2, 3}
    Set$new(1,2,3,4) - Set$new(2)
    #> {1, 3, 4}

    Reals$new() - PosReals$new()
    #> ℝ-

    Interval$new(5, 10) - Interval$new(3, 12)
    #> ∅
    Interval$new(5, 10) - Interval$new(7, 12)
    #> [5,7)
    Interval$new(5, 10) - Interval$new(11, 12) # no effect
    #> [5,10]

### Cartesian Product

The cartesian product of multiple sets is often confused with the n-ary cartesian product, read the help page at `?setproduct` for a full description of the problem. Both forms are allowed in `set6` with the `nest` argument.

    Set$new(1, 2) * Set$new(3, 4)
    #> {1, 2} × {3, 4}
    Set$new(1, 2) * Set$new(3, 4) * Set$new(5, 6) # n-ary
    #> {1, 2} × {3, 4} × {5, 6}

    # nest = FALSE default - we will return to the `simplify` argument below
    setproduct(Set$new(1, 2), Set$new(3, 4), Set$new(5, 6), nest = TRUE, simplify = TRUE)
    #> {((1, 3), 5), ((1, 3), 6),...,((2, 4), 5), ((2, 4), 6)}
    setproduct(Set$new(1, 2), Set$new(3, 4), Set$new(5, 6), nest = FALSE, simplify = TRUE)
    #> {(1, 3, 5), (1, 3, 6),...,(2, 4, 5), (2, 4, 6)}

    # n-ary cartesian product on the same set
    setpower(Set$new(1,2), 3, simplify = TRUE)
    #> {(1, 1, 1), (1, 1, 2),...,(2, 2, 1), (2, 2, 2)}

### Intersection

The intersection of two sets is defined as the set of elements that lie in both sets.

    Set$new(1,2,3) & Set$new(3,5,6)
    #> {3}
    Set$new(5,6) & Reals$new()
    #> {5, 6}
    Set$new(1) & Set$new(2)
    #> ∅

## Wrappers

Finally we look briefly at wrappers, and the `simplify` argument. Each operation has an associated wrapper that will be created if `simplify == FALSE` or if the resulting set is too complicated to return as a single `Set` object. Wrappers faciliate lazy evaluation and symbolic representation by providing unique character representations of all sets after operations and do not evaluate the set elements unless specifically requested. In general wrappers should not be directly constructed but instead only used as the result of operations. The operations concerned with products, i.e. `setproduct`, `setpower`, `powerset`, all have `simplify == FALSE` as the default; whereas the others concerned with unions and differences, have `simplify == TRUE` as the default.

    # default: simplify = TRUE
    setunion(Set$new(1,2,3), Set$new(4,5))
    #> {1, 2,...,4, 5}
    setunion(Set$new(1,2,3), Set$new(4,5), simplify = FALSE)
    #> {1, 2, 3} ∪ {4, 5}

    # default: simplify = FALSE
    setproduct(Set$new(1,2), Set$new(4,5))
    #> {1, 2} × {4, 5}
    setproduct(Set$new(1,2), Set$new(4,5), simplify = TRUE)
    #> {(1, 4), (1, 5), (2, 4), (2, 5)}

    # default: simplify = FALSE
    powerset(Set$new(1,2,3))
    #> ℘({1, 2, 3})
    powerset(Set$new(1,2,3), simplify = TRUE)
    #> {{1, 2, 3}, {1, 2},...,{3}, ∅}

All wrappers inherit from `Set` and therefore share the same methods and fields.

    u = setunion(Set$new(1,2,3), Set$new(4,5), simplify = FALSE)
    c(2,5,8) %inset% u
    #> [1]  TRUE  TRUE FALSE

    p = Set$new(1,2) * Set$new(3,4)
    p$contains(Tuple$new(2, 4))
    #> [1] TRUE

## Going Forward

`set6` is still relatively slow compared to other sets packages and most short-term updates will focus on improving bottlenecks.

See the website for more tutorials and follow/star on GitHub for updates.