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).

- IsSet
- Set
- IsEqualSet
- AddSet
- RemoveSet
- UniteSet
- IntersectSet
- SubtractSet
- Set Functions for Sets
- More about Sets

`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

`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( [] ); [ ]

`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( `

is equivalent to `list1`, `list2` )`Set( `

(see Set), but the
former is more efficient.
`list1` ) = Set( `list2` )

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`

.

`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`

.

`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`

.

`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`

.

`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`

.

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.

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.

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).

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

02 Dec 2021