GAP (digraphs) - Chapter 3: Creating digraphs

Goto Chapter: Top 1 2 3 4 5 6 7 8 9 A Bib Ind
[Top of Book] [Contents] [Previous Chapter] [Next Chapter]

[MathJax on]

3 Creating digraphs
3.1 Creating digraphs
3.1-1 IsDigraph
3.1-2 IsMutableDigraph
3.1-3 IsImmutableDigraph
3.1-4 IsCayleyDigraph
3.1-5 IsDigraphWithAdjacencyFunction
3.1-6 DigraphByOutNeighboursType
3.1-7 Digraph
3.1-8 DigraphByAdjacencyMatrix
3.1-9 DigraphByEdges
3.1-10 EdgeOrbitsDigraph
3.1-11 DigraphByInNeighbours
3.1-12 CayleyDigraph
3.2 Changing representations
3.2-1 AsBinaryRelation
3.2-2 AsDigraph
3.2-3 Graph
3.2-4 AsGraph
3.2-5 AsTransformation
3.3 New digraphs from old
3.3-1 DigraphImmutableCopy
3.3-2 DigraphImmutableCopyIfImmutable
3.3-3 InducedSubdigraph
3.3-4 ReducedDigraph
3.3-5 MaximalSymmetricSubdigraph
3.3-6 MaximalAntiSymmetricSubdigraph
3.3-7 UndirectedSpanningForest
3.3-8 QuotientDigraph
3.3-9 DigraphReverse
3.3-10 DigraphDual
3.3-11 DigraphSymmetricClosure
3.3-12 DigraphTransitiveClosure
3.3-13 DigraphTransitiveReduction
3.3-14 DigraphAddVertex
3.3-15 DigraphAddVertices
3.3-16 DigraphAddEdge
3.3-17 DigraphAddEdgeOrbit
3.3-18 DigraphAddEdges
3.3-19 DigraphRemoveVertex
3.3-20 DigraphRemoveVertices
3.3-21 DigraphRemoveEdge
3.3-22 DigraphRemoveEdgeOrbit
3.3-23 DigraphRemoveEdges
3.3-24 DigraphRemoveLoops
3.3-25 DigraphRemoveAllMultipleEdges
3.3-26 DigraphReverseEdges
3.3-27 DigraphDisjointUnion
3.3-28 DigraphEdgeUnion
3.3-29 DigraphJoin
3.3-30 DigraphCartesianProduct
3.3-31 DigraphDirectProduct
3.3-32 DigraphCartesianProductProjections
3.3-33 DigraphDirectProductProjections
3.3-34 LineDigraph
3.3-35 LineUndirectedDigraph
3.3-36 DoubleDigraph
3.3-37 BipartiteDoubleDigraph
3.3-38 DigraphAddAllLoops
3.3-39 DistanceDigraph
3.3-40 DigraphClosure
3.3-41 DigraphMycielskian
3.4 Random digraphs
3.4-1 RandomDigraph
3.4-2 RandomMultiDigraph
3.4-3 RandomTournament
3.4-4 RandomLattice
3.5 Standard examples
3.5-1 ChainDigraph
3.5-2 CompleteDigraph
3.5-3 CompleteBipartiteDigraph
3.5-4 CompleteMultipartiteDigraph
3.5-5 CycleDigraph
3.5-6 EmptyDigraph
3.5-7 JohnsonDigraph
3.5-8 PetersenGraph
3.5-9 GeneralisedPetersenGraph

### 3 Creating digraphs

In this chapter we describe how to create digraphs.

#### 3.1 Creating digraphs

##### 3.1-1 IsDigraph

`‣ IsDigraph` | ( category )

Every digraph in Digraphs belongs to the category `IsDigraph`. Some basic attributes and operations for digraphs are `DigraphVertices` (5.1-1), `DigraphEdges` (5.1-3), and `OutNeighbours` (5.2-6).

##### 3.1-2 IsMutableDigraph

`‣ IsMutableDigraph` | ( category )

`IsMutableDigraph` is a synonym for `IsDigraph` (3.1-1) and `IsMutable` (Reference: IsMutable). A mutable digraph may be changed in-place by methods in the Digraphs package, and is not attribute-storing – see `IsAttributeStoringRep` (Reference: IsAttributeStoringRep).

A mutable digraph may be converted into an immutable attribute-storing digraph by calling `MakeImmutable` (Reference: MakeImmutable) on the digraph.

##### 3.1-3 IsImmutableDigraph

`‣ IsImmutableDigraph` | ( category )

`IsImmutableDigraph` is a subcategory of `IsDigraph` (3.1-1). Digraphs that lie in `IsImmutableDigraph` are immutable and attribute-storing. In particular, they lie in `IsAttributeStoringRep` (Reference: IsAttributeStoringRep).

A mutable digraph may be converted to an immutable digraph that lies in the category `IsImmutableDigraph` by calling `MakeImmutable` (Reference: MakeImmutable) on the digraph.

The operation `DigraphMutableCopy` (3.3-1) can be used to construct a mutable copy of an immutable digraph. It is however not possible to convert an immutable digraph into a mutable digraph in-place.

##### 3.1-4 IsCayleyDigraph

`‣ IsCayleyDigraph` | ( category )

`IsCayleyDigraph` is a subcategory of `IsDigraph`. Digraphs that are Cayley digraphs of a group and that are constructed by the operation `CayleyDigraph` (3.1-12) are constructed in this category, and are always immutable.

##### 3.1-5 IsDigraphWithAdjacencyFunction

`‣ IsDigraphWithAdjacencyFunction` | ( category )

`IsDigraphWithAdjacencyFunction` is a subcategory of `IsDigraph`. Digraphs that are created using an adjacency function are constructed in this category.

##### 3.1-6 DigraphByOutNeighboursType

`‣ DigraphByOutNeighboursType` | ( global variable )

`‣ DigraphFamily` | ( family )

The type of all digraphs is `DigraphByOutNeighboursType`. The family of all digraphs is `DigraphFamily`.

##### 3.1-7 Digraph

`‣ Digraph`( [filt, ]obj[, source, range] ) | ( operation )

`‣ Digraph`( [filt, ]list, func ) | ( operation )

`‣ Digraph`( [filt, ]G, list, act, adj ) | ( operation )

Returns: A digraph.

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

for a list (i.e. an adjacency list)

  if obj is a list of lists of positive integers in the range from `1` to `Length(obj)`, then this function returns the digraph with vertices E ^ 0 =`[1 .. Length(obj)]`, and edges corresponding to the entries of obj.

  More precisely, there is an edge from vertex `i` to `j` if and only if `j` is in `obj[i]`; the source of this edge is `i` and the range is `j`. If `j` occurs in `obj[i]` with multiplicity `k`, then there are `k` edges from `i` to `j`.

for three lists

  if obj is a duplicate-free list, and source and range are lists of equal length consisting of positive integers in the list `[1 .. Length(obj)]`, then this function returns a digraph with vertices E ^ 0 =`[1 .. Length(obj)]`, and `Length(source)` edges. For each `i` in `[1 .. Length(source)]` there exists an edge with source vertex `source[i]` and range vertex `range[i]`. See `DigraphSource` (5.2-5) and `DigraphRange` (5.2-5).

  The vertices of the digraph will be labelled by the elements of obj.

for an integer, and two lists

  if obj is an integer, and source and range are lists of equal length consisting of positive integers in the list `[1 .. obj]`, then this function returns a digraph with vertices E ^ 0 =`[1 .. obj]`, and `Length(source)` edges. For each `i` in `[1 .. Length(source)]` there exists an edge with source vertex `source[i]` and range vertex `range[i]`. See `DigraphSource` (5.2-5) and `DigraphRange` (5.2-5).

for a list and a function

  if list is a list and func is a function taking 2 arguments that are elements of list, and func returns `true` or `false`, then this operation creates a digraph with vertices `[1 .. Length(list)]` and an edge from vertex `i` to vertex `j` if and only if `func(list[i], list[j])` returns `true`.

for a group, a list, and two functions

  The arguments will be G, list, act, adj.

  Let G be a group acting on the objects in list via the action act, and let adj be a function taking two objects from list as arguments and returning `true` or `false`. The function adj will describe the adjacency between objects from list, which is invariant under the action of G. This variant of the constructor returns a digraph with vertices the objects of list and directed edges `[x, y]` when `f(x, y)` is `true`.

  The action of the group G on the objects in list is stored in the attribute `DigraphGroup` (7.2-10), and is used to speed up operations like `DigraphDiameter` (5.3-1).

for a Grape package graph

  if obj is a Grape package graph (i.e. a record for which the function `IsGraph` returns `true`), then this function returns a digraph isomorphic to obj.

for a binary relation

  if obj is a binary relation on the points `[1 .. n]` for some posititve integer n, then this function returns the digraph defined by obj. Specifically, this function returns a digraph which has n vertices, and which has an edge with source `i` and range `j` if and only if `[i,j]` is a pair in the binary relation obj.

    gap> gr := Digraph([
    > [2, 5, 8, 10], [2, 3, 4, 2, 5, 6, 8, 9, 10], [1],
    > [3, 5, 7, 8, 10], [2, 5, 7], [3, 6, 7, 9, 10], [1, 4],
    > [1, 5, 9], [1, 2, 7, 8], [3, 5]]);
    <immutable multidigraph with 10 vertices, 38 edges>
    gap> gr := Digraph(["a", "b", "c"], ["a"], ["b"]);
    <immutable digraph with 3 vertices, 1 edge>
    gap> gr := Digraph(5, [1, 2, 2, 4, 1, 1], [2, 3, 5, 5, 1, 1]);
    <immutable multidigraph with 5 vertices, 6 edges>
    gap> Petersen := Graph(SymmetricGroup(5), [[1, 2]], OnSets,
    > function(x, y) return Intersection(x, y) = []; end);;
    gap> Digraph(Petersen);
    <immutable digraph with 10 vertices, 30 edges>
    gap> gr := Digraph([1 .. 10], ReturnTrue);
    <immutable digraph with 10 vertices, 100 edges>

The next example illustrates the uses of the fourth and fifth variants of this constructor. The resulting digraph is a strongly regular graph, and it is actually the point graph of the van Lint-Schrijver partial geometry, [vLS81]. The algebraic description is taken from the seminal paper of Calderbank and Kantor [CK86].

    gap> f := GF(3 ^ 4);
    GF(3^4)
    gap> gamma := First(f, x -> Order(x) = 5);
    Z(3^4)^64
    gap> L := Union([Zero(f)], List(Group(gamma)));
    [ 0*Z(3), Z(3)^0, Z(3^4)^16, Z(3^4)^32, Z(3^4)^48, Z(3^4)^64 ]
    gap> omega := Union(List(L, x -> List(Difference(L, [x]), y -> x - y)));
    [ Z(3)^0, Z(3), Z(3^4)^5, Z(3^4)^7, Z(3^4)^8, Z(3^4)^13, Z(3^4)^15,
      Z(3^4)^16, Z(3^4)^21, Z(3^4)^23, Z(3^4)^24, Z(3^4)^29, Z(3^4)^31,
      Z(3^4)^32, Z(3^4)^37, Z(3^4)^39, Z(3^4)^45, Z(3^4)^47, Z(3^4)^48,
      Z(3^4)^53, Z(3^4)^55, Z(3^4)^56, Z(3^4)^61, Z(3^4)^63, Z(3^4)^64,
      Z(3^4)^69, Z(3^4)^71, Z(3^4)^72, Z(3^4)^77, Z(3^4)^79 ]
    gap> adj := function(x, y)
    >   return x - y in omega;
    > end;
    function( x, y ) ... end
    gap> digraph := Digraph(AsList(f), adj);
    <immutable digraph with 81 vertices, 2430 edges>
    gap> group := Group(Z(3));;
    gap> act := \*;
    <Operation "*">
    gap> digraph := Digraph(group, List(f), act, adj);
    <immutable digraph with 81 vertices, 2430 edges>

##### 3.1-8 DigraphByAdjacencyMatrix

`‣ DigraphByAdjacencyMatrix`( [filt, ]list ) | ( operation )

Returns: A digraph.

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

If list is the adjacency matrix of a digraph in the sense of `AdjacencyMatrix` (5.2-1), then this operation returns the digraph which is defined by list.

Alternatively, if list is a square boolean matrix, then this operation returns the digraph with `Length(`list`)` vertices which has the edge `[i,j]` if and only if list`[i][j]` is `true`.

    gap> DigraphByAdjacencyMatrix([
    > [0, 1, 0, 2, 0],
    > [1, 1, 1, 0, 1],
    > [0, 3, 2, 1, 1],
    > [0, 0, 1, 0, 1],
    > [2, 0, 0, 0, 0]]);
    <immutable multidigraph with 5 vertices, 18 edges>
    gap> D := DigraphByAdjacencyMatrix([
    > [true, false, true],
    > [false, false, true],
    > [false, true, false]]);
    <immutable digraph with 3 vertices, 4 edges>
    gap> OutNeighbours(D);
    [ [ 1, 3 ], [ 3 ], [ 2 ] ]
    gap> D := DigraphByAdjacencyMatrix(IsMutableDigraph,
    > [[true, false, true],
    >  [false, false, true],
    >  [false, true, false]]);
    <mutable digraph with 3 vertices, 4 edges>

