# 28 Sets

A very important mathematical concept, maybe the most important of all, are sets. Mathematically a set is an abstract object such that each object is either an element of the set or it is not. So a set is a collection like a list, and in fact GAP3 uses lists to represent sets. Note that this of course implies that GAP3 only deals with finite sets.

Unlike a list a set must not contain an element several times. It simply makes no sense to say that an object is twice an element of a set, because an object is either an element of a set, or it is not. Therefore the list that is used to represent a set has no duplicates, that is, no two elements of such a list are equal.

Also unlike a list a set does not impose any ordering on the elements. Again it simply makes no sense to say that an object is the first or second etc. element of a set, because, again, an object is either an element of a set, or it is not. Since ordering is not defined for a set we can put the elements in any order into the list used to represent the set. We put the elements sorted into the list, because this ordering is very practical. For example if we convert a list into a set we have to remove duplicates, which is very easy to do after we have sorted the list, since then equal elements will be next to each other.

In short sets are represented by sorted lists without holes and duplicates in GAP3. Such a list is in this document called a proper set. Note that we guarantee this representation, so you may make use of the fact that a set is represented by a sorted list in your functions.

In some contexts (for example see Combinatorics), we also want to talk about multisets. A multiset is like a set, except that an element may appear several times in a multiset. Such multisets are represented by sorted lists with holes that may have duplicates.

The first section in this chapter describes the functions to test if an object is a set and to convert objects to sets (see IsSet and Set).

The next section describes the function that tests if two sets are equal (see IsEqualSet).

The next sections describe the destructive functions that compute the standard set operations for sets (see AddSet, RemoveSet, UniteSet, IntersectSet, and SubtractSet).

The last section tells you more about sets and their internal representation (see More about Sets).

All set theoretic functions, especially `Intersection` and `Union`, also accept sets as arguments. Thus all functions described in chapter Domains are applicable to sets (see Set Functions for Sets).

Since sets are just a special case of lists, all the operations and functions for lists, especially the membership test (see In), can be used for sets just as well (see Lists).

## 28.1 IsSet

`IsSet( obj )`

`IsSet` returns `true` if the object obj is a set and `false` otherwise. An object is a set if it is a sorted lists without holes or duplicates. Will cause an error if evaluation of obj is an unbound variable.

```    gap> IsSet( [] );
true
gap> IsSet( [ 2, 3, 5, 7, 11 ] );
true
gap> IsSet( [, 2, 3,, 5,, 7,,,, 11 ] );
false        # this list contains holes
gap> IsSet( [ 11, 7, 5, 3, 2 ] );
false        # this list is not sorted
gap> IsSet( [ 2, 2, 3, 5, 5, 7, 11, 11 ] );
false        # this list contains duplicates
gap> IsSet( 235711 );
false        # this argument is not even a list ```

## 28.2 Set

`Set( list )`

`Set` returns a new proper set, which is represented as a sorted list without holes or duplicates, containing the elements of the list list.

`Set` returns a new list even if the list list is already a proper set, in this case it is equivalent to `ShallowCopy` (see ShallowCopy). Thus the result is a new list that is not identical to any other list. The elements of the result are however identical to elements of list. If list contains equal elements, it is not specified to which of those the element of the result is identical (see Identical Lists).

```    gap> Set( [3,2,11,7,2,,5] );
[ 2, 3, 5, 7, 11 ]
gap> Set( [] );
[  ] ```

## 28.3 IsEqualSet

`IsEqualSet( list1, list2 )`

`IsEqualSet` returns `true` if the two lists list1 and list2 are equal when viewed as sets, and `false` otherwise. list1 and list2 are equal if every element of list1 is also an element of list2 and if every element of list2 is also an element of list1.

If both lists are proper sets then they are of course equal if and only if they are also equal as lists. Thus `IsEqualSet( list1, list2 )` is equivalent to `Set( list1 ) = Set( list2 )` (see Set), but the former is more efficient.

```    gap> IsEqualSet( [2,3,5,7,11], [11,7,5,3,2] );
true
gap> IsEqualSet( [2,3,5,7,11], [2,3,5,7,11,13] );
false ```

`AddSet( set, elm )`