##### 3.1-9 DigraphByEdges

`‣ DigraphByEdges`( [filt, ]list[, n] ) | ( operation )

Returns: A digraph.

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

If list is list of pairs of positive integers, then this function returns the digraph with the minimum number of vertices `m` such that its list equal list.

If the optional second argument n is a positive integer with `n >= m` (with `m` defined as above), then this function returns the digraph with n vertices and list list.

See `DigraphEdges` (5.1-3).

    gap> DigraphByEdges(
    > [[1, 3], [2, 1], [2, 3], [2, 5], [3, 6],
    >  [4, 6], [5, 2], [5, 4], [5, 6], [6, 6]]);
    <immutable digraph with 6 vertices, 10 edges>
    gap> DigraphByEdges(
    > [[1, 3], [2, 1], [2, 3], [2, 5], [3, 6],
    >  [4, 6], [5, 2], [5, 4], [5, 6], [6, 6]], 12);
    <immutable digraph with 12 vertices, 10 edges>
    gap> DigraphByEdges(IsMutableDigraph,
    > [[1, 3], [2, 1], [2, 3], [2, 5], [3, 6],
    >  [4, 6], [5, 2], [5, 4], [5, 6], [6, 6]], 12);
    <mutable digraph with 12 vertices, 10 edges>

##### 3.1-10 EdgeOrbitsDigraph

`‣ EdgeOrbitsDigraph`( G, edges[, n] ) | ( operation )

Returns: An immutable digraph.

If G is a permutation group, edges is an edge or list of edges, and n is a non-negative integer such that G fixes `[1 .. n]` setwise, then this operation returns an immutable digraph with n vertices and the union of the orbits of the edges in edges under the action of the permutation group G. An edge in this context is simply a pair of positive integers.

If the optional third argument n is not present, then the largest moved point of the permutation group G is used by default.

    gap> digraph := EdgeOrbitsDigraph(Group((1, 3), (1, 2)(3, 4)),
    >                                 [[1, 2], [4, 5]], 5);
    <immutable digraph with 5 vertices, 12 edges>
    gap> OutNeighbours(digraph);
    [ [ 2, 4, 5 ], [ 1, 3, 5 ], [ 2, 4, 5 ], [ 1, 3, 5 ], [  ] ]
    gap> RepresentativeOutNeighbours(digraph);
    [ [ 2, 4, 5 ], [  ] ]

##### 3.1-11 DigraphByInNeighbours

`‣ DigraphByInNeighbours`( [filt, ]list ) | ( operation )

`‣ DigraphByInNeighbors`( [filt, ]list ) | ( operation )

Returns: A digraph.

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

If list is a list of lists of positive integers list the range `[1 .. Length(list)]`, then this function returns the digraph with vertices E^0=`[1 .. Length(list)]`, and edges corresponding to the entries of list. More precisely, there is an edge with source vertex `i` and range vertex `j` if `i` is list `list[j]`.

If `i` occurs list `list[j]` with multiplicity `k`, then there are `k` multiple edges from `i` to `j`.

See `InNeighbours` (5.2-7).

    gap> D := DigraphByInNeighbours([
    > [2, 5, 8, 10], [2, 3, 4, 5, 6, 8, 9, 10],
    > [1], [3, 5, 7, 8, 10], [2, 5, 7], [3, 6, 7, 9, 10], [1, 4],
    > [1, 5, 9], [1, 2, 7, 8], [3, 5]]);
    <immutable digraph with 10 vertices, 37 edges>
    gap> D := DigraphByInNeighbours([[2, 3, 2], [1], [1, 2, 3]]);
    <immutable multidigraph with 3 vertices, 7 edges>
    gap> D := DigraphByInNeighbours(IsMutableDigraph,
    >                               [[2, 3, 2], [1], [1, 2, 3]]);
    <mutable multidigraph with 3 vertices, 7 edges>

##### 3.1-12 CayleyDigraph

`‣ CayleyDigraph`( G[, gens] ) | ( operation )

Returns: An immutable digraph.

Let G be any group and let gens be a list of elements of G. This operation returns an immutable digraph that corresponds to the Cayley graph of G with respect gens. The vertices are the elements of G. There exists an edge from the vertex `u` to the vertex `v` if and only if there exists a generator `g` in gens such that `x * g = y`.

If the optional second argument gens is not present, then the generators of G are used by default.

The digraph created by this operation belongs to the category `IsCayleyDigraph` (3.1-4), the group G can be recovered from the digraph using `GroupOfCayleyDigraph` (5.4-1), and the generators gens can be obtained using `GeneratorsOfCayleyDigraph` (5.4-2).

Note that this function can only return an immutable digraph.

    gap> G := DihedralGroup(8);
    <pc group of size 8 with 3 generators>
    gap> CayleyDigraph(G);
    <immutable digraph with 8 vertices, 24 edges>
    gap> G := DihedralGroup(IsPermGroup, 8);
    Group([ (1,2,3,4), (2,4) ])
    gap> CayleyDigraph(G);
    <immutable digraph with 8 vertices, 16 edges>
    gap> digraph := CayleyDigraph(G, [()]);
    <immutable digraph with 8 vertices, 8 edges>
    gap> GroupOfCayleyDigraph(digraph) = G;
    true
    gap> GeneratorsOfCayleyDigraph(digraph);
    [ () ]

#### 3.2 Changing representations

##### 3.2-1 AsBinaryRelation

`‣ AsBinaryRelation`( digraph ) | ( operation )

Returns: A binary relation.

If digraph is a digraph with a positive number of vertices n, and no multiple edges, then this operation returns a binary relation on the points `[1..n]`. The pair `[i,j]` is in the binary relation if and only if `[i,j]` is an edge in digraph.

    gap> D := Digraph([[3, 2], [1, 2], [2], [3, 4]]);
    <immutable digraph with 4 vertices, 7 edges>
    gap> AsBinaryRelation(D);
    Binary Relation on 4 points

##### 3.2-2 AsDigraph

`‣ AsDigraph`( [filt, ]trans[, n] ) | ( operation )

Returns: A digraph, or `fail`.

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

If trans is a transformation, and n is a non-negative integer such that the restriction of trans to `[1 .. n]` defines a transformation of `[1 .. n]`, then `AsDigraph` returns the functional digraph with n vertices defined by trans. See `IsFunctionalDigraph` (6.1-9).

Specifically, the digraph returned by `AsDigraph` has n edges: for each vertex `x` in `[1 .. n]`, there is a unique edge with source `x`; this edge has range `x^trans`.

If the optional second argument n is not supplied, then the degree of the transformation trans is used by default. If the restriction of trans to `[1 .. n]` does not define a transformation of `[1 .. n]`, then `AsDigraph(trans, n)` returns `fail`.

    gap> f := Transformation([4, 3, 3, 1, 7, 9, 10, 4, 2, 3]);
    Transformation( [ 4, 3, 3, 1, 7, 9, 10, 4, 2, 3 ] )
    gap> AsDigraph(f);
    <immutable functional digraph with 10 vertices>
    gap> AsDigraph(f, 4);
    <immutable functional digraph with 4 vertices>
    gap> AsDigraph(f, 5);
    fail
    gap> b := BinaryRelationOnPoints(
    > [[3], [1, 3, 5], [1], [1, 2, 4], [2, 3, 5]]);
    Binary Relation on 5 points
    gap> D := AsDigraph(b);
    <immutable digraph with 5 vertices, 11 edges>

##### 3.2-3 Graph

`‣ Graph`( digraph ) | ( operation )

Returns: A Grape package graph.

If digraph is a mutable or immutable digraph without multiple edges, then this operation returns a Grape package graph that is isomorphic to digraph.

If digraph is a multidigraph, then since Grape does not support multiple edges, the multiple edges will be reduced to a single edge in the result. In order words, for a multidigraph this operation will return the same as `Graph(DigraphRemoveAllMultipleEdges(`digraph`))`.

    gap> Petersen := Graph(SymmetricGroup(5), [[1, 2]], OnSets,
    > function(x, y) return Intersection(x, y) = []; end);;
    gap> Display(Petersen);
    rec(
      adjacencies := [ [ 3, 5, 8 ] ],
      group :=
       Group( [ ( 1, 2, 3, 5, 7)( 4, 6, 8, 9,10), ( 2, 4)( 6, 9)( 7,10)
         ] ),
      isGraph := true,
      names := [ [ 1, 2 ], [ 2, 3 ], [ 3, 4 ], [ 1, 3 ], [ 4, 5 ],
          [ 2, 4 ], [ 1, 5 ], [ 3, 5 ], [ 1, 4 ], [ 2, 5 ] ],
      order := 10,
      representatives := [ 1 ],
      schreierVector := [ -1, 1, 1, 2, 1, 1, 1, 1, 2, 2 ] )
    gap> Digraph(Petersen);
    <immutable digraph with 10 vertices, 30 edges>
    gap> Graph(last) = Petersen;
    true

##### 3.2-4 AsGraph

`‣ AsGraph`( digraph ) | ( attribute )

Returns: A Grape package graph.

If digraph is a digraph, then this method returns the same as `Graph` (3.2-3), except that if digraph is immutable, then the result will be stored as a mutable attribute of digraph. In this latter case, when `AsGraph(`digraph`)` is called subsequently, the same GAP object will be returned as before.

    gap> D := Digraph([[1, 2], [3], []]);
    <immutable digraph with 3 vertices, 3 edges>
    gap> G := AsGraph(D);
    rec( adjacencies := [ [ 1, 2 ], [ 3 ], [  ] ], group := Group(()),
      isGraph := true, names := [ 1 .. 3 ], order := 3,
      representatives := [ 1, 2, 3 ], schreierVector := [ -1, -2, -3 ] )

##### 3.2-5 AsTransformation

`‣ AsTransformation`( digraph ) | ( attribute )

Returns: A transformation, or `fail`

If digraph is a functional digraph, then `AsTransformation` returns the transformation which is defined by digraph. See `IsFunctionalDigraph` (6.1-9). Otherwise, `AsTransformation(`digraph`)` returns `fail`.

If digraph is a functional digraph with n vertices, then `AsTransformation(`digraph`)` will return the transformation `f` of degree at most n where for each 1 ≤ i ≤ n, `i ^ f` is equal to the unique out-neighbour of vertex `i` in digraph.

    gap> D := Digraph([[1], [3], [2]]);
    <immutable digraph with 3 vertices, 3 edges>
    gap> AsTransformation(D);
    Transformation( [ 1, 3, 2 ] )
    gap> D := CycleDigraph(IsMutableDigraph, 3);
    <mutable digraph with 3 vertices, 3 edges>
    gap> AsTransformation(D);
    Transformation( [ 2, 3, 1 ] )
    gap> AsPermutation(last);
    (1,2,3)
    gap> D := Digraph([[2, 3], [], []]);
    <immutable digraph with 3 vertices, 2 edges>
    gap> AsTransformation(D);
    fail

#### 3.3 New digraphs from old

##### 3.3-1 DigraphImmutableCopy

`‣ DigraphImmutableCopy`( digraph ) | ( operation )

`‣ DigraphMutableCopy`( digraph ) | ( operation )

`‣ DigraphCopySameMutability`( digraph ) | ( operation )

`‣ DigraphCopy`( digraph ) | ( operation )

Returns: A digraph.

Each of these operations returns a new copy of digraph, of the appropriate mutability, retaining none of the attributes or properties of digraph.

`DigraphCopy` is a synonym for `DigraphCopySameMutability`.

    gap> D := CycleDigraph(10);
    <immutable cycle digraph with 10 vertices>
    gap> DigraphCopy(D) = D;
    true
    gap> IsIdenticalObj(DigraphCopy(D), D);
    false
    gap> DigraphMutableCopy(D);
    <mutable digraph with 10 vertices, 10 edges>

##### 3.3-2 DigraphImmutableCopyIfImmutable

`‣ DigraphImmutableCopyIfImmutable`( digraph ) | ( operation )

`‣ DigraphImmutableCopyIfMutable`( digraph ) | ( operation )

`‣ DigraphMutableCopyIfMutable`( digraph ) | ( operation )

`‣ DigraphMutableCopyIfImmutable`( digraph ) | ( operation )

Returns: A digraph.

Each of these operations returns either the original argument digraph, or a new copy of digraph of the appropriate mutability, according to the mutability of digraph.

    gap> C := CycleDigraph(10);
    <immutable cycle digraph with 10 vertices>
    gap> D := DigraphImmutableCopyIfImmutable(C);
    <immutable digraph with 10 vertices, 10 edges>
    gap> IsIdenticalObj(C, D);
    false
    gap> C = D;
    true
    gap> D := DigraphImmutableCopyIfMutable(C);
    <immutable cycle digraph with 10 vertices>
    gap> IsIdenticalObj(C, D);
    true
    gap> C = D;
    true
    gap> D := DigraphMutableCopyIfMutable(C);
    <immutable cycle digraph with 10 vertices>
    gap> IsMutableDigraph(D);
    false
    gap> D := DigraphMutableCopyIfImmutable(C);
    <mutable digraph with 10 vertices, 10 edges>
    gap> IsMutableDigraph(D);
    true
    gap> C := CycleDigraph(IsMutableDigraph, 10);
    <mutable digraph with 10 vertices, 10 edges>
    gap> D := DigraphImmutableCopyIfImmutable(C);
    <mutable digraph with 10 vertices, 10 edges>
    gap> IsIdenticalObj(C, D);
    true
    gap> C = D;
    true
    gap> D := DigraphImmutableCopyIfMutable(C);
    <immutable digraph with 10 vertices, 10 edges>
    gap> IsIdenticalObj(C, D);
    false
    gap> C = D;
    true
    gap> D := DigraphMutableCopyIfMutable(C);
    <mutable digraph with 10 vertices, 10 edges>
    gap> IsMutableDigraph(D);
    true
    gap> D := DigraphMutableCopyIfImmutable(C);
    <mutable digraph with 10 vertices, 10 edges>
    gap> IsIdenticalObj(C, D);
    true
    gap> IsMutableDigraph(D);
    true

##### 3.3-3 InducedSubdigraph

`‣ InducedSubdigraph`( digraph, verts ) | ( operation )

Returns: A digraph.

If digraph is a digraph, and verts is a subset of the vertices of digraph, then this operation returns a digraph constructed from digraph by retaining precisely those vertices in verts, and those edges whose source and range vertices are both contained in verts.

The vertices of the induced subdigraph are `[1..Length(verts)]` but the original vertex labels can be accessed via `DigraphVertexLabels` (5.1-9).

If digraph belongs to `IsMutableDigraph` (3.1-2), then digraph is modified in place. If digraph belongs to `IsImmutableDigraph` (3.1-3), a new immutable digraph containing the appropriate vertices and edges is returned.

    gap> D := Digraph([[1, 1, 2, 3, 4, 4], [1, 3, 4], [3, 1], [1, 1]]);
    <immutable multidigraph with 4 vertices, 13 edges>
    gap> InducedSubdigraph(D, [1, 3, 4]);
    <immutable multidigraph with 3 vertices, 9 edges>
    gap> DigraphVertices(last);
    [ 1 .. 3 ]
    gap> D := DigraphMutableCopy(D);
    <mutable multidigraph with 4 vertices, 13 edges>
    gap> new := InducedSubdigraph(D, [1, 3, 4]);
    <mutable multidigraph with 3 vertices, 9 edges>
    gap> D = new;
    true

##### 3.3-4 ReducedDigraph

`‣ ReducedDigraph`( digraph ) | ( operation )

`‣ ReducedDigraphAttr`( digraph ) | ( attribute )

Returns: A digraph.

This function returns a digraph isomorphic to the subdigraph of digraph induced by the set of non-isolated vertices, i.e. the set of those vertices of digraph which are the source or range of some edge in digraph. See `InducedSubdigraph` (3.3-3).

The ordering of the remaining vertices of digraph is preserved, as are the labels of the remaining vertices and edges; see `DigraphVertexLabels` (5.1-9) and `DigraphEdgeLabels` (5.1-11). This can allow one to match a vertex in the reduced digraph to the corresponding vertex in digraph.

If digraph is immutable, then a new immutable digraph is returned. Otherwise, the isolated vertices of the mutable digraph digraph are removed in-place.

    gap> D := Digraph([[1, 2], [], [], [1, 4], []]);
    <immutable digraph with 5 vertices, 4 edges>
    gap> R := ReducedDigraph(D);
    <immutable digraph with 3 vertices, 4 edges>
    gap> OutNeighbours(R);
    [ [ 1, 2 ], [  ], [ 1, 3 ] ]
    gap> DigraphEdges(D);
    [ [ 1, 1 ], [ 1, 2 ], [ 4, 1 ], [ 4, 4 ] ]
    gap> DigraphEdges(R);
    [ [ 1, 1 ], [ 1, 2 ], [ 3, 1 ], [ 3, 3 ] ]
    gap> DigraphVertexLabel(R, 3);
    4
    gap> DigraphVertexLabel(R, 2);
    2
    gap> D := Digraph(IsMutableDigraph, [[], [3], [2]]);
    <mutable digraph with 3 vertices, 2 edges>
    gap> ReducedDigraph(D);
    <mutable digraph with 2 vertices, 2 edges>
    gap> D;
    <mutable digraph with 2 vertices, 2 edges>

##### 3.3-5 MaximalSymmetricSubdigraph

`‣ MaximalSymmetricSubdigraph`( digraph ) | ( operation )

`‣ MaximalSymmetricSubdigraphAttr`( digraph ) | ( attribute )

`‣ MaximalSymmetricSubdigraphWithoutLoops`( digraph ) | ( operation )

`‣ MaximalSymmetricSubdigraphWithoutLoopsAttr`( digraph ) | ( attribute )

Returns: A digraph.

If digraph is a digraph, then `MaximalSymmetricSubdigraph` returns a symmetric digraph without multiple edges which has the same vertex set as digraph, and whose edge list is formed from digraph by ignoring the multiplicity of edges, and by ignoring edges `[u,v]` for which there does not exist an edge `[v,u]`.

The digraph returned by `MaximalSymmetricSubdigraphWithoutLoops` is the same, except that loops are removed.

If digraph is immutable, then a new immutable digraph is returned. Otherwise, the mutable digraph digraph is changed in-place into such a digraph described above.

See `IsSymmetricDigraph` (6.1-12), `IsMultiDigraph` (6.1-10), and `DigraphHasLoops` (6.1-1) for more information.

    gap> D := Digraph([[2, 2], [1, 3], [4], [3, 1]]);
    <immutable multidigraph with 4 vertices, 7 edges>
    gap> not IsSymmetricDigraph(D) and IsMultiDigraph(D);
    true
    gap> OutNeighbours(D);
    [ [ 2, 2 ], [ 1, 3 ], [ 4 ], [ 3, 1 ] ]
    gap> S := MaximalSymmetricSubdigraph(D);
    <immutable symmetric digraph with 4 vertices, 4 edges>
    gap> IsSymmetricDigraph(S) and not IsMultiDigraph(S);
    true
    gap> OutNeighbours(S);
    [ [ 2 ], [ 1 ], [ 4 ], [ 3 ] ]
    gap> D := CycleDigraph(IsMutableDigraph, 3);
    <mutable digraph with 3 vertices, 3 edges>
    gap> MaximalSymmetricSubdigraph(D);
    <mutable empty digraph with 3 vertices>
    gap> D;
    <mutable empty digraph with 3 vertices>

##### 3.3-6 MaximalAntiSymmetricSubdigraph

`‣ MaximalAntiSymmetricSubdigraph`( digraph ) | ( operation )

`‣ MaximalAntiSymmetricSubdigraphAttr`( digraph ) | ( attribute )

Returns: A digraph.

If digraph is a digraph, then `MaximalAntiSymmetricSubdigraph` returns an anti-symmetric subdigraph of digraph formed by retaining the vertices of digraph, discarding any duplicate edges, and discarding any edge `[i,j]` of digraph where `i > j` and the reverse edge `[j,i]` is an edge of digraph. In other words, for every symmetric pair of edges `[i,j]` and `[j,i]` in digraph, where `i` and `j` are distinct, it discards the the edge [max(i,j),min(i,j)].

If digraph is immutable, then a new immutable digraph is returned. Otherwise, the mutable digraph digraph is changed in-place.

See `IsAntisymmetricDigraph` (6.1-2) for more information.

    gap> D := Digraph([[2, 2], [1, 3], [4], [3, 1]]);
    <immutable multidigraph with 4 vertices, 7 edges>
    gap> not IsAntiSymmetricDigraph(D) and IsMultiDigraph(D);
    true
    gap> OutNeighbours(D);
    [ [ 2, 2 ], [ 1, 3 ], [ 4 ], [ 3, 1 ] ]
    gap> D := MaximalAntiSymmetricSubdigraph(D);
    <immutable antisymmetric digraph with 4 vertices, 4 edges>
    gap> IsAntiSymmetricDigraph(D) and not IsMultiDigraph(D);
    true
    gap> OutNeighbours(D);
    [ [ 2 ], [ 3 ], [ 4 ], [ 1 ] ]
    gap> D := Digraph(IsMutableDigraph, [[2], [1]]);
    <mutable digraph with 2 vertices, 2 edges>
    gap> MaximalAntiSymmetricSubdigraph(D);
    <mutable digraph with 2 vertices, 1 edge>
    gap> D;
    <mutable digraph with 2 vertices, 1 edge>

##### 3.3-7 UndirectedSpanningForest

`‣ UndirectedSpanningForest`( digraph ) | ( operation )

`‣ UndirectedSpanningForestAttr`( digraph ) | ( attribute )

`‣ UndirectedSpanningTree`( digraph ) | ( operation )

`‣ UndirectedSpanningTreeAttr`( digraph ) | ( attribute )

Returns: A digraph, or `fail`.

If digraph is a digraph with at least one vertex, then `UndirectedSpanningForest` returns an undirected spanning forest of digraph, otherwise this attribute returns `fail`. See `IsUndirectedSpanningForest` (4.1-2) for the definition of an undirected spanning forest.

If digraph is a digraph with at least one vertex and whose `MaximalSymmetricSubdigraph` (3.3-5) is connected (see `IsConnectedDigraph` (6.3-3)), then `UndirectedSpanningTree` returns an undirected spanning tree of digraph, otherwise this attribute returns `fail`. See `IsUndirectedSpanningTree` (4.1-2) for the definition of an undirected spanning tree.

If digraph is immutable, then an immutable digraph is returned. Otherwise, the mutable digraph digraph is changed in-place into an undirected spanning tree of digraph.

Note that for an immutable digraph that has known undirected spanning tree, the attribute `UndirectedSpanningTree` returns the same digraph as the attribute `UndirectedSpanningForest`.

    gap> D := Digraph([[1, 2, 1, 3], [1], [4], [3, 4, 3]]);
    <immutable multidigraph with 4 vertices, 9 edges>
    gap> UndirectedSpanningTree(D);
    fail
    gap> forest := UndirectedSpanningForest(D);
    <immutable symmetric digraph with 4 vertices, 4 edges>
    gap> OutNeighbours(forest);
    [ [ 2 ], [ 1 ], [ 4 ], [ 3 ] ]
    gap> IsUndirectedSpanningForest(D, forest);
    true
    gap> DigraphConnectedComponents(forest).comps;
    [ [ 1, 2 ], [ 3, 4 ] ]
    gap> DigraphConnectedComponents(MaximalSymmetricSubdigraph(D)).comps;
    [ [ 1, 2 ], [ 3, 4 ] ]
    gap> UndirectedSpanningForest(MaximalSymmetricSubdigraph(D))
    > = forest;
    true
    gap> D := CompleteDigraph(4);
    <immutable complete digraph with 4 vertices>
    gap> tree := UndirectedSpanningTree(D);
    <immutable symmetric digraph with 4 vertices, 6 edges>
    gap> IsUndirectedSpanningTree(D, tree);
    true
    gap> tree = UndirectedSpanningForest(D);
    true
    gap> UndirectedSpanningForest(EmptyDigraph(0));
    fail
    gap> D := PetersenGraph(IsMutableDigraph);
    <mutable digraph with 10 vertices, 30 edges>
    gap> UndirectedSpanningTree(D);
    <mutable digraph with 10 vertices, 18 edges>
    gap> D;
    <mutable digraph with 10 vertices, 18 edges>

##### 3.3-8 QuotientDigraph

`‣ QuotientDigraph`( digraph, p ) | ( operation )

Returns: A digraph.

If digraph is a digraph, and p is a partition of the vertices of digraph, then this operation returns a digraph constructed by amalgamating all vertices of digraph which lie in the same part of p.

A partition of the vertices of digraph is a list of non-empty disjoint lists, such that the union of all the sub-lists is equal to vertex set of digraph. In particular, each vertex must appear in precisely one sub-list.

The vertices of digraph in part `i` of p will become vertex `i` in the quotient, and there exists some edge in digraph with source in part `i` and range in part `j` if and only if there is an edge from `i` to `j` in the quotient. In particular, this means that the quotient of a digraph has no multiple edges. which was a change introduced in version 1.0.0 of the Digraphs package.