`AddSet` adds elm, which may be an elment of an arbitrary type, to the set set, which must be a proper set, otherwise an error will be signalled. If elm is already an element of the set set, the set is not changed. Otherwise elm is inserted at the correct position such that set is again a set afterwards.

```    gap> s := [2,3,7,11];;
gap> AddSet( s, 5 );  s;
[ 2, 3, 5, 7, 11 ]
gap> AddSet( s, 13 );  s;
[ 2, 3, 5, 7, 11, 13 ]
gap> AddSet( s, 3 );  s;
[ 2, 3, 5, 7, 11, 13 ] ```

`RemoveSet` (see RemoveSet) is the counterpart of `AddSet`.

## 28.5 RemoveSet

`RemoveSet( set, elm )`

`RemoveSet` removes the element elm, which may be an object of arbitrary type, from the set set, which must be a set, otherwise an error will be signalled. If elm is not an element of set nothing happens. If elm is an element it is removed and all the following elements in the list are moved one position forward.

```    gap> s := [ 2, 3, 4, 5, 6, 7 ];;
gap> RemoveSet( s, 6 );
gap> s;
[ 2, 3, 4, 5, 7 ]
gap> RemoveSet( s, 10 );
gap> s;
[ 2, 3, 4, 5, 7 ] ```

`AddSet` (see AddSet) is the counterpart of `RemoveSet`.

## 28.6 UniteSet

`UniteSet( set1, set2 )`

`UniteSet` unites the set set1 with the set set2. This is equivalent to adding all the elements in set2 to set1 (see AddSet). set1 must be a proper set, otherwise an error is signalled. set2 may also be list that is not a proper set, in which case `UniteSet` silently applies `Set` to it first (see Set). `UniteSet` returns nothing, it is only called to change set1.

```    gap> set := [ 2, 3, 5, 7, 11 ];;
gap> UniteSet( set, [ 4, 8, 9 ] );  set;
[ 2, 3, 4, 5, 7, 8, 9, 11 ]
gap> UniteSet( set, [ 16, 9, 25, 13, 16 ] );  set;
[ 2, 3, 4, 5, 7, 8, 9, 11, 13, 16, 25 ] ```

The function `UnionSet` (see Set Functions for Sets) is the nondestructive counterpart to the destructive procedure `UniteSet`.

## 28.7 IntersectSet

`IntersectSet( set1, set2 )`

`IntersectSet` intersects the set set1 with the set set2. This is equivalent to removing all the elements that are not in set2 from set1 (see RemoveSet). set1 must be a set, otherwise an error is signalled. set2 may be a list that is not a proper set, in which case `IntersectSet` silently applies `Set` to it first (see Set). `IntersectSet` returns nothing, it is only called to change set1.

```    gap> set := [ 2, 3, 4, 5, 7, 8, 9, 11, 13, 16 ];;
gap> IntersectSet( set, [ 3, 5, 7, 9, 11, 13, 15, 17 ] );  set;
[ 3, 5, 7, 9, 11, 13 ]
gap> IntersectSet( set, [ 9, 4, 6, 8 ] );  set;
[ 9 ] ```

The function `IntersectionSet` (see Set Functions for Sets) is the nondestructive counterpart to the destructive procedure `IntersectSet`.

## 28.8 SubtractSet

`SubtractSet( set1, set2 )`

`SubtractSet` subtracts the set set2 from the set set1. This is equivalent to removing all the elements in set2 from set1 (see RemoveSet). set1 must be a proper set, otherwise an error is signalled. set2 may be a list that is not a proper set, in which case `SubtractSet` applies `Set` to it first (see Set). `SubtractSet` returns nothing, it is only called to change set1.

```    gap> set := [ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];;
gap> SubtractSet( set, [ 6, 10 ] );  set;
[ 2, 3, 4, 5, 7, 8, 9, 11 ]
gap> SubtractSet( set, [ 9, 4, 6, 8 ] );  set;
[ 2, 3, 5, 7, 11 ] ```

The function `Difference` (see Difference) is the nondestructive counterpart to destructive the procedure `SubtractSet`.

## 28.9 Set Functions for Sets