If digraph belongs to `IsMutableDigraph` (3.1-2), then digraph is modified in place. If digraph belongs to `IsImmutableDigraph` (3.1-3), a new immutable digraph with the above properties is returned.

    gap> D := Digraph([[2, 1], [4], [1], [1, 3, 4]]);
    <immutable digraph with 4 vertices, 7 edges>
    gap> DigraphVertices(D);
    [ 1 .. 4 ]
    gap> DigraphEdges(D);
    [ [ 1, 2 ], [ 1, 1 ], [ 2, 4 ], [ 3, 1 ], [ 4, 1 ], [ 4, 3 ],
      [ 4, 4 ] ]
    gap> p := [[1], [2, 4], [3]];
    [ [ 1 ], [ 2, 4 ], [ 3 ] ]
    gap> quo := QuotientDigraph(D, p);
    <immutable digraph with 3 vertices, 6 edges>
    gap> DigraphVertices(quo);
    [ 1 .. 3 ]
    gap> DigraphEdges(quo);
    [ [ 1, 1 ], [ 1, 2 ], [ 2, 1 ], [ 2, 2 ], [ 2, 3 ], [ 3, 1 ] ]
    gap> QuotientDigraph(EmptyDigraph(0), []);
    <immutable empty digraph with 0 vertices>

##### 3.3-9 DigraphReverse

`‣ DigraphReverse`( digraph ) | ( operation )

`‣ DigraphReverseAttr`( digraph ) | ( attribute )

Returns: A digraph.

The reverse of a digraph is the digraph formed by reversing the orientation of each of its edges, i.e. for every edge `[i, j]` of a digraph, the reverse contains the corresponding edge `[j, i]`.

`DigraphReverse` returns the reverse of the digraph digraph. If digraph is immutable, then a new immutable digraph is returned. Otherwise, the mutable digraph digraph is changed in-place into its reverse.

    gap> D := Digraph([[3], [1, 3, 5], [1], [1, 2, 4], [2, 3, 5]]);
    <immutable digraph with 5 vertices, 11 edges>
    gap> DigraphReverse(D);
    <immutable digraph with 5 vertices, 11 edges>
    gap> OutNeighbours(last);
    [ [ 2, 3, 4 ], [ 4, 5 ], [ 1, 2, 5 ], [ 4 ], [ 2, 5 ] ]
    gap> D := Digraph([[2, 4], [1], [4], [3, 4]]);
    <immutable digraph with 4 vertices, 6 edges>
    gap> DigraphEdges(D);
    [ [ 1, 2 ], [ 1, 4 ], [ 2, 1 ], [ 3, 4 ], [ 4, 3 ], [ 4, 4 ] ]
    gap> DigraphEdges(DigraphReverse(D));
    [ [ 1, 2 ], [ 2, 1 ], [ 3, 4 ], [ 4, 1 ], [ 4, 3 ], [ 4, 4 ] ]
    gap> D := CycleDigraph(IsMutableDigraph, 3);
    <mutable digraph with 3 vertices, 3 edges>
    gap> OutNeighbours(D);
    [ [ 2 ], [ 3 ], [ 1 ] ]
    gap> DigraphReverse(D);
    <mutable digraph with 3 vertices, 3 edges>
    gap> OutNeighbours(D);
    [ [ 3 ], [ 1 ], [ 2 ] ]

##### 3.3-10 DigraphDual

`‣ DigraphDual`( digraph ) | ( operation )

`‣ DigraphDualAttr`( digraph ) | ( attribute )

Returns: A digraph.

The dual of digraph has the same vertices as digraph, and there is an edge in the dual from `i` to `j` whenever there is no edge from `i` to `j` in digraph. The dual is sometimes called the complement.

`DigraphDual` returns the dual of the digraph digraph. If digraph is an immutable digraph, then a new immutable digraph is returned. Otherwise, the mutable digraph digraph is changed in-place into its dual.

    gap> D := Digraph([[2, 3], [], [4, 6], [5], [],
    > [7, 8, 9], [], [], []]);
    <immutable digraph with 9 vertices, 8 edges>
    gap> DigraphDual(D);
    <immutable digraph with 9 vertices, 73 edges>
    gap> D := CycleDigraph(IsMutableDigraph, 3);
    <mutable digraph with 3 vertices, 3 edges>
    gap> DigraphDual(D);
    <mutable digraph with 3 vertices, 6 edges>
    gap> D;
    <mutable digraph with 3 vertices, 6 edges>

##### 3.3-11 DigraphSymmetricClosure

`‣ DigraphSymmetricClosure`( digraph ) | ( operation )

`‣ DigraphSymmetricClosureAttr`( digraph ) | ( attribute )

Returns: A digraph.

If digraph is a digraph, then this attribute gives the minimal symmetric digraph which has the same vertices and contains all the edges of digraph.

A digraph is symmetric if its adjacency matrix `AdjacencyMatrix` (5.2-1) is symmetric. For a digraph with multiple edges this means that there are the same number of edges from a vertex `u` to a vertex `v` as there are from `v` to `u`; see `IsSymmetricDigraph` (6.1-12).

If digraph is immutable, then a new immutable digraph is returned. Otherwise, the mutable digraph digraph is changed in-place into its symmetric closure.

    gap> D := Digraph([[1, 2, 3], [2, 4], [1], [3, 4]]);
    <immutable digraph with 4 vertices, 8 edges>
    gap> D := DigraphSymmetricClosure(D);
    <immutable symmetric digraph with 4 vertices, 11 edges>
    gap> IsSymmetricDigraph(D);
    true
    gap> List(OutNeighbours(D), AsSet);
    [ [ 1, 2, 3 ], [ 1, 2, 4 ], [ 1, 4 ], [ 2, 3, 4 ] ]
    gap> D := Digraph([[2, 2], [1]]);
    <immutable multidigraph with 2 vertices, 3 edges>
    gap> D := DigraphSymmetricClosure(D);
    <immutable symmetric multidigraph with 2 vertices, 4 edges>
    gap> OutNeighbours(D);
    [ [ 2, 2 ], [ 1, 1 ] ]
    gap> D := CycleDigraph(IsMutableDigraph, 3);
    <mutable digraph with 3 vertices, 3 edges>
    gap> DigraphSymmetricClosure(D);
    <mutable digraph with 3 vertices, 6 edges>
    gap> D;
    <mutable digraph with 3 vertices, 6 edges>

##### 3.3-12 DigraphTransitiveClosure

`‣ DigraphTransitiveClosure`( digraph ) | ( operation )

`‣ DigraphTransitiveClosureAttr`( digraph ) | ( attribute )

`‣ DigraphReflexiveTransitiveClosure`( digraph ) | ( operation )

`‣ DigraphReflexiveTransitiveClosureAttr`( digraph ) | ( attribute )

Returns: A digraph.

If digraph is a digraph with no multiple edges, then these attributes return the (reflexive) transitive closure of digraph.

A digraph is reflexive if it has a loop at every vertex, and it is transitive if whenever `[i,j]` and `[j,k]` are edges of digraph, `[i,k]` is also an edge. The (reflexive) transitive closure of a digraph digraph is the least (reflexive and) transitive digraph containing digraph.

If digraph is immutable, then a new immutable digraph is returned. Otherwise, the mutable digraph digraph is changed in-place into its (reflexive) transitive closure.

Let n be the number of vertices of digraph, and let m be the number of edges. For an arbitrary digraph, these attributes will use a version of the Floyd-Warshall algorithm, with complexity O(n^3). However, for a topologically sortable digraph [see `DigraphTopologicalSort` (5.1-7)], these attributes will use methods with complexity O(m + n + m ⋅ n) when this is faster.

    gap> D := DigraphFromDiSparse6String(".H`eOWR`Ul^");
    <immutable digraph with 9 vertices, 8 edges>
    gap> IsReflexiveDigraph(D) or IsTransitiveDigraph(D);
    false
    gap> OutNeighbours(D);
    [ [ 4, 6 ], [ 1, 3 ], [  ], [ 5 ], [  ], [ 7, 8, 9 ], [  ], [  ],
      [  ] ]
    gap> T := DigraphTransitiveClosure(D);
    <immutable transitive digraph with 9 vertices, 18 edges>
    gap> OutNeighbours(T);
    [ [ 4, 6, 5, 7, 8, 9 ], [ 1, 3, 4, 5, 6, 7, 8, 9 ], [  ], [ 5 ],
      [  ], [ 7, 8, 9 ], [  ], [  ], [  ] ]
    gap> RT := DigraphReflexiveTransitiveClosure(D);
    <immutable preorder digraph with 9 vertices, 27 edges>
    gap> OutNeighbours(RT);
    [ [ 4, 6, 5, 7, 8, 9, 1 ], [ 1, 3, 4, 5, 6, 7, 8, 9, 2 ], [ 3 ],
      [ 5, 4 ], [ 5 ], [ 7, 8, 9, 6 ], [ 7 ], [ 8 ], [ 9 ] ]
    gap> D := CycleDigraph(IsMutableDigraph, 3);
    <mutable digraph with 3 vertices, 3 edges>
    gap> DigraphReflexiveTransitiveClosure(D);
    <mutable digraph with 3 vertices, 9 edges>
    gap> D;
    <mutable digraph with 3 vertices, 9 edges>

##### 3.3-13 DigraphTransitiveReduction

`‣ DigraphTransitiveReduction`( digraph ) | ( operation )

`‣ DigraphTransitiveReductionAttr`( digraph ) | ( attribute )

`‣ DigraphReflexiveTransitiveReduction`( digraph ) | ( operation )

`‣ DigraphReflexiveTransitiveReductionAttr`( digraph ) | ( attribute )

Returns: A digraph.

If digraph is a topologically sortable digraph [see `DigraphTopologicalSort` (5.1-7)] with no multiple edges, then these operations return the (reflexive) transitive reduction of digraph.

The (reflexive) transitive reduction of such a digraph is the unique least subgraph such that the (reflexive) transitive closure of the subgraph is equal to the (reflexive) transitive closure of digraph [see `DigraphReflexiveTransitiveClosure` (3.3-12)]. In order words, it is the least subgraph of digraph which retains the same reachability as digraph.

If digraph is immutable, then a new immutable digraph is returned. Otherwise, the mutable digraph digraph is changed in-place into its (reflexive) transitive reduction.

Let n be the number of vertices of an arbitrary digraph, and let m be the number of edges. Then these operations use methods with complexity O(m + n + m ⋅ n).

    gap> D := Digraph([[1, 2, 3], [3], [3]]);;
    gap> DigraphHasLoops(D);
    true
    gap> D1 := DigraphReflexiveTransitiveReduction(D);
    <immutable digraph with 3 vertices, 2 edges>
    gap> DigraphHasLoops(D1);
    false
    gap> OutNeighbours(D1);
    [ [ 2 ], [ 3 ], [  ] ]
    gap> D2 := DigraphTransitiveReduction(D);
    <immutable digraph with 3 vertices, 4 edges>
    gap> DigraphHasLoops(D2);
    true
    gap> OutNeighbours(D2);
    [ [ 2, 1 ], [ 3 ], [ 3 ] ]
    gap> DigraphReflexiveTransitiveClosure(D)
    >  = DigraphReflexiveTransitiveClosure(D1);
    true
    gap> DigraphTransitiveClosure(D)
    >  = DigraphTransitiveClosure(D2);
    true
    gap> D := Digraph(IsMutableDigraph, [[1], [1], [1, 2, 3]]);
    <mutable digraph with 3 vertices, 5 edges>
    gap> DigraphReflexiveTransitiveReduction(D);
    <mutable digraph with 3 vertices, 2 edges>
    gap> D;
    <mutable digraph with 3 vertices, 2 edges>

##### 3.3-14 DigraphAddVertex

`‣ DigraphAddVertex`( digraph[, label] ) | ( operation )

Returns: A digraph.

The operation returns a digraph constructed from digraph by adding a single new vertex, and no new edges.

If the optional second argument label is a GAP object, then the new vertex will be labelled label.

If digraph belongs to `IsMutableDigraph` (3.1-2), then the vertex is added directly to digraph. If digraph belongs to `IsImmutableDigraph` (3.1-3), an immutable copy of digraph with the additional vertex is returned.

    gap> D := CompleteDigraph(3);
    <immutable complete digraph with 3 vertices>
    gap> new := DigraphAddVertex(D);
    <immutable digraph with 4 vertices, 6 edges>
    gap> D = new;
    false
    gap> DigraphVertices(new);
    [ 1 .. 4 ]
    gap> new := DigraphAddVertex(D, Group([(1, 2)]));
    <immutable digraph with 4 vertices, 6 edges>
    gap> DigraphVertexLabels(new);
    [ 1, 2, 3, Group([ (1,2) ]) ]
    gap> D := CompleteBipartiteDigraph(IsMutableDigraph, 2, 3);
    <mutable digraph with 5 vertices, 12 edges>
    gap> new := DigraphAddVertex(D);
    <mutable digraph with 6 vertices, 12 edges>
    gap> D = new;
    true

##### 3.3-15 DigraphAddVertices

`‣ DigraphAddVertices`( digraph, m ) | ( operation )

`‣ DigraphAddVertices`( digraph, labels ) | ( operation )

Returns: A digraph.

For a non-negative integer m, this operation returns a digraph constructed from digraph by adding m new vertices.

Otherwise, if labels is a list consisting of `k` GAP objects, then this operation returns a digraph constructed from digraph by adding `k` new vertices, which are labelled according to this list.

If digraph belongs to `IsMutableDigraph` (3.1-2), then the vertices are added directly to digraph, which is changed in-place. If digraph belongs to `IsImmutableDigraph` (3.1-3), then digraph itself is returned if no vertices are added (i.e. `m=0` or labels is empty), otherwise the result is a new immutable digraph.

    gap> D := CompleteDigraph(3);
    <immutable complete digraph with 3 vertices>
    gap> new := DigraphAddVertices(D, 3);
    <immutable digraph with 6 vertices, 6 edges>
    gap> DigraphVertices(new);
    [ 1 .. 6 ]
    gap> new := DigraphAddVertices(D, [Group([(1, 2)]), "d"]);
    <immutable digraph with 5 vertices, 6 edges>
    gap> DigraphVertexLabels(new);
    [ 1, 2, 3, Group([ (1,2) ]), "d" ]
    gap> DigraphAddVertices(D, 0) = D;
    true
    gap> D := CompleteBipartiteDigraph(IsMutableDigraph, 2, 3);
    <mutable digraph with 5 vertices, 12 edges>
    gap> new := DigraphAddVertices(D, 4);
    <mutable digraph with 9 vertices, 12 edges>
    gap> D = new;
    true

##### 3.3-16 DigraphAddEdge

`‣ DigraphAddEdge`( digraph, edge ) | ( operation )

`‣ DigraphAddEdge`( digraph, src, ran ) | ( operation )

Returns: A digraph.

If edge is a pair of vertices of digraph, or src and ran are vertices of digraph, then this operation returns a digraph constructed from digraph by adding a new edge with source edge`[1]` [src] and range edge`[2]` [ran].

If digraph belongs to `IsMutableDigraph` (3.1-2), then the edge is added directly to digraph. If digraph belongs to `IsImmutableDigraph` (3.1-3), then an immutable copy of digraph with the additional edge is returned.

    gap> D1 := Digraph([[2], [3], []]);
    <immutable digraph with 3 vertices, 2 edges>
    gap> DigraphEdges(D1);
    [ [ 1, 2 ], [ 2, 3 ] ]
    gap> D2 := DigraphAddEdge(D1, [3, 1]);
    <immutable digraph with 3 vertices, 3 edges>
    gap> DigraphEdges(D2);
    [ [ 1, 2 ], [ 2, 3 ], [ 3, 1 ] ]
    gap> D3 := DigraphAddEdge(D2, [2, 3]);
    <immutable multidigraph with 3 vertices, 4 edges>
    gap> DigraphEdges(D3);
    [ [ 1, 2 ], [ 2, 3 ], [ 2, 3 ], [ 3, 1 ] ]
    gap> D := CycleDigraph(IsMutableDigraph, 4);
    <mutable digraph with 4 vertices, 4 edges>
    gap> new := DigraphAddEdge(D, [1, 3]);
    <mutable digraph with 4 vertices, 5 edges>
    gap> DigraphEdges(new);
    [ [ 1, 2 ], [ 1, 3 ], [ 2, 3 ], [ 3, 4 ], [ 4, 1 ] ]
    gap> D = new;
    true

##### 3.3-17 DigraphAddEdgeOrbit

`‣ DigraphAddEdgeOrbit`( digraph, edge ) | ( operation )

Returns: A new digraph.

This operation returns a new digraph with the same vertices and edges as digraph and with additional edges consisting of the orbit of the edge edge under the action of the `DigraphGroup` (7.2-10) of digraph. If edge is already an edge in digraph, then digraph is returned unchanged. The argument digraph must be an immutable digraph.

An edge is simply a pair of vertices of digraph.

    gap> gr1 := CayleyDigraph(DihedralGroup(8));
    <immutable digraph with 8 vertices, 24 edges>
    gap> gr2 := DigraphAddEdgeOrbit(gr1, [1, 8]);
    <immutable digraph with 8 vertices, 32 edges>
    gap> DigraphEdges(gr1);
    [ [ 1, 2 ], [ 1, 3 ], [ 1, 4 ], [ 2, 1 ], [ 2, 8 ], [ 2, 6 ],
      [ 3, 5 ], [ 3, 4 ], [ 3, 7 ], [ 4, 6 ], [ 4, 7 ], [ 4, 1 ],
      [ 5, 3 ], [ 5, 2 ], [ 5, 8 ], [ 6, 4 ], [ 6, 5 ], [ 6, 2 ],
      [ 7, 8 ], [ 7, 1 ], [ 7, 3 ], [ 8, 7 ], [ 8, 6 ], [ 8, 5 ] ]
    gap> DigraphEdges(gr2);
    [ [ 1, 2 ], [ 1, 3 ], [ 1, 4 ], [ 1, 8 ], [ 2, 1 ], [ 2, 8 ],
      [ 2, 6 ], [ 2, 3 ], [ 3, 5 ], [ 3, 4 ], [ 3, 7 ], [ 3, 2 ],
      [ 4, 6 ], [ 4, 7 ], [ 4, 1 ], [ 4, 5 ], [ 5, 3 ], [ 5, 2 ],
      [ 5, 8 ], [ 5, 4 ], [ 6, 4 ], [ 6, 5 ], [ 6, 2 ], [ 6, 7 ],
      [ 7, 8 ], [ 7, 1 ], [ 7, 3 ], [ 7, 6 ], [ 8, 7 ], [ 8, 6 ],
      [ 8, 5 ], [ 8, 1 ] ]
    gap> gr3 := DigraphRemoveEdgeOrbit(gr2, [1, 8]);
    <immutable digraph with 8 vertices, 24 edges>
    gap> gr3 = gr1;
    true

##### 3.3-18 DigraphAddEdges

`‣ DigraphAddEdges`( digraph, edges ) | ( operation )

Returns: A digraph.

If edges is a (possibly empty) list of pairs of vertices of digraph, then this operation returns a digraph constructed from digraph by adding the edges specified by edges. More precisely, for every `edge` in edges, a new edge will be added with source `edge[1]` and range `edges[2]`.

If an edge is included in edges with multiplicity `k`, then it will be added `k` times. If digraph belongs to `IsMutableDigraph` (3.1-2), then the edges are added directly to digraph. If digraph belongs to `IsImmutableDigraph` (3.1-3), then the result is returned as an immutable digraph.

    gap> func := function(n)
    >  local source, range, i;
    >  source := [];
    >  range  := [];
    >  for i in [1 .. n - 2] do
    >    Add(source, i);
    >    Add(range, i + 1);
    >  od;
    >  return Digraph(n, source, range);
    > end;;
    gap> D := func(1024);
    <immutable digraph with 1024 vertices, 1022 edges>
    gap> new := DigraphAddEdges(D,
    > [[1023, 1024], [1, 1024], [1023, 1024], [1024, 1]]);
    <immutable multidigraph with 1024 vertices, 1026 edges>
    gap> D = new;
    false
    gap> D2 := DigraphMutableCopy(func(1024));
    <mutable digraph with 1024 vertices, 1022 edges>
    gap> new := DigraphAddEdges(D2,
    > [[1023, 1024], [1, 1024], [1023, 1024], [1024, 1]]);
    <mutable multidigraph with 1024 vertices, 1026 edges>
    gap> D2 = new;
    true

##### 3.3-19 DigraphRemoveVertex

`‣ DigraphRemoveVertex`( digraph, v ) | ( operation )

Returns: A digraph.

If v is a vertex of digraph, then this operation returns a digraph constructed from digraph by removing vertex v, along with any edge whose source or range vertex is v.

If digraph has `n` vertices, then the vertices of the returned digraph are `[1..n-1]`, but the original labels can be accessed via `DigraphVertexLabels` (5.1-9).

If digraph belongs to `IsMutableDigraph` (3.1-2), then the vertex is removed directly from digraph. If digraph belongs to `IsImmutableDigraph` (3.1-3), an immutable copy of digraph without the vertex is returned.

    gap> D := Digraph(["a", "b", "c"],
    >                  ["a", "a", "b", "c", "c"],
    >                  ["b", "c", "a", "a", "c"]);
    <immutable digraph with 3 vertices, 5 edges>
    gap> DigraphVertexLabels(D);
    [ "a", "b", "c" ]
    gap> DigraphEdges(D);
    [ [ 1, 2 ], [ 1, 3 ], [ 2, 1 ], [ 3, 1 ], [ 3, 3 ] ]
    gap> new := DigraphRemoveVertex(D, 2);
    <immutable digraph with 2 vertices, 3 edges>
    gap> DigraphVertexLabels(new);
    [ "a", "c" ]
    gap> D := CycleDigraph(IsMutableDigraph, 5);
    <mutable digraph with 5 vertices, 5 edges>
    gap> new := DigraphRemoveVertex(D, 1);
    <mutable digraph with 4 vertices, 3 edges>
    gap> DigraphVertexLabels(D);
    [ 2, 3, 4, 5 ]
    gap> D = new;
    true

##### 3.3-20 DigraphRemoveVertices

`‣ DigraphRemoveVertices`( digraph, verts ) | ( operation )

Returns: A digraph.

If verts is a (possibly empty) duplicate-free list of vertices of digraph, then this operation returns a digraph constructed from digraph by removing every vertex in verts, along with any edge whose source or range vertex is in verts.

If digraph has `n` vertices, then the vertices of the new digraph are `[1 .. n-Length(verts)]`, but the original labels can be accessed via `DigraphVertexLabels` (5.1-9).

If digraph belongs to `IsMutableDigraph` (3.1-2), then the vertices are removed directly from digraph. If digraph belongs to `IsImmutableDigraph` (3.1-3), an immutable copy of digraph without the vertices is returned.

    gap> D := Digraph([[3], [1, 3, 5], [1], [1, 2, 4], [2, 3, 5]]);
    <immutable digraph with 5 vertices, 11 edges>
    gap> SetDigraphVertexLabels(D, ["a", "b", "c", "d", "e"]);
    gap> new := DigraphRemoveVertices(D, [2, 4]);
    <immutable digraph with 3 vertices, 4 edges>
    gap> DigraphVertexLabels(new);
    [ "a", "c", "e" ]
    gap> D := CycleDigraph(IsMutableDigraph, 5);
    <mutable digraph with 5 vertices, 5 edges>
    gap> new := DigraphRemoveVertices(D, [1, 3]);
    <mutable digraph with 3 vertices, 1 edge>
    gap> DigraphVertexLabels(D);
    [ 2, 4, 5 ]
    gap> D = new;
    true

##### 3.3-21 DigraphRemoveEdge

`‣ DigraphRemoveEdge`( digraph, edge ) | ( operation )

`‣ DigraphRemoveEdge`( digraph, src, ran ) | ( operation )

Returns: A digraph.

If digraph is a digraph with no multiple edges and edge is a pair of vertices of digraph, or src and ran are vertices of digraph, then this operation returns a digraph constructed from digraph by removing the edge specified by edge or [src, ran].

If digraph belongs to `IsMutableDigraph` (3.1-2), then the edge is removed directly from digraph. If digraph belongs to `IsImmutableDigraph` (3.1-3), an immutable copy of digraph without the edge is returned.

Note that if digraph belongs to `IsImmutableDigraph` (3.1-3), then a new copy of digraph will be returned even if edge or [src, ran] does not define an edge of digraph.

    gap> D := CycleDigraph(250000);
    <immutable cycle digraph with 250000 vertices>
    gap> D := DigraphRemoveEdge(D, [250000, 1]);
    <immutable digraph with 250000 vertices, 249999 edges>
    gap> new := DigraphRemoveEdge(D, [25000, 2]);;
    gap> new = D;
    true
    gap> IsIdenticalObj(new, D);
    false
    gap> D := DigraphMutableCopy(D);;
    gap> new := DigraphRemoveEdge(D, 2500, 2);;
    gap> IsIdenticalObj(new, D);
    true

##### 3.3-22 DigraphRemoveEdgeOrbit

`‣ DigraphRemoveEdgeOrbit`( digraph, edge ) | ( operation )

Returns: A new digraph.

This operation returns a new digraph with the same vertices as digraph and with the orbit of the edge edge (under the action of the `DigraphGroup` (7.2-10) of digraph) removed. If edge is not an edge in digraph, then digraph is returned unchanged. The argument digraph must be an immutable digraph.