As was already mentioned in the introduction to this chapter all domain functions also accept sets as arguments. Thus all functions described in the chapter Domains are applicable to sets. This section describes those functions where it might be helpful to know the implementation of those functions for sets.

`IsSubset( set1, set2 )`

This is implemented by `IsSubsetSet`, which you can call directly to save a little bit of time. Either argument to `IsSubsetSet` may also be a list that is not a proper set, in which case `IsSubset` silently applies `Set` (see Set) to it first.

`Union( set1, set2 )`

This is implemented by `UnionSet`, which you can call directly to save a little bit of time. Note that `UnionSet` only accepts two sets, unlike `Union`, which accepts several sets or a list of sets. The result of `UnionSet` is a new set, represented as a sorted list without holes or duplicates. Each argument to `UnionSet` may also be a list that is not a proper set, in which case `UnionSet` silently applies `Set` (see Set) to this argument. `UnionSet` is implemented in terms of its destructive counterpart `UniteSet` (see UniteSet).

`Intersection( set1, set2 )`

This is implemented by `IntersectionSet`, which you can call directly to save a little bit of time. Note that `IntersectionSet` only accepts two sets, unlike `Intersection`, which accepts several sets or a list of sets. The result of `IntersectionSet` is a new set, represented as a sorted list without holes or duplicates. Each argument to `IntersectionSet` may also be a list that is not a proper set, in which case `IntersectionSet` silently applies `Set` (see Set) to this argument. `IntersectionSet` is implemented in terms of its destructive counterpart `IntersectSet` (see IntersectSet).

The result of `IntersectionSet` and `UnionSet` is always a new list, that is not identical to any other list. The elements of that list however are identical to the corresponding elements of set1. If set1 is not a proper list it is not specified to which of a number of equal elements in set1 the element in the result is identical (see Identical Lists).

In the previous section we defined a proper set as a sorted list without holes or duplicates. This representation is not only nice to use, it is also a good internal representation supporting efficient algorithms. For example the `in` operator can use binary instead of a linear search since a set is sorted. For another example `Union` only has to merge the sets.

However, all those set functions also allow lists that are not proper sets, silently making a copy of it and converting this copy to a set. Suppose all the functions would have to test their arguments every time, comparing each element with its successor, to see if they are proper sets. This would chew up most of the performance advantage again. For example suppose `in` would have to run over the whole list, to see if it is a proper set, so it could use the binary search. That would be ridiculous.

To avoid this a list that is a proper set may, but need not, have an internal flag set that tells those functions that this list is indeed a proper set. Those functions do not have to check this argument then, and can use the more efficient algorithms. This section tells you when a proper set obtains this flag, so you can write your functions in such a way that you make best use of the algorithms.

The results of `Set`, `Difference`, `Intersection` and `Union` are known to be sets by construction, and thus have the flag set upon creation.

If an argument to `IsSet`, `IsEqualSet`, `IsSubset`, `Set`, `Difference`, `Intersection` or `Union` is a proper set, that does not yet have the flag set, those functions will notice that and set the flag for this set. Note that `in` will use linear search if the right operand does not have the flag set, will therefore not detect if it is a proper set and will, unlike the functions above, never set the flag.

If you change a proper set, that does have this flag set, by assignment, `Add` or `Append` the set will generally lose it flag, even if the change is such that the resulting list is still a proper set. However if the set has more than 100 elements and the value assigned or added is not a list and not a record and the resulting list is still a proper set than it will keep the flag. Note that changing a list that is not a proper set will never set the flag, even if the resulting list is a proper set. Such a set will obtain the flag only if it is passed to a set function.

Suppose you have built a proper set in such a way that it does not have the flag set, and that you now want to perform lots of membership tests. Then you should call `IsSet` with that set as an argument. If it is indeed a proper set `IsSet` will set the flag, and the subsequent `in` operations will use the more efficient binary search. You can think of the call to `IsSet` as a hint to GAP3 that this list is a proper set.

There is no way you can set the flag for an ordinary list without going through the checking in `IsSet`. The internal functions depend so much on the fact that a list with this flag set is indeed sorted and without holes and duplicates that the risk would be too high to allow setting the flag without such a check.

gap3-jm
24 Apr 2021