An edge is simply a pair of vertices of digraph.

    gap> gr1 := CayleyDigraph(DihedralGroup(8));
    <immutable digraph with 8 vertices, 24 edges>
    gap> gr2 := DigraphAddEdgeOrbit(gr1, [1, 8]);
    <immutable digraph with 8 vertices, 32 edges>
    gap> DigraphEdges(gr1);
    [ [ 1, 2 ], [ 1, 3 ], [ 1, 4 ], [ 2, 1 ], [ 2, 8 ], [ 2, 6 ],
      [ 3, 5 ], [ 3, 4 ], [ 3, 7 ], [ 4, 6 ], [ 4, 7 ], [ 4, 1 ],
      [ 5, 3 ], [ 5, 2 ], [ 5, 8 ], [ 6, 4 ], [ 6, 5 ], [ 6, 2 ],
      [ 7, 8 ], [ 7, 1 ], [ 7, 3 ], [ 8, 7 ], [ 8, 6 ], [ 8, 5 ] ]
    gap> DigraphEdges(gr2);
    [ [ 1, 2 ], [ 1, 3 ], [ 1, 4 ], [ 1, 8 ], [ 2, 1 ], [ 2, 8 ],
      [ 2, 6 ], [ 2, 3 ], [ 3, 5 ], [ 3, 4 ], [ 3, 7 ], [ 3, 2 ],
      [ 4, 6 ], [ 4, 7 ], [ 4, 1 ], [ 4, 5 ], [ 5, 3 ], [ 5, 2 ],
      [ 5, 8 ], [ 5, 4 ], [ 6, 4 ], [ 6, 5 ], [ 6, 2 ], [ 6, 7 ],
      [ 7, 8 ], [ 7, 1 ], [ 7, 3 ], [ 7, 6 ], [ 8, 7 ], [ 8, 6 ],
      [ 8, 5 ], [ 8, 1 ] ]
    gap> gr3 := DigraphRemoveEdgeOrbit(gr2, [1, 8]);
    <immutable digraph with 8 vertices, 24 edges>
    gap> gr3 = gr1;
    true

##### 3.3-23 DigraphRemoveEdges

`‣ DigraphRemoveEdges`( digraph, edges ) | ( operation )

Returns: A digraph.

If one of the following holds:

- digraph is a digraph with no multiple edges, and edges is a list of pairs of vertices of digraph, or

- digraph is a digraph and edges is an empty list

then this operation returns a digraph constructed from digraph by removing all of the edges specified by edges (see `DigraphRemoveEdge` (3.3-21)).

If digraph belongs to `IsMutableDigraph` (3.1-2), then the edge is removed directly from digraph. If digraph belongs to `IsImmutableDigraph` (3.1-3), the edge is removed from an immutable copy of digraph and this new digraph is returned.

Note that if edges is empty, then this operation will always return digraph rather than a copy. Also, if any element of edges is invalid (i.e. does not define an edge of digraph) then that element will simply be ignored.

    gap> D := CycleDigraph(250000);
    <immutable cycle digraph with 250000 vertices>
    gap> D := DigraphRemoveEdges(D, [[250000, 1]]);
    <immutable digraph with 250000 vertices, 249999 edges>
    gap> D := DigraphMutableCopy(D);
    <mutable digraph with 250000 vertices, 249999 edges>
    gap> new := DigraphRemoveEdges(D, [[1, 2], [2, 3], [3, 100]]);
    <mutable digraph with 250000 vertices, 249997 edges>
    gap> new = D;
    true

##### 3.3-24 DigraphRemoveLoops

`‣ DigraphRemoveLoops`( digraph ) | ( operation )

`‣ DigraphRemoveLoopsAttr`( digraph ) | ( attribute )

Returns: A digraph.

If digraph is a digraph, then this operation returns a digraph constructed from digraph by removing every loop. A loop is an edge with equal source and range.

If digraph is immutable, then a new immutable digraph is returned. Otherwise, the loops are removed from the mutable digraph digraph in-place.

    gap> D := Digraph([[1, 2, 4], [1, 4], [3, 4], [1, 4, 5], [1, 5]]);
    <immutable digraph with 5 vertices, 12 edges>
    gap> DigraphRemoveLoops(D);
    <immutable digraph with 5 vertices, 8 edges>
    gap> D := Digraph(IsMutableDigraph, [[1, 2], [1]]);
    <mutable digraph with 2 vertices, 3 edges>
    gap> DigraphRemoveLoops(D);
    <mutable digraph with 2 vertices, 2 edges>
    gap> D;
    <mutable digraph with 2 vertices, 2 edges>

##### 3.3-25 DigraphRemoveAllMultipleEdges

`‣ DigraphRemoveAllMultipleEdges`( digraph ) | ( operation )

`‣ DigraphRemoveAllMultipleEdgesAttr`( digraph ) | ( attribute )

Returns: A digraph.

If digraph is a digraph, then this operation returns a digraph constructed from digraph by removing all multiple edges. The result is the largest subdigraph of digraph which does not contain multiple edges.

If digraph is immutable, then a new immutable digraph is returned. Otherwise, the multiple edges of the mutable digraph digraph are removed in-place.

    gap> D1 := Digraph([[1, 2, 3, 2], [1, 1, 3], [2, 2, 2]]);
    <immutable multidigraph with 3 vertices, 10 edges>
    gap> D2 := DigraphRemoveAllMultipleEdges(D1);
    <immutable digraph with 3 vertices, 6 edges>
    gap> OutNeighbours(D2);
    [ [ 1, 2, 3 ], [ 1, 3 ], [ 2 ] ]
    gap> D := Digraph(IsMutableDigraph, [[2, 2], [1]]);
    <mutable multidigraph with 2 vertices, 3 edges>
    gap> DigraphRemoveAllMultipleEdges(D);
    <mutable digraph with 2 vertices, 2 edges>
    gap> D;
    <mutable digraph with 2 vertices, 2 edges>

##### 3.3-26 DigraphReverseEdges

`‣ DigraphReverseEdges`( digraph, edges ) | ( operation )

`‣ DigraphReverseEdge`( digraph, edge ) | ( operation )

`‣ DigraphReverseEdge`( digraph, src, ran ) | ( operation )

Returns: A digraph.

If digraph is a digraph without multiple edges, and edges is a list of pairs of vertices of digraph (the entries of each pair corresponding to the source and the range of an edge, respectively), then `DigraphReverseEdges` returns a digraph constructed from digraph by reversing the orientation of every edge specified by edges. If only one edge is to be reversed, then `DigraphReverseEdge` can be used instead. In this case, the second argument should just be a single vertex-pair, or the second and third arguments should be the source and range of an edge respectively.

Note that even though digraph cannot have multiple edges, the output may have multiple edges.

If digraph belongs to `IsMutableDigraph` (3.1-2), then the edges are reversed in digraph. If digraph belongs to `IsImmutableDigraph` (3.1-3), an immutable copy of digraph with the specified edges reversed is returned.

    gap> D := DigraphFromDiSparse6String(".Tg?i@s?t_e?_qEsC");
    <immutable digraph with 21 vertices, 8 edges>
    gap> DigraphEdges(D);
    [ [ 1, 2 ], [ 1, 7 ], [ 1, 8 ], [ 5, 21 ], [ 7, 19 ], [ 9, 1 ],
      [ 11, 2 ], [ 21, 1 ] ]
    gap> new := DigraphReverseEdge(D, [7, 19]);
    <immutable digraph with 21 vertices, 8 edges>
    gap> DigraphEdges(new);
    [ [ 1, 2 ], [ 1, 7 ], [ 1, 8 ], [ 5, 21 ], [ 9, 1 ], [ 11, 2 ],
      [ 19, 7 ], [ 21, 1 ] ]
    gap> D2 := DigraphMutableCopy(new);;
    gap> new := DigraphReverseEdges(D2, [[19, 7]]);;
    gap> D2 = new;
    true
    gap> D = new;
    true

##### 3.3-27 DigraphDisjointUnion

`‣ DigraphDisjointUnion`( D1, D2, ... ) | ( function )

`‣ DigraphDisjointUnion`( list ) | ( function )

Returns: A digraph.

In the first form, if D1, D2, etc. are digraphs, then `DigraphDisjointUnion` returns their disjoint union. In the second form, if list is a non-empty list of digraphs, then `DigraphDisjointUnion` returns the disjoint union of the digraphs contained in the list.

For a disjoint union of digraphs, the vertex set is the disjoint union of the vertex sets, and the edge list is the disjoint union of the edge lists.

More specifically, for a collection of digraphs D1, D2, `...`, the disjoint union with have `DigraphNrVertices(`D1`)` `+` `DigraphNrVertices(`D2`)` `+` `...` vertices. The edges of D1 will remain unchanged, whilst the edges of the `i`th digraph, D`[i]`, will be changed so that they belong to the vertices of the disjoint union corresponding to D`[i]`. In particular, the edges of D`[i]` will have their source and range increased by `DigraphNrVertices(`D1`)` `+` `...` `+` `DigraphNrVertices(`D`[i-1])`.

Note that previously set `DigraphVertexLabels` (5.1-9) will be lost.

If the first digraph D1 [list[1]] belongs to `IsMutableDigraph` (3.1-2), then D1 [list[1]] is modified in place to contain the appropriate vertices and edges. If digraph belongs to `IsImmutableDigraph` (3.1-3), a new immutable digraph containing the appropriate vertices and edges is returned.

    gap> D1 := CycleDigraph(3);
    <immutable cycle digraph with 3 vertices>
    gap> OutNeighbours(D1);
    [ [ 2 ], [ 3 ], [ 1 ] ]
    gap> D2 := CompleteDigraph(3);
    <immutable complete digraph with 3 vertices>
    gap> OutNeighbours(D2);
    [ [ 2, 3 ], [ 1, 3 ], [ 1, 2 ] ]
    gap> union := DigraphDisjointUnion(D1, D2);
    <immutable digraph with 6 vertices, 9 edges>
    gap> OutNeighbours(union);
    [ [ 2 ], [ 3 ], [ 1 ], [ 5, 6 ], [ 4, 6 ], [ 4, 5 ] ]

##### 3.3-28 DigraphEdgeUnion

`‣ DigraphEdgeUnion`( D1, D2, ... ) | ( function )

`‣ DigraphEdgeUnion`( list ) | ( function )

Returns: A digraph.

In the first form, if D1, D2, etc. are digraphs, then `DigraphEdgeUnion` returns their edge union. In the second form, if list is a non-empty list of digraphs, then `DigraphEdgeUnion` returns the edge union of the digraphs contained in the list.

The vertex set of the edge union of a collection of digraphs is the union of the vertex sets, whilst the edge list of the edge union is the concatenation of the edge lists. The number of vertices of the edge union is equal to the maximum number of vertices of one of the digraphs, whilst the number of edges of the edge union will equal the sum of the number of edges of each digraph.

Note that previously set `DigraphVertexLabels` (5.1-9) will be lost.

If the first digraph D1 [list[1]] belongs to `IsMutableDigraph` (3.1-2), then D1 [list[1]] is modified in place to contain the appropriate vertices and edges. If digraph belongs to `IsImmutableDigraph` (3.1-3), a new immutable digraph containing the appropriate vertices and edges is returned.

    gap> D := CycleDigraph(10);
    <immutable cycle digraph with 10 vertices>
    gap> DigraphEdgeUnion(D, D);
    <immutable multidigraph with 10 vertices, 20 edges>
    gap> D1 := Digraph([[2], [1]]);
    <immutable digraph with 2 vertices, 2 edges>
    gap> D2 := Digraph([[2, 3], [2], [1]]);
    <immutable digraph with 3 vertices, 4 edges>
    gap> union := DigraphEdgeUnion(D1, D2);
    <immutable multidigraph with 3 vertices, 6 edges>
    gap> OutNeighbours(union);
    [ [ 2, 2, 3 ], [ 1, 2 ], [ 1 ] ]
    gap> union = DigraphByEdges(
    > Concatenation(DigraphEdges(D1), DigraphEdges(D2)));
    true

##### 3.3-29 DigraphJoin

`‣ DigraphJoin`( D1, D2, ... ) | ( function )

`‣ DigraphJoin`( list ) | ( function )

Returns: A digraph.

In the first form, if D1, D2, etc. are digraphs, then `DigraphJoin` returns their join. In the second form, if list is a non-empty list of digraphs, then `DigraphJoin` returns the join of the digraphs contained in the list.

The join of a collection of digraphs D1, D2, `...` is formed by first taking the `DigraphDisjointUnion` (3.3-27) of the collection. In the disjoint union, if i ≠ j then there are no edges between vertices corresponding to digraphs D`[i]` and D`[j]` in the collection; the join is created by including all such edges.

For example, the join of two empty digraphs is a complete bipartite digraph.

Note that previously set `DigraphVertexLabels` (5.1-9) will be lost.

If the first digraph D1 [list[1]] belongs to `IsMutableDigraph` (3.1-2), then D1 [list[1]] is modified in place to contain the appropriate vertices and edges. If digraph belongs to `IsImmutableDigraph` (3.1-3), a new immutable digraph containing the appropriate vertices and edges is returned.

    gap> D := CompleteDigraph(3);
    <immutable complete digraph with 3 vertices>
    gap> IsCompleteDigraph(DigraphJoin(D, D));
    true
    gap> D2 := CycleDigraph(3);
    <immutable cycle digraph with 3 vertices>
    gap> DigraphJoin(D, D2);
    <immutable digraph with 6 vertices, 27 edges>

##### 3.3-30 DigraphCartesianProduct

`‣ DigraphCartesianProduct`( gr1, gr2, ... ) | ( function )

`‣ DigraphCartesianProduct`( list ) | ( function )

Returns: A digraph.

In the first form, if gr1, gr2, etc. are digraphs, then `DigraphCartesianProduct` returns a digraph isomorphic to their Cartesian product.

In the second form, if list is a non-empty list of digraphs, then `DigraphCartesianProduct` returns a digraph isomorphic to the Cartesian product of the digraphs contained in the list.

Mathematically, the Cartesian product of two digraphs `G`, `H` is a digraph with vertex set `Cartesian(DigraphVertices(G), DigraphVertices(H))` such that there is an edge from `[u, u']` to `[v, v']` iff `u = v` and there is an edge from `u'` to `v'` in `H` or `u' = v'` and there is an edge from `u` to `v` in `G`.

Due to technical reasons, the digraph `D` returned by `DigraphCartesianProduct` has vertex set `[1 .. DigraphNrVertices(G)*DigraphNrVertices(H)]` instead, and the exact method of encoding pairs of vertices into integers is implementation specific. The original vertex pair can be somewhat regained by using `DigraphCartesianProductProjections` (3.3-32). In addition, `DigraphVertexLabels` (5.1-9) are preserved: if vertex pair `[u,u']` was encoded as `i` then the vertex label of `i` will be the pair of vertex labels of `u` and `u'` i.e. `DigraphVertexLabel(D,i) = [DigraphVertexLabel(G,u), DigraphVertexLabel(H,u')]`.

As the Cartesian product is associative, the Cartesian product of a collection of digraphs gr1, gr2, `...` is computed in the obvious fashion.

    gap> gr := ChainDigraph(4);
    <immutable chain digraph with 4 vertices>
    gap> gr2 := CycleDigraph(3);
    <immutable cycle digraph with 3 vertices>
    gap> gr3 := DigraphCartesianProduct(gr, gr2);
    <immutable digraph with 12 vertices, 21 edges>
    gap> IsIsomorphicDigraph(gr3,
    > Digraph([[2, 5], [3, 6], [4, 7], [8],
    >          [6, 9], [7, 10], [8, 11], [12],
    >          [10, 1], [11, 2], [12, 3], [4]]));
    true

##### 3.3-31 DigraphDirectProduct

`‣ DigraphDirectProduct`( gr1, gr2, ... ) | ( function )

`‣ DigraphDirectProduct`( list ) | ( function )

Returns: A digraph.

In the first form, if gr1, gr2, etc. are digraphs, then `DigraphDirectProduct` returns a digraph isomorphic to their direct product.

In the second form, if list is a non-empty list of digraphs, then `DigraphDirectProduct` returns a digraph isomorphic to the direct product of the digraphs contained in the list.

Mathematically, the direct product of two digraphs `G`, `H` is a digraph with vertex set `Cartesian(DigraphVertices(G), DigraphVertices(H))` such that there is an edge from `[u, u']` to `[v, v']` iff there is an edge from `u` to `v` in `G` and an edge from `u'` to `v'` in `H`.

Due to technical reasons, the digraph `D` returned by `DigraphDirectProduct` has vertex set `[1 .. DigraphNrVertices(G)*DigraphNrVertices(H)]` instead, and the exact method of encoding pairs of vertices into integers is implementation specific. The original vertex pair can be somewhat regained by using `DigraphDirectProductProjections` (3.3-33). In addition `DigraphVertexLabels` (5.1-9) are preserved: if vertex pair `[u,u']` was encoded as `i` then the vertex label of `i` will be the pair of vertex labels of `u` and `u'` i.e. `DigraphVertexLabel(D,i) = [DigraphVertexLabel(G,u), DigraphVertexLabel(H,u')]`.

As the direct product is associative, the direct product of a collection of digraphs gr1, gr2, `...` is computed in the obvious fashion.

    gap> gr := ChainDigraph(4);
    <immutable chain digraph with 4 vertices>
    gap> gr2 := CycleDigraph(3);
    <immutable cycle digraph with 3 vertices>
    gap> gr3 := DigraphDirectProduct(gr, gr2);
    <immutable digraph with 12 vertices, 9 edges>
    gap> IsIsomorphicDigraph(gr3,
    > Digraph([[6], [7], [8], [],
    >          [10], [11], [12], [],
    >          [2], [3], [4], []]));
    true

##### 3.3-32 DigraphCartesianProductProjections

`‣ DigraphCartesianProductProjections`( digraph ) | ( attribute )

Returns: A list of transformations.

If digraph is a Cartesian product digraph, `digraph = DigraphCartesianProduct(gr_1, gr_2, ... )`, then `DigraphCartesianProductProjections` returns a list `proj` such that `proj[i]` is the projection onto the `i`-th coordinate of the product.

A projection is an idempotent endomorphism of digraph. If `gr1, gr2, ...` are all loopless digraphs, then the induced subdigraph of digraph on the image of `proj[i]` is isomorphic to `gr_i`.

Currently this attribute is only set upon creating an immutable digraph via `DigraphCartesianProduct` and there is no way of calculating it for other digraphs.

For more information see `DigraphCartesianProduct` (3.3-30)

    gap> D := DigraphCartesianProduct(ChainDigraph(3), CycleDigraph(4),
    > Digraph([[2], [2]]));;
    gap> HasDigraphCartesianProductProjections(D);
    true
    gap> proj := DigraphCartesianProductProjections(D);; Length(proj);
    3
    gap> IsIdempotent(proj[2]);
    true
    gap> RankOfTransformation(proj[3]);
    2
    gap> S := ImageSetOfTransformation(proj[2]);;
    gap> IsIsomorphicDigraph(CycleDigraph(4), InducedSubdigraph(D, S));
    true

##### 3.3-33 DigraphDirectProductProjections

`‣ DigraphDirectProductProjections`( digraph ) | ( attribute )

Returns: A list of transformations.

If digraph is a direct product digraph, `digraph = DigraphDirectProduct(gr_1, gr_2, ... )`, then `DigraphDirectProductProjections` returns a list `proj` such that `proj[i]` is the projection onto the `i`-th coordinate of the product.

A projection is an idempotent endomorphism of digraph. If `gr1, gr2, ...` are all loopless digraphs, then the image of digraph under `proj[i]` is isomorphic to `gr_i`.

Currently this attribute is only set upon creating an immutable digraph via `DigraphDirectProduct` and there is no way of calculating it for other digraphs.

For more information, see `DigraphDirectProduct` (3.3-31)

    gap> D := DigraphDirectProduct(ChainDigraph(3), CycleDigraph(4),
    > Digraph([[2], [2]]));;
    gap> HasDigraphDirectProductProjections(D);
    true
    gap> proj := DigraphDirectProductProjections(D);; Length(proj);
    3
    gap> IsIdempotent(proj[2]);
    true
    gap> RankOfTransformation(proj[3]);
    2
    gap> P := DigraphRemoveAllMultipleEdges(
    > ReducedDigraph(OnDigraphs(D, proj[2])));;
    gap> IsIsomorphicDigraph(CycleDigraph(4), P);
    true

##### 3.3-34 LineDigraph

`‣ LineDigraph`( digraph ) | ( operation )

`‣ EdgeDigraph`( digraph ) | ( operation )

Returns: A digraph.

Given a digraph digraph, the operation returns the digraph obtained by associating a vertex with each edge of digraph, and creating an edge from a vertex `v` to a vertex `u` if and only if the terminal vertex of the edge associated with `v` is the start vertex of the edge associated with `u`.

Note that the returned digraph is always a new immutable digraph, and the argument digraph is never modified.

    gap> LineDigraph(CompleteDigraph(3));
    <immutable digraph with 6 vertices, 12 edges>
    gap> LineDigraph(ChainDigraph(3));
    <immutable digraph with 2 vertices, 1 edge>

##### 3.3-35 LineUndirectedDigraph

`‣ LineUndirectedDigraph`( digraph ) | ( operation )

`‣ EdgeUndirectedDigraph`( digraph ) | ( operation )

Returns: A digraph.

Given a symmetric digraph digraph, the operation returns the symmetric digraph obtained by associating a vertex with each edge of digraph, ignoring directions and multiplicites, and adding an edge between two vertices if and only if the corresponding edges have a vertex in common.

Note that the returned digraph is always a new immutable digraph, and the argument digraph is never modified.

    gap> LineUndirectedDigraph(CompleteDigraph(3));
    <immutable digraph with 3 vertices, 6 edges>
    gap> LineUndirectedDigraph(DigraphSymmetricClosure(ChainDigraph(3)));
    <immutable digraph with 2 vertices, 2 edges>

##### 3.3-36 DoubleDigraph

`‣ DoubleDigraph`( digraph ) | ( operation )

Returns: A digraph.

Let digraph be a digraph with vertex set `V`. This function returns the double digraph of digraph. The vertex set of the double digraph is the orginal vertex set together with a duplicate. The edges are `[u_1, v_2]` and `[u_2, v_1]` if and only if `[u, v]` is an edge in digraph, together with the original edges and their duplicates.

If digraph is mutable, then digraph is modified in-place. If digraph is immutable, then a new immutable digraph constructed as described above is returned.

    gap> gamma := Digraph([[2], [3], [1]]);
    <immutable digraph with 3 vertices, 3 edges>
    gap> DoubleDigraph(gamma);
    <immutable digraph with 6 vertices, 12 edges>

##### 3.3-37 BipartiteDoubleDigraph

`‣ BipartiteDoubleDigraph`( digraph ) | ( operation )

Returns: A digraph.

Let digraph be a digraph with vertex set `V`. This function returns the bipartite double digraph of digraph. The vertex set of the double digraph is the original vertex set together with a duplicate. The edges are `[u_1, v_2]` and `[u_2, v_1]` if and only if `[u, v]` is an edge in digraph. The resulting graph is bipartite, since the orignal edges are not included in the resulting digraph.

If digraph is mutable, then digraph is modified in-place. If digraph is immutable, then a new immutable digraph constructed as described above is returned.

    gap> gamma := Digraph([[2], [3], [1]]);
    <immutable digraph with 3 vertices, 3 edges>
    gap> BipartiteDoubleDigraph(gamma);
    <immutable digraph with 6 vertices, 6 edges>

##### 3.3-38 DigraphAddAllLoops

`‣ DigraphAddAllLoops`( digraph ) | ( operation )

`‣ DigraphAddAllLoopsAttr`( digraph ) | ( attribute )

Returns: A digraph.

For a digraph digraph this operation returns a new digraph constructed from digraph, such that a loop is added for every vertex which did not have a loop in digraph.

If digraph is immutable, then a new immutable digraph is returned. Otherwise, the loops are added to the loopless vertices of the mutable digraph digraph in-place.

    gap> D := EmptyDigraph(13);
    <immutable empty digraph with 13 vertices>
    gap> D := DigraphAddAllLoops(D);
    <immutable reflexive digraph with 13 vertices, 13 edges>
    gap> OutNeighbours(D);
    [ [ 1 ], [ 2 ], [ 3 ], [ 4 ], [ 5 ], [ 6 ], [ 7 ], [ 8 ], [ 9 ],
      [ 10 ], [ 11 ], [ 12 ], [ 13 ] ]
    gap> D := Digraph([[1, 2, 3], [1, 3], [1]]);
    <immutable digraph with 3 vertices, 6 edges>
    gap> D := DigraphAddAllLoops(D);
    <immutable reflexive digraph with 3 vertices, 8 edges>
    gap> OutNeighbours(D);
    [ [ 1, 2, 3 ], [ 1, 3, 2 ], [ 1, 3 ] ]
    gap> D := CycleDigraph(IsMutableDigraph, 3);
    <mutable digraph with 3 vertices, 3 edges>
    gap> DigraphAddAllLoops(D);
    <mutable digraph with 3 vertices, 6 edges>
    gap> D;
    <mutable digraph with 3 vertices, 6 edges>

##### 3.3-39 DistanceDigraph

`‣ DistanceDigraph`( digraph, i ) | ( operation )

`‣ DistanceDigraph`( digraph, list ) | ( operation )

Returns: A digraph.

The first argument is a digraph, the second argument is a non-negative integer or a list of positive integers. This operation returns a digraph on the same set of vertices as digraph, with two vertices being adjacent if and only if the distance between them in digraph equals i or is a number in list. See `DigraphShortestDistance` (5.3-2).

If digraph is mutable, then digraph is modified in-place. If digraph is immutable, then a new immutable digraph constructed as described above is returned.

    gap> digraph := DigraphFromSparse6String(
    > ":]n?AL`BC_DEbEF`GIaGHdIJeGKcKL_@McDHfILaBJfHMjKM");
    <immutable digraph with 30 vertices, 90 edges>
    gap> DistanceDigraph(digraph, 1);
    <immutable digraph with 30 vertices, 90 edges>
    gap> DistanceDigraph(digraph, [1, 2]);
    <immutable digraph with 30 vertices, 270 edges>

##### 3.3-40 DigraphClosure

`‣ DigraphClosure`( digraph, k ) | ( operation )

Returns: A digraph.

Given a symmetric loopless digraph with no multiple edges digraph, the k-closure of digraph is defined to be the unique smallest symmetric loopless digraph `C` with no multiple edges on the vertices of digraph that contains all the edges of digraph and satsifies the property that the sum of the degrees of every two non-adjacenct vertices in `C` is less than k. See `IsSymmetricDigraph` (6.1-12), `DigraphHasLoops` (6.1-1), `IsMultiDigraph` (6.1-10), and `OutDegreeOfVertex` (5.2-10).

The operation `DigraphClosure` returns the k-closure of digraph.

    gap> D := CompleteDigraph(6);
    <immutable complete digraph with 6 vertices>
    gap> D := DigraphRemoveEdges(D, [[1, 2], [2, 1]]);
    <immutable digraph with 6 vertices, 28 edges>
    gap> closure := DigraphClosure(D, 6);
    <immutable digraph with 6 vertices, 30 edges>
    gap> IsCompleteDigraph(closure);
    true

##### 3.3-41 DigraphMycielskian

`‣ DigraphMycielskian`( digraph ) | ( operation )

`‣ DigraphMycielskianAttr`( digraph ) | ( attribute )

Returns: A digraph.

If digraph is a symmetric digraph, then `DigraphMycielskian` returns the Mycielskian of digraph.

The Mycielskian of a symmetric digraph is a larger symmetric digraph constructed from it, which has a larger chromatic number. For further information, see https://en.wikipedia.org/wiki/Mycielskian.

If digraph is immutable, then a new immutable digraph is returned. Otherwise, the mutable digraph digraph is changed in-place into its Mycielskian.

    gap> D := CycleDigraph(2);
    <immutable cycle digraph with 2 vertices>
    gap> ChromaticNumber(D);
    2
    gap> D := DigraphMycielskian(D);
    <immutable digraph with 5 vertices, 10 edges>
    gap> ChromaticNumber(D);
    3
    gap> D := DigraphMycielskian(D);
    <immutable digraph with 11 vertices, 40 edges>
    gap> ChromaticNumber(D);
    4
    gap> D := CompleteBipartiteDigraph(IsMutable, 2, 3);
    <mutable digraph with 5 vertices, 12 edges>
    gap> DigraphMycielskian(D);
    <mutable digraph with 11 vertices, 46 edges>
    gap> D;
    <mutable digraph with 11 vertices, 46 edges>

#### 3.4 Random digraphs

##### 3.4-1 RandomDigraph

`‣ RandomDigraph`( [filt, ]n[, p] ) | ( operation )

Returns: A digraph.

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

If n is a positive integer, then this function returns a random digraph with n vertices and without multiple edges. The result may or may not have loops.

If the optional second argument p is a float with value 0 ≤ p ≤ 1, then an edge will exist between each pair of vertices with probability approximately p. If p is not specified, then a random probability will be assumed (chosen with uniform probability).

    gap> RandomDigraph(1000);
    <immutable digraph with 1000 vertices, 364444 edges>
    gap> RandomDigraph(10000, 0.023);
    <immutable digraph with 10000 vertices, 2300438 edges>
    gap> RandomDigraph(IsMutableDigraph, 1000, 1 / 2);
    <mutable digraph with 1000 vertices, 499739 edges>

##### 3.4-2 RandomMultiDigraph

`‣ RandomMultiDigraph`( n[, m] ) | ( operation )

Returns: A digraph.

If n is a positive integer, then this function returns a random digraph with n vertices. If the optional second argument m is a positive integer, then the digraph will have m edges. If m is not specified, then the number of edges will be chosen randomly (with uniform probability) from the range `[1 ..` n choose 2`]`.

The method used by this function chooses each edge from the set of all possible edges with uniform probability. No effort is made to avoid creating multiple edges, so it is possible (but not guaranteed) that the result will have multiple edges. The result may or may not have loops.

    gap> RandomMultiDigraph(1000);
    <immutable multidigraph with 1000 vertices, 216659 edges>
    gap> RandomMultiDigraph(1000, 950);
    <immutable multidigraph with 1000 vertices, 950 edges>

##### 3.4-3 RandomTournament

`‣ RandomTournament`( [filt, ]n ) | ( operation )

Returns: A digraph.

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

If n is a non-negative integer, this function returns a random tournament with n vertices. See `IsTournament` (6.1-13).

    gap> RandomTournament(10);
    <immutable tournament with 10 vertices>
    gap> RandomTournament(IsMutableDigraph, 10);
    <mutable digraph with 1000 vertices, 500601 edges>

##### 3.4-4 RandomLattice

`‣ RandomLattice`( n ) | ( operation )

Returns: A digraph.

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

If n is a positive integer, this function return a random lattice with `m` vertices, where it is guaranteed that `m` is between n and `2 * n`. See `IsLatticeDigraph` (6.1-17).

    gap> RandomLattice(10);
    <immutable lattice digraph with 10 vertices, 39 edges>
    gap> RandomLattice(IsMutableDigraph, 10);
    <mutable digraph with 12 vertices, 52 edges>

#### 3.5 Standard examples

##### 3.5-1 ChainDigraph

`‣ ChainDigraph`( [filt, ]n ) | ( operation )

Returns: A digraph.

If n is a positive integer, this function returns a chain with n vertices and `n - 1` edges. Specifically, for each vertex `i` (with `i` < `n`), there is a directed edge with source `i` and range `i + 1`.

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

The `DigraphReflexiveTransitiveClosure` (3.3-12) of a chain represents a total order.

    gap> ChainDigraph(42);
    <immutable chain digraph with 42 vertices>
    gap> ChainDigraph(IsMutableDigraph, 10);
    <mutable digraph with 10 vertices, 9 edges>

##### 3.5-2 CompleteDigraph

`‣ CompleteDigraph`( [filt, ]n ) | ( operation )

Returns: A digraph.

If n is a non-negative integer, this function returns the complete digraph with n vertices. See `IsCompleteDigraph` (6.1-5).

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

    gap> CompleteDigraph(20);
    <immutable complete digraph with 20 vertices>
    gap> CompleteDigraph(IsMutableDigraph, 10);
    <mutable digraph with 10 vertices, 90 edges>

##### 3.5-3 CompleteBipartiteDigraph

`‣ CompleteBipartiteDigraph`( [filt, ]m, n ) | ( operation )

Returns: A digraph.

A complete bipartite digraph is a digraph whose vertices can be partitioned into two non-empty vertex sets, such there exists a unique edge with source `i` and range `j` if and only if `i` and `j` lie in different vertex sets.

If m and n are positive integers, this function returns the complete bipartite digraph with vertex sets of sizes m (containing the vertices `[1 .. m]`) and n (containing the vertices `[m + 1 .. m + n]`).

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

    gap> CompleteBipartiteDigraph(2, 3);
    <immutable complete bipartite digraph with bicomponent sizes 2 and 3>
    gap> CompleteBipartiteDigraph(IsMutableDigraph, 3, 2);
    <mutable digraph with 5 vertices, 12 edges>

##### 3.5-4 CompleteMultipartiteDigraph

`‣ CompleteMultipartiteDigraph`( [filt, ]orders ) | ( operation )

Returns: A digraph.

For a list orders of `n` positive integers, this function returns the digraph containing `n` independent sets of vertices of orders `[l[1] .. l[n]]`. Moreover, each vertex is adjacent to every other not contained in the same independent set.

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

    gap> CompleteMultipartiteDigraph([5, 4, 2]);
    <immutable complete multipartite digraph with 11 vertices, 76 edges>
    gap> CompleteMultipartiteDigraph(IsMutableDigraph, [5, 4, 2]);
    <mutable digraph with 11 vertices, 76 edges>

##### 3.5-5 CycleDigraph

`‣ CycleDigraph`( [filt, ]n ) | ( operation )

Returns: A digraph.

If n is a positive integer, this function returns a cycle digraph with n vertices and n edges. Specifically, for each vertex `i` (with `i` < `n`), there is a directed edge with source `i` and range `i + 1`. In addition, there is an edge with source `n` and range `1`.

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

    gap> CycleDigraph(1);
    <immutable digraph with 1 vertex, 1 edge>
    gap> CycleDigraph(123);
    <immutable cycle digraph with 123 vertices>
    gap> CycleDigraph(IsMutableDigraph, 10);
    <mutable digraph with 10 vertices, 10 edges>

##### 3.5-6 EmptyDigraph

`‣ EmptyDigraph`( [filt, ]n ) | ( operation )

`‣ NullDigraph`( [filt, ]n ) | ( operation )

Returns: A digraph.

If n is a non-negative integer, this function returns the empty or null digraph with n vertices. An empty digraph is one with no edges.

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

`NullDigraph` is a synonym for `EmptyDigraph`.

    gap> EmptyDigraph(20);
    <immutable empty digraph with 20 vertices>
    gap> NullDigraph(10);
    <immutable empty digraph with 10 vertices>
    gap> EmptyDigraph(IsMutableDigraph, 10);
    <mutable empty digraph with 10 vertices>

##### 3.5-7 JohnsonDigraph

`‣ JohnsonDigraph`( [filt, ]n, k ) | ( operation )

Returns: A digraph.

If n and k are non-negative integers, then this operation returns a symmetric digraph which corresponds to the undirected Johnson graph J(n, k).

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

The Johnson graph J(n, k) has vertices given by all the k-subsets of the range `[1 .. n]`, and two vertices are connected by an edge iff their intersection has size k - 1.

    gap> gr := JohnsonDigraph(3, 1);
    <immutable symmetric digraph with 3 vertices, 6 edges>
    gap> OutNeighbours(gr);
    [ [ 2, 3 ], [ 1, 3 ], [ 1, 2 ] ]
    gap> gr := JohnsonDigraph(4, 2);
    <immutable symmetric digraph with 6 vertices, 24 edges>
    gap> OutNeighbours(gr);
    [ [ 2, 3, 4, 5 ], [ 1, 3, 4, 6 ], [ 1, 2, 5, 6 ], [ 1, 2, 5, 6 ],
      [ 1, 3, 4, 6 ], [ 2, 3, 4, 5 ] ]
    gap> JohnsonDigraph(1, 0);
    <immutable empty digraph with 1 vertex>
    gap> JohnsonDigraph(IsMutableDigraph, 1, 0);
    <mutable empty digraph with 1 vertex>

##### 3.5-8 PetersenGraph

`‣ PetersenGraph`( [filt] ) | ( operation )

Returns: A digraph.

From https://en.wikipedia.org/wiki/Petersen_graph:

"The Petersen graph is an undirected graph with 10 vertices and 15 edges. It is a small graph that serves as a useful example and counterexample for many problems in graph theory. The Petersen graph is named after Julius Petersen, who in 1898 constructed it to be the smallest bridgeless cubic graph with no three-edge-coloring."

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

See also `GeneralisedPetersenGraph` (3.5-9).

    gap> ChromaticNumber(PetersenGraph());
    3
    gap> PetersenGraph(IsMutableDigraph);
    <mutable digraph with 10 vertices, 30 edges>

##### 3.5-9 GeneralisedPetersenGraph

`‣ GeneralisedPetersenGraph`( [filt, ]n, k ) | ( operation )

Returns: A digraph.

If n is a positive integer and k is a non-negative integer less than `n / 2`, then this operation returns the generalised Petersen graph GPG(n, k).

From https://en.wikipedia.org/wiki/Generalized_Petersen_graph:

"The generalized Petersen graphs are a family of cubic graphs formed by connecting the vertices of a regular polygon to the corresponding vertices of a star polygon. They include the Petersen graph and generalize one of the ways of constructing the Petersen graph. The generalized Petersen graph family was introduced in 1950 by H. S. M. Coxeter and was given its name in 1969 by Mark Watkins."

If the optional first argument filt is present, then this should specify the category or representation the digraph being created will belong to. For example, if filt is `IsMutableDigraph` (3.1-2), then the digraph being created will be mutable, if filt is `IsImmutableDigraph` (3.1-3), then the digraph will be immutable. If the optional first argument filt is not present, then `IsImmutableDigraph` (3.1-3) is used by default.

See also `PetersenGraph` (3.5-8).

    gap> GeneralisedPetersenGraph(7, 2);
    <immutable symmetric digraph with 14 vertices, 42 edges>
    gap> GeneralisedPetersenGraph(40, 1);
    <immutable symmetric digraph with 80 vertices, 240 edges>
    gap> D := GeneralisedPetersenGraph(5, 2);
    <immutable symmetric digraph with 10 vertices, 30 edges>
    gap> IsIsomorphicDigraph(D, PetersenGraph());
    true
    gap> GeneralisedPetersenGraph(IsMutableDigraph, 9, 4);
    <mutable digraph with 18 vertices, 54 edges>

[Top of Book] [Contents] [Previous Chapter] [Next Chapter]
Goto Chapter: Top 1 2 3 4 5 6 7 8 9 A Bib Ind

generated by GAPDoc2HTML