#############################################################################
##
#W  attr.xml
#Y  Copyright (C) 2014-16                               James D. Mitchell
##
##  Licensing information can be found in the README file of this package.
##
#############################################################################
##

<#GAPDoc Label="DigraphAdjacencyFunction">
<ManSection>
  <Attr Name="DigraphAdjacencyFunction" Arg="digraph"/>
  <Returns>A function.</Returns>
  <Description>
    If <A>digraph</A> is a digraph, then <C>DigraphAdjacencyFunction</C> returns
    a function which takes two integer parameters <C>x, y</C> and returns
    <K>true</K> if there exists an edge from vertex <C>x</C> to vertex <C>y</C>
    in <A>digraph</A> and <K>false</K> if not.
    
    <Example><![CDATA[
gap> digraph := Digraph([[1, 2], [3], []]);
<digraph with 3 vertices, 3 edges>
gap> foo := DigraphAdjacencyFunction(digraph);
function( u, v ) ... end
gap> foo(1, 1);
true
gap> foo(1, 2);
true
gap> foo(1, 3);
false
gap> foo(3, 1);
false
gap> gr := Digraph(["a", "b", "c"],
>                  ["a", "b", "b"],
>                  ["b", "a", "a"]);
<multidigraph with 3 vertices, 3 edges>
gap> foo := DigraphAdjacencyFunction(gr);
function( u, v ) ... end
gap> foo(1, 2);
true
gap> foo(3, 2);
false
gap> foo(3, 1);
false]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="AsGraph">
<ManSection>
  <Attr Name="AsGraph" Arg="digraph"/>
  <Returns>A &Grape; package graph.</Returns>
  <Description>
    If <A>digraph</A> is a digraph, then this method returns the same as
    <Ref Oper="Graph"/>, except that the result will be stored as a mutable
    attribute of <A>digraph</A>. <P/>

    If <C>AsGraph(</C><A>digraph</A><C>)</C> is called subsequently,
    then the same &GAP; object will be returned as before.
    
    <Example><![CDATA[
gap> d := Digraph([[1, 2], [3], []]);
<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 ] )
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="AsTransformation">
<ManSection>
  <Attr Name="AsTransformation" Arg="digraph"/>
  <Returns>A transformation, or <K>fail</K></Returns>
  <Description>
    If <A>digraph</A> is a functional digraph, then <C>AsTransformation</C>
    returns the transformation which is defined by <A>digraph</A>.  See <Ref
      Prop="IsFunctionalDigraph"/>. Otherwise,
    <C>AsTransformation(</C><A>digraph</A><C>)</C> returns <K>fail</K>.  <P/>

    If <A>digraph</A> is a functional digraph with <M>n</M> vertices, then
    <C>AsTransformation(</C><A>digraph</A><C>)</C> will return the
    transformation <C>f</C> of degree at most <M>n</M> where for each <M>1
      \leq i \leq n</M>, <C>i ^ f</C> is equal to the unique out-neighbour of
    vertex <C>i</C> in <A>digraph</A>.
    
    <Example><![CDATA[
gap> gr := Digraph([[1], [3], [2]]);
<digraph with 3 vertices, 3 edges>
gap> gr := CycleDigraph(3);
<digraph with 3 vertices, 3 edges>
gap> AsTransformation(gr);
Transformation( [ 2, 3, 1 ] )
gap> AsPermutation(last);
(1,2,3)
gap> gr := Digraph([[2, 3], [], []]);
<digraph with 3 vertices, 2 edges>
gap> AsTransformation(gr);
fail]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphDual">
<ManSection>
  <Attr Name="DigraphDual" Arg="digraph"/>
  <Returns>A digraph.</Returns>
  <Description>
    If <A>digraph</A> is a digraph without multiple edges, then this
    returns the <E>dual</E> of <A>digraph</A>. The <E>dual</E> is sometimes
    called the <E>complement</E>.<P/> 
    
    The <E>dual</E> of <A>digraph</A> has the same vertices as <A>digraph</A>,
    and there is an edge in the dual from <C>i</C> to <C>j</C>
    whenever there is no edge from <C>i</C> to <C>j</C> in <A>digraph</A>.
    <Example><![CDATA[
gap> gr := Digraph([[2, 3], [], [4, 6], [5], [],
> [7, 8, 9], [], [], []]);
<digraph with 9 vertices, 8 edges>
gap> DigraphDual(gr);
<digraph with 9 vertices, 73 edges>]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphTopologicalSort">
<ManSection>
  <Attr Name="DigraphTopologicalSort" Arg="digraph"/>
  <Returns>A list of positive integers, or <K>fail</K>.</Returns>
  <Description>
    If <A>digraph</A> is a digraph with no cycles of length greater than
    <M>1</M>, then <C>DigraphTopologicalSort</C> returns the vertices of
    <A>digraph</A> ordered so that every edge's source appears no earlier in
    the list than its range.  If the digraph <A>digraph</A> contains cycles
    of length greater than <M>1</M>, then this operation returns
    <K>fail</K>.  <P/>

    The method used for this attribute has complexity <M>O(m+n)</M> where
    <M>m</M> is the number of edges (counting multiple edges as one) and
    <M>n</M> is the number of vertices in the digraph. <P/> 
    <Example><![CDATA[
gap> gr := Digraph([[2, 3], [], [4, 6], [5], [], [7, 8, 9], [],
> [], []]);
<digraph with 9 vertices, 8 edges>
gap> DigraphTopologicalSort(gr);
[ 2, 5, 4, 7, 8, 9, 6, 3, 1 ]
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="AdjacencyMatrix">
<ManSection>
  <Attr Name="AdjacencyMatrix" Arg="digraph"/>
  <Returns>A square matrix of non-negative integers.</Returns>
  <Description>
    This function returns the adjacency matrix <C>mat</C> of the digraph 
    <A>digraph</A>.
    The value of the matrix entry <C>mat[i][j]</C> is the number of edges 
    in <A>digraph</A> with source <C>i</C> and range <C>j</C>.
    
    <Example><![CDATA[
gap> gr := Digraph([[2, 2, 2], [1, 3, 6, 8, 9, 10], [4, 6, 8],
> [1, 2, 3, 9], [3, 3], [3, 5, 6, 10], [1, 2, 7],
> [1, 2, 3, 10, 5, 6, 10], [1, 3, 4, 5, 8, 10], 
> [2, 3, 4, 6, 7, 10]]);
<multidigraph with 10 vertices, 44 edges>
gap> mat := AdjacencyMatrix(gr);;
gap> Display(mat);
[ [  0,  3,  0,  0,  0,  0,  0,  0,  0,  0 ],
  [  1,  0,  1,  0,  0,  1,  0,  1,  1,  1 ],
  [  0,  0,  0,  1,  0,  1,  0,  1,  0,  0 ],
  [  1,  1,  1,  0,  0,  0,  0,  0,  1,  0 ],
  [  0,  0,  2,  0,  0,  0,  0,  0,  0,  0 ],
  [  0,  0,  1,  0,  1,  1,  0,  0,  0,  1 ],
  [  1,  1,  0,  0,  0,  0,  1,  0,  0,  0 ],
  [  1,  1,  1,  0,  1,  1,  0,  0,  0,  2 ],
  [  1,  0,  1,  1,  1,  0,  0,  1,  0,  1 ],
  [  0,  1,  1,  1,  0,  1,  1,  0,  0,  1 ] ]]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="BooleanAdjacencyMatrix">
<ManSection>
  <Attr Name="BooleanAdjacencyMatrix" Arg="digraph"/>
  <Returns>A square matrix of booleans.</Returns>
  <Description>
    If <A>digraph</A> is a digraph with a positive number of vertices
    <C>n</C>, then <C>BooleanAdjacencyMatrix(</C><A>digraph</A><C>)</C>
    returns the boolean adjacency matrix <C>mat</C> of <A>digraph</A>.  The
    value of the matrix entry <C>mat[j][i]</C> is <K>true</K> if and only if
    there exists an edge in <A>digraph</A> with source <C>j</C> and range
    <C>i</C>.<P/>
    
    Note this the boolean adjacency loses information about multiple edges.
    <P/>

    If <A>digraph</A> has no vertices, then this attribute returns the empty
    list.
    <Example><![CDATA[
gap> gr := Digraph([[3, 4], [2, 3], [1, 2, 4], [4]]);
<digraph with 4 vertices, 8 edges>
gap> BooleanAdjacencyMatrix(gr);
[ [ false, false, true, true ], [ false, true, true, false ], 
  [ true, true, false, true ], [ false, false, false, true ] ]
gap> gr := CycleDigraph(4);;
gap> BooleanAdjacencyMatrix(gr);
[ [ false, true, false, false ], [ false, false, true, false ], 
  [ false, false, false, true ], [ true, false, false, false ] ]
gap> BooleanAdjacencyMatrix(EmptyDigraph(0));
[  ]]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="RangeSourceDigraph">
<ManSection>
  <Attr Name="DigraphRange" Arg="digraph"/>
  <Attr Name="DigraphSource" Arg="digraph"/>
  <Returns>A list of positive integers.</Returns>
  <Description>
    <C>DigraphRange</C> and <C>DigraphSource</C> return the range and source of
    the digraph <A>digraph</A>. More precisely, position <C>i</C> in
    <C>DigraphRange(<A>digraph</A>)</C> is the range of the <C>i</C>th edge of
    <A>digraph</A>. 

    <Example><![CDATA[
gap> gr := Digraph([[1, 2, 3, 5], [1, 3, 4], [2, 3], 
> [2], [1, 2, 3, 4]]);
<digraph with 5 vertices, 14 edges>
gap> DigraphRange(gr);
[ 1, 2, 3, 5, 1, 3, 4, 2, 3, 2, 1, 2, 3, 4 ]
gap> DigraphSource(gr);
[ 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 5, 5, 5 ]
gap> DigraphEdges(gr);
[ [ 1, 1 ], [ 1, 2 ], [ 1, 3 ], [ 1, 5 ], [ 2, 1 ], [ 2, 3 ], 
  [ 2, 4 ], [ 3, 2 ], [ 3, 3 ], [ 4, 2 ], [ 5, 1 ], [ 5, 2 ], 
  [ 5, 3 ], [ 5, 4 ] ]
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphEdges">
<ManSection>
  <Attr Name="DigraphEdges" Arg="digraph"/>
  <Returns>A list of lists.</Returns>
  <Description>
    <C>DigraphEdges</C> returns a list of edges of the digraph <A>digraph</A>,
    where each edge is a pair of elements of <Ref Oper="DigraphVertices"/> of
    the form <C>[source,range]</C>.
    <P/>

    The entries of <C>DigraphEdges(</C><A>digraph</A><C>)</C> are in one-to-one
    corresponence with the edges of <A>digraph</A>.  Hence
    <C>DigraphEdges(</C><A>digraph</A><C>)</C> is duplicate-free if and only if
    <A>digraph</A> contains no multiple edges. <P/>

    The entries of <C>DigraphEdges</C> are guaranteed to be sorted by their
    first component (i.e. by the source of each edge), but they are not
    necessarily then sorted by the second component.
    <Example><![CDATA[
gap> gr := Digraph([[1, 3, 4, 3, 5], [1, 2, 3, 5], [2, 4, 5], 
> [2, 4, 5], [1]]);
<multidigraph with 5 vertices, 16 edges>
gap> DigraphEdges(gr);
[ [ 1, 1 ], [ 1, 3 ], [ 1, 4 ], [ 1, 3 ], [ 1, 5 ], [ 2, 1 ], 
  [ 2, 2 ], [ 2, 3 ], [ 2, 5 ], [ 3, 2 ], [ 3, 4 ], [ 3, 5 ], 
  [ 4, 2 ], [ 4, 4 ], [ 4, 5 ], [ 5, 1 ] ]
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphNrEdges">
<ManSection>
  <Attr Name="DigraphNrEdges" Arg="digraph"/>
  <Returns>An integer.</Returns>
  <Description>
    This function returns the number of edges of the digraph <A>digraph</A>.
    <Example><![CDATA[
gap> gr := Digraph([[1, 3, 4, 5], [1, 2, 3, 5], [2, 4, 5], 
> [2, 4, 5], [1]]);;
gap> DigraphNrEdges(gr);
15
gap> gr := Digraph(["a", "b", "c"],
> ["a", "b", "b"],
> ["b", "a", "a"]);
<multidigraph with 3 vertices, 3 edges>
gap> DigraphNrEdges(gr);
3]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="OutNeighbours">
<ManSection>
  <Attr Name="OutNeighbours" Arg="digraph"/>
  <Attr Name="OutNeighbors" Arg="digraph"/>
  <Oper Name="OutNeighboursCopy" Arg="digraph"/>
  <Oper Name="OutNeighborsCopy" Arg="digraph"/>
  <Returns>The adjacencies of a digraph.</Returns>
  <Description>
    This function returns the list <C>out</C> of out-neighbours of each vertex
    of the digraph <A>digraph</A>.
    More specifically, a vertex <C>j</C> appears in <C>out[i]</C> each time
    there exists an edge with source <C>i</C> and range <C>j</C> in 
    <A>digraph</A>. <P/>

    The function <C>OutNeighbours</C> returns an immutable list of immutable 
    lists, whereas the function <C>OutNeighboursCopy</C> returns a copy of
    <C>OutNeighbours</C> which is a mutable list of mutable lists. <P/>
    <Example><![CDATA[
gap> gr := Digraph(["a", "b", "c"],
> ["a", "b", "b"],
> ["b", "a", "c"]);
<digraph with 3 vertices, 3 edges>
gap> OutNeighbours(gr);
[ [ 2 ], [ 1, 3 ], [  ] ]
gap> gr := Digraph(3, 
> [1, 2, 3, 1, 1, 2],
> [1, 2, 3, 2, 3, 1]);
<digraph with 3 vertices, 6 edges>
gap> OutNeighbours(gr);
[ [ 1, 2, 3 ], [ 2, 1 ], [ 3 ] ]
gap> gr := Digraph(3,
> [1, 2, 3, 1, 1, 2, 1],
> [1, 2, 3, 2, 3, 1, 2]);
<multidigraph with 3 vertices, 7 edges>
gap> OutNeighbours(gr);
[ [ 1, 2, 3, 2 ], [ 2, 1 ], [ 3 ] ]
gap> OutNeighboursCopy(gr);
[ [ 1, 2, 3, 2 ], [ 2, 1 ], [ 3 ] ]
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="InNeighbours">
<ManSection>
  <Attr Name="InNeighbours" Arg="digraph"/>
  <Attr Name="InNeighbors" Arg="digraph"/>
  <Returns>A list of lists of vertices.</Returns>
  <Description>
    This function returns the list <C>inn</C> of in-neighbours of each vertex
    of the digraph <A>digraph</A>.
    More specifically, a vertex <C>j</C> appears in <C>inn[i]</C> each time
    there exists an edge with source <C>j</C> and range <C>i</C> in
    <A>digraph</A>. <P/>
    
    Note that each entry of <C>inn</C> is sorted into ascending order. <P/>

    <Example><![CDATA[
gap> gr := Digraph(["a", "b", "c"],
> ["a", "b", "b"],
> ["b", "a", "c"]);
<digraph with 3 vertices, 3 edges>
gap> InNeighbours(gr);
[ [ 2 ], [ 1 ], [ 2 ] ]
gap> gr := Digraph(3, 
> [1, 2, 3, 1, 1, 2],
> [1, 2, 3, 2, 3, 1]);
<digraph with 3 vertices, 6 edges>
gap> InNeighbours(gr);
[ [ 1, 2 ], [ 1, 2 ], [ 1, 3 ] ]
gap> gr := Digraph(3,
> [1, 2, 3, 1, 1, 2, 1],
> [1, 2, 3, 2, 3, 1, 2]);
<multidigraph with 3 vertices, 7 edges>
gap> InNeighbours(gr);
[ [ 1, 2 ], [ 1, 1, 2 ], [ 1, 3 ] ]
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="OutDegrees">
<ManSection>
  <Attr Name="OutDegrees" Arg="digraph"/>
  <Attr Name="OutDegreeSequence" Arg="digraph"/>
  <Attr Name="OutDegreeSet" Arg="digraph"/>
  <Returns>A list of non-negative integers.</Returns>
  <Description>

    Given a digraph <A>digraph</A> with <M>n</M> vertices, the function
    <C>OutDegrees</C> returns a list <C>out</C> of length <M>n</M>, such that 
    for a vertex <C>i</C> in <A>digraph</A>, the value of <C>out[i]</C> is the 
    out-degree of vertex <C>i</C>.
    See <Ref Oper="OutDegreeOfVertex"/>. <P/>

    The function <C>OutDegreeSequence</C> returns the same list,
    after it has been sorted into non-increasing order. <P/>

    The function <C>OutDegreeSet</C> returns the same list, sorted into
    increasing order with duplicate entries removed. <P/>

    <Example><![CDATA[
gap> gr := Digraph([[1, 3, 2, 2], [], [2, 1], []]);
<multidigraph with 4 vertices, 6 edges>
gap> OutDegrees(gr);
[ 4, 0, 2, 0 ]
gap> OutDegreeSequence(gr);
[ 4, 2, 0, 0 ]
gap> OutDegreeSet(gr);
[ 0, 2, 4 ]
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="InDegrees">
<ManSection>
  <Attr Name="InDegrees" Arg="digraph"/>
  <Attr Name="InDegreeSequence" Arg="digraph"/>
  <Attr Name="InDegreeSet" Arg="digraph"/>
  <Returns>A list of non-negative integers.</Returns>
  <Description>

    Given a digraph <A>digraph</A> with <M>n</M> vertices, the function
    <C>InDegrees</C> returns a list <C>inn</C> of length <M>n</M>, such that 
    for a vertex <C>i</C> in <A>digraph</A>, the value of <C>inn[i]</C> is 
    the in-degree of vertex <C>i</C>.
    See <Ref Oper="InDegreeOfVertex"/>. <P/>

    The function <C>InDegreeSequence</C> returns the same list, 
    after it has been sorted into non-increasing order. <P/>

    The function <C>InDegreeSet</C> returns the same list, sorted into
    increasing order with duplicate entries removed. <P/>

    <Example><![CDATA[
gap> gr := Digraph( [ [ 1, 3, 2, 2, 4 ], [ ], [ 2, 1, 4 ], [ ] ] );
<multidigraph with 4 vertices, 8 edges>
gap> InDegrees(gr);
[ 2, 3, 1, 2 ]
gap> InDegreeSequence(gr);
[ 3, 2, 2, 1 ]
gap> InDegreeSet(gr);
[ 1, 2, 3 ]
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphVertices">
<ManSection>
  <Attr Name="DigraphVertices" Arg="digraph"/>
  <Returns>A list of integers.</Returns>
  <Description>
    Returns the vertices of the digraph <A>digraph</A>. <P/>

    Note that the vertices of a digraph are always a range of
    positive integers from <C>1</C> to the number of vertices of the graph. 
    <Example><![CDATA[
gap> gr := Digraph( [ "a", "b", "c" ],
> [ "a", "b", "b" ],
> [ "b", "c", "a" ] );
<digraph with 3 vertices, 3 edges>
gap> DigraphVertices(gr);
[ 1 .. 3 ]
gap> gr := Digraph( [ 1, 2, 3, 4, 5, 7 ],
> [ 1, 2, 2, 4, 4 ],
> [ 2, 3, 5, 3, 5 ] );
<digraph with 6 vertices, 5 edges>
gap> DigraphVertices(gr);
[ 1 .. 6 ]
gap> DigraphVertices(RandomDigraph(100));
[ 1 .. 100 ]
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphNrVertices">
<ManSection>
  <Attr Name="DigraphNrVertices" Arg="digraph"/>
  <Returns>An integer.</Returns>
  <Description>
    Returns the number of vertices of the digraph <A>digraph</A>. <P/>

    <Example><![CDATA[
gap> gr := Digraph( [ "a", "b", "c" ],
> [ "a", "b", "b" ],
> [ "b", "c", "a" ] );
<digraph with 3 vertices, 3 edges>
gap> DigraphNrVertices(gr);
3
gap> gr := Digraph( [ 1, 2, 3, 4, 5, 7 ],
> [ 1, 2, 2, 4, 4 ], 
> [ 2, 3, 5, 3, 5 ] );
<digraph with 6 vertices, 5 edges>
gap> DigraphNrVertices(gr);
6
gap> DigraphNrVertices(RandomDigraph(100));
100]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphStronglyConnectedComponents">
<ManSection>
  <Attr Name="DigraphStronglyConnectedComponents" Arg="digraph"/>
  <Returns>A record.</Returns>
  <Description>
    This function returns the record <C>scc</C> corresponding to the strongly
    connected components of the digraph <A>digraph</A>.  Two vertices of
    <A>digraph</A> are in the same strongly connected component whenever they
    are equal, or there is a directed path from each vertex to the other.  The
    set of strongly connected components is a partition of the vertex set of
    <A>digraph</A>.
    <P/>

    The record <C>scc</C> has 2 components: <C>comps</C> and <C>id</C>.
    The component <C>comps</C> is a list of the strongly connected components
    of <A>digraph</A> (each of which is a list of vertices).
    The component <C>id</C> is a list such that the vertex <C>i</C> is an
    element of the strongly connected component <C>comps[id[i]]</C>. <P/>

    The method used in this function is a non-recursive version of Gabow's
    Algorithm <Cite Key="Gabow2000aa"/> and has complexity <M>O(m+n)</M> where
    <M>m</M> is the number of edges (counting multiple edges as one) and
    <M>n</M> is the number of vertices in the digraph. 
    
    <Example><![CDATA[
gap> gr := Digraph( [ "a", "b", "c" ],
> [ "a", "b", "b" ],
> [ "b", "c", "a" ] );
<digraph with 3 vertices, 3 edges>
gap> DigraphStronglyConnectedComponents(gr);
rec( comps := [ [ 3 ], [ 1, 2 ] ], id := [ 2, 2, 1 ] )
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

#

<#GAPDoc Label="DigraphConnectedComponents">
<ManSection>
  <Attr Name="DigraphConnectedComponents" Arg="digraph"/>
  <Returns>A record.</Returns>
  <Description>
    This function returns the record <C>wcc</C> corresponding to the weakly
    connected components of the digraph <A>digraph</A>.  Two vertices of
    <A>digraph</A> are in the same weakly connected component whenever they are
    equal, or there exists a path (ignoring the orientation of edges) between
    them.  In other words, two vertices are in the same weakly connected
    component of <A>digraph</A> if and only if they are in the same strongly
    connected component (see <Ref Attr="DigraphStronglyConnectedComponents"/>)
    of the <Ref Attr="DigraphSymmetricClosure"/> of <A>digraph</A>.  <P/>

    The set of weakly connected components is a partition of
    the vertex set of <A>digraph</A>. <P/>

    The record <C>wcc</C> has 2 components: <C>comps</C> and <C>id</C>.
    The component <C>comps</C> is a list of the weakly connected components
    of  <A>digraph</A> (each of which is a list of vertices).
    The component <C>id</C> is a list such that the vertex <C>i</C> is an 
    element of the weakly connected component <C>comps[id[i]]</C>. <P/>

    The method used in this function has complexity  <M>O(m+n)</M>, where
    <M>m</M> is the number of edges and
    <M>n</M> is the number of vertices in the digraph. 
    
    <Example><![CDATA[
gap> gr := Digraph( [ "a", "b", "c" ],
> [ "a", "b", "b" ], 
> [ "b", "c", "a" ] );
<digraph with 3 vertices, 3 edges>
gap> DigraphConnectedComponents(gr);
rec( comps := [ [ 1, 2, 3 ] ], id := [ 1, 1, 1 ] )
gap> gr := Digraph( [ [ 1 ], [ 1, 2 ], [  ] ] );
<digraph with 3 vertices, 3 edges>
gap> DigraphConnectedComponents(gr);
rec( comps := [ [ 1, 2 ], [ 3 ] ], id := [ 1, 1, 2 ] )
gap> gr := Digraph( [ ] );
<digraph with 0 vertices, 0 edges>
gap> DigraphConnectedComponents(gr);
rec( comps := [  ], id := [  ] )
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

#

<#GAPDoc Label="DigraphShortestDistances">
<ManSection>
  <Attr Name="DigraphShortestDistances" Arg="digraph"/>
  <Returns>A square matrix.</Returns>
  <Description>
    If <A>digraph</A> is a digraph with <M>n</M> vertices, then this 
    function returns an <M>n \times n</M> matrix <C>mat</C>, where each entry is
    either a non-negative integer or <C>fail</C>.  If <M>n = 0</M>, then an
    empty list is returned. <P/>
    
    If there is a directed path from vertex <C>i</C> to vertex <C>j</C>, then
    the value of <C>mat[i][j]</C> is the length of the shortest such path. If
    no such path exists, then the value of <C>mat[i][j]</C> is <C>fail</C>.
    We use the convention that the distance from every vertex to itself is
    <C>0</C>, i.e. <C>mat[i][i] = 0</C> for all vertices <C>i</C>. <P/>

    The method used in this function is a version of the Floyd-Warshall 
    algorithm, and has complexity <M>O(n^3)</M>.
    
    <Example><![CDATA[
gap> gr := Digraph( [ [ 1, 2 ], [ 3 ], [ 1, 2 ], [ 4 ] ] );
<digraph with 4 vertices, 6 edges>
gap> mat := DigraphShortestDistances(gr);;
gap> Display(mat);
[ [     0,     1,     2,  fail ],
  [     2,     0,     1,  fail ],
  [     1,     1,     0,  fail ],
  [  fail,  fail,  fail,     0 ] ]
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

#

<#GAPDoc Label="DigraphSinks">
<ManSection>
  <Attr Name="DigraphSinks" Arg="digraph"/>
  <Returns>A list of vertices.</Returns>
  <Description>
    This function returns a list of the sinks of the digraph
    <A>digraph</A>.
    A sink of a digraph is a vertex with out-degree zero.
    See <Ref Oper="OutDegreeOfVertex"/>.
    <Example><![CDATA[
gap> gr := Digraph( [ [ 3, 5, 2, 2 ], [ 3 ], [  ], [ 5, 2, 5, 3 ], [  ] ] );
<multidigraph with 5 vertices, 9 edges>
gap> DigraphSinks(gr);
[ 3, 5 ]
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphSources">
<ManSection>
  <Attr Name="DigraphSources" Arg="digraph"/>
  <Returns>A list of vertices.</Returns>
  <Description>
    This function returns a list of the sources of the digraph 
    <A>digraph</A>.
    A source of a digraph is a vertex with in-degree zero.
    See <Ref Oper="InDegreeOfVertex"/>.
    <Example><![CDATA[
gap> gr := Digraph( [ [ 3, 5, 2, 2 ], [ 3 ], [  ], [ 5, 2, 5, 3 ], [  ] ] );
<multidigraph with 5 vertices, 9 edges>
gap> DigraphSources(gr);
[ 1, 4 ]
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphPeriod">
<ManSection>
  <Attr Name="DigraphPeriod" Arg="digraph"/>
  <Returns>An integer.</Returns>
  <Description>
    This function returns the period of the digraph <A>digraph</A>.<P/>

    If a digraph <A>digraph</A> has at least one cycle, then the
    period is the greatest positive integer which divides the lengths of all 
    cycles of <A>digraph</A>.
    If <A>digraph</A> has no cycles, then this function returns <M>0</M>.<P/>
    
    A digraph with a period of <M>1</M> is said to be <E>aperiodic</E>.
    See <Ref Prop="IsAperiodicDigraph"/>. <P/>
    <Example><![CDATA[
gap> gr := Digraph( [ [ 6 ], [ 1 ], [ 2 ], [ 3 ], [ 4, 4 ], [ 5 ] ] );
<multidigraph with 6 vertices, 7 edges>
gap> DigraphPeriod(gr);
6
gap> gr := Digraph( [ [ 2 ], [ 3, 5 ], [ 4 ], [ 5 ], [ 1, 2 ] ] );
<digraph with 5 vertices, 7 edges>
gap> DigraphPeriod(gr);
1
gap> gr := Digraph( [ [ 2 ], [ ] ] );
<digraph with 2 vertices, 1 edge>
gap> DigraphPeriod(gr);
0
gap> IsAcyclicDigraph(gr);
true
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphDiameter">
<ManSection>
  <Attr Name="DigraphDiameter" Arg="digraph"/>
  <Returns>An integer or <C>fail</C>.</Returns>
  <Description>
    This function returns the diameter of the digraph <A>digraph</A>.
    <P/>

    If a digraph <A>digraph</A> is strongly connected and has at least 1
    vertex, then the <E>diameter</E> is the maximum shortest distance between
    any pair of distinct vertices. Otherwise then the diameter of
    <A>digraph</A> is undefined, and this function returns the value
    <C>fail</C>. <P/>
    
    See <Ref Attr="DigraphShortestDistances"/>. <P/>
    <Example><![CDATA[
gap> gr := Digraph( [ [ 2 ], [ 3 ], [ 4, 5 ], [ 5 ], 
> [ 1, 2, 3, 4, 5 ] ] );
<digraph with 5 vertices, 10 edges>
gap> DigraphDiameter(gr);
3
gap> gr := Digraph( [ [ 2 ], [  ] ] );
<digraph with 2 vertices, 1 edge>
gap> DigraphDiameter(gr);
fail
gap> IsStronglyConnectedDigraph(gr);
false
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphUndirectedGirth">
<ManSection>
  <Attr Name="DigraphUndirectedGirth" Arg="digraph"/>
  <Returns>An integer or <C>infinity</C>.</Returns>
  <Description>
    If <A>digraph</A> is a symmetric digraph, then this function returns the
    girth of <A>digraph</A> when treated as an undirected graph (i.e. each pair
    of edges <M>[i, j]</M> and <M>[j, i]</M> is treated as a single edge between
    <M>i</M> and <M>j</M>). <P/>

    The <E>girth</E> of an undirected graph is the length of its shortest simple
    cycle, i.e. the shortest non-trivial path starting and ending at the same
    vertex and passing through no vertex more than once. <P/>

    If <A>digraph</A> has no cycles, then this function will return
    <C>infinity</C>. <P/>
    <Example><![CDATA[
gap> gr := Digraph([[2,4], [1,3], [2,4], [1,3]]);
<digraph with 4 vertices, 8 edges>
gap> DigraphUndirectedGirth(gr);
4
gap> gr := Digraph([[2], [1,3], [2]]);
<digraph with 3 vertices, 4 edges>
gap> DigraphUndirectedGirth(gr);      
infinity
gap> gr := Digraph([[1], [], [4], [3]]);
<digraph with 4 vertices, 3 edges>
gap> DigraphUndirectedGirth(gr);
1
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphGirth">
<ManSection>
  <Attr Name="DigraphGirth" Arg="digraph"/>
  <Returns>An integer or <C>infinity</C>.</Returns>
  <Description>
    The <E>girth</E> of a digraph is the length of its shortest simple cycle,
    i.e. the shortest non-trivial directed path starting and ending at the same
    vertex and passing through no vertex more than once. 
    <P/>

    If <A>digraph</A> has no cycles, then this function will return
    <C>infinity</C>.  If <A>digraph</A> contains a loop, then this function will
    return <C>1</C>. 
    <P/>

    In the worst case, the method used in this function is a version of the
    Floyd-Warshall algorithm, and has complexity <C>O(<A>n</A> ^ 3)</C>, where
    <A>n</A> is the number of vertices in <A>digraph</A>.  If the digraph has
    known automorphisms [see <Ref Attr="DigraphGroup"/>], then the performance
    is likely to be better.
    <P/>

    For symmetric digraphs, see also <Ref Oper="DigraphUndirectedGirth"/>. <P/>
    <Example><![CDATA[
gap> gr := Digraph([[1], [1]]);
<digraph with 2 vertices, 2 edges>
gap> DigraphGirth(gr);
1
gap> gr := Digraph([[2, 3], [3], [4], []]);
<digraph with 4 vertices, 4 edges>
gap> DigraphGirth(gr);
infinity
gap> gr := Digraph([[2, 3], [3], [4], [1]]);
<digraph with 4 vertices, 5 edges>
gap> DigraphGirth(gr);
3
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="ReducedDigraph">
<ManSection>
  <Attr Name="ReducedDigraph" Arg="digraph"/>
  <Returns>A digraph.</Returns>
  <Description>
    This function returns a digraph isomorphic to the subdigraph of 
    <A>digraph</A> induced by the set of non-isolated vertices,
    i.e. the set of those vertices of <A>digraph</A> which are the source or 
    range of some edge in <A>digraph</A>.
    See <Ref Oper="InducedSubdigraph"/>.
    <P/>
    
    The vertex labels of the graph are preserved, so that a vertex in the new
    digraph can be matched to the corresponding vertex in <A>digraph</A>.<P/>
    <Example><![CDATA[
gap> d := Digraph([ [ 1, 2 ], [  ], [  ], [ 1, 4 ], [  ] ]);
<digraph with 5 vertices, 4 edges>
gap> r := ReducedDigraph(d);
<digraph with 3 vertices, 4 edges>
gap> OutNeighbours(r);
[ [ 1, 3 ], [ 1, 2 ], [  ] ]
gap> DigraphEdges(r); DigraphEdges(d);
[ [ 1, 1 ], [ 1, 3 ], [ 2, 1 ], [ 2, 2 ] ]
[ [ 1, 1 ], [ 1, 2 ], [ 4, 1 ], [ 4, 4 ] ]
gap> DigraphVertexLabel(r, 3);
2
gap> DigraphVertexLabel(r, 2);
4]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphSymmetricClosure">
<ManSection>
  <Attr Name="DigraphSymmetricClosure" Arg="digraph"/>
  <Returns>A digraph.</Returns>
  <Description>
    If <A>digraph</A> is a digraph, then this attribute gives the minimal
    symmetric digraph which has the same vertices and contains all the edges of
    <A>digraph</A>.
    See <Ref Prop="IsSymmetricDigraph"/>.
    A digraph is symmetric if, whenever there is an edge from <C>i</C> to
    <C>j</C>, there is also an edge from <C>j</C> to <C>i</C>. <P/>

<Example><![CDATA[
gap> gr := Digraph([[1,2,3], [2,4], [1], [3,4]]);
<digraph with 4 vertices, 8 edges>
gap> gr1 := DigraphSymmetricClosure(gr);
<digraph with 4 vertices, 11 edges>
gap> IsSymmetricDigraph(gr1);
true
gap> OutNeighbours(gr1);
[ [ 1, 2, 3 ], [ 2, 4, 1 ], [ 1, 4 ], [ 3, 4, 2 ] ]
gap> gr := Digraph([[2, 2], [1]]);
<multidigraph with 2 vertices, 3 edges>
gap> gr1 := DigraphSymmetricClosure(gr);
<multidigraph with 2 vertices, 4 edges>
gap> OutNeighbours(gr1);
[ [ 2, 2 ], [ 1, 1 ] ]
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphReflexiveTransitiveClosure">
<ManSection>
  <Attr Name="DigraphReflexiveTransitiveClosure" Arg="digraph"/>
  <Attr Name="DigraphTransitiveClosure" Arg="digraph"/>
  <Returns>A digraph.</Returns>
  <Description>
    If <A>digraph</A> is a digraph with no multiple edges, then these
    attributes return the (reflexive) transitive closure of <A>digraph</A>.
    <P/>

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

    Let <M>n</M> be the number of vertices of <A>digraph</A>, and let
    <M>m</M> be the number of edges.  For an arbitrary digraph, these
    attributes will use a version of the Floyd-Warshall algorithm, with
    complexity <M>O(n^3)</M>.

    However, for a topologically sortable digraph [see <Ref
      Attr="DigraphTopologicalSort"/>], these attributes will use methods
    with complexity <M>O(m + n + m \cdot n)</M> when this is faster.  <P/>

    <Example><![CDATA[
gap> gr := Digraph( [ [ 4, 6 ], [ 1, 3 ], [  ], [ 5 ], [  ],
> [ 7, 8, 9 ], [  ], [  ], [  ] ] );;
gap> DigraphTransitiveClosure(gr);
<digraph with 9 vertices, 18 edges>
gap> OutNeighbours(last);
[ [ 4, 5, 6, 7, 8, 9 ], [ 1, 3, 4, 5, 6, 7, 8, 9 ], [  ], [ 5 ], 
  [  ], [ 7, 8, 9 ], [  ], [  ], [  ] ]
gap> DigraphReflexiveTransitiveClosure(gr);  
<digraph with 9 vertices, 27 edges>
gap> OutNeighbours(last);
[ [ 1, 4, 5, 6, 7, 8, 9 ], [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ], [ 3 ], 
  [ 4, 5 ], [ 5 ], [ 6, 7, 8, 9 ], [ 7 ], [ 8 ], [ 9 ] ]
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphBicomponents">
<ManSection>
  <Attr Name="DigraphBicomponents" Arg="digraph"/>
  <Returns>A pair of lists of vertices, or <K>fail</K>.</Returns>
  <Description>
    If <A>digraph</A> is a bipartite digraph, i.e. if it satisfies <Ref
      Prop="IsBipartiteDigraph"/>, then <C>DigraphBicomponents</C> returns a
    pair of bicomponents of <A>digraph</A>. Otherwise,
    <C>DigraphBicomponents</C> returns <K>fail</K>.<P/>
    
    For a bipartite digraph, the vertices can be partitioned into two non-empty
    sets such that the source and range of any edge are in distinct sets. The
    parts of this partition are called <E>bicomponents</E> of <A>digraph</A>.
    Equivalently, a pair of bicomponents of <A>digraph</A> consists of the
    color-classes of a 2-coloring of <A>digraph</A>. <P/>

    For a bipartite digraph with at least 3 vertices, there is a unique pair of
    bicomponents of bipartite if and only if the digraph is connected. See <Ref
      Prop="IsConnectedDigraph"/> for more information.
    <Example><![CDATA[
gap> gr := CycleDigraph(3);
<digraph with 3 vertices, 3 edges>
gap> DigraphBicomponents(gr);
fail
gap> gr := ChainDigraph(5);
<digraph with 5 vertices, 4 edges>
gap> DigraphBicomponents(gr);
[ [ 1, 3, 5 ], [ 2, 4 ] ]
gap> gr := Digraph([[5], [1, 4], [5], [5], []]);
<digraph with 5 vertices, 5 edges>
gap> DigraphBicomponents(gr);
[ [ 1, 3, 4 ], [ 2, 5 ] ]]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphAllSimpleCircuits">
<ManSection>
  <Attr Name="DigraphAllSimpleCircuits" Arg="digraph"/>
  <Returns>A list of lists of vertices.</Returns>
  <Description>
    If <A>digraph</A> is a digraph, then <C>DigraphAllSimpleCircuits</C>
    returns a list of the <E>simple circuits</E> in <A>digraph</A>. <P/>
    
    A <E>simple circuit</E> in <A>digraph</A> is a non-trivial directed path
    in <A>digraph</A> from a vertex <C>v</C> back to <C>v</C>, in which no
    vertex is visited more than once. Since a circuit of length <C>n</C> is
    determined by its first <C>n</C> vertices, a circuit <M>v_{1} \rightarrow
      \cdots \rightarrow v_{n} \rightarrow v_{1}</M> can be represented as
    the list <M>[v_{1}, \ldots, v_{n}]</M>. For each simple circuit of
    <A>digraph</A>, <C>DigraphAllSimpleCircuits(</C><A>digraph</A><C>)</C>
    will include precisely one such list to represents the circuit (cyclic
    permutations of such a list describe the same circuit).
    <P/>

    Note that a loop is a simple circuit.

    <Example><![CDATA[
gap> gr := Digraph([[], [3], [2, 4], [5, 4], [4]]);
<digraph with 5 vertices, 6 edges>
gap> DigraphAllSimpleCircuits(gr);
[ [ 4 ], [ 4, 5 ], [ 2, 3 ] ]
gap> gr := ChainDigraph(10);;
gap> DigraphAllSimpleCircuits(gr);
[  ]
gap> gr := Digraph([[3], [1], [1]]);
<digraph with 3 vertices, 3 edges>
gap> DigraphAllSimpleCircuits(gr);
[ [ 1, 3 ] ]]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphLongestSimpleCircuit">
<ManSection>
  <Attr Name="DigraphLongestSimpleCircuit" Arg="digraph"/>
  <Returns>A list of vertices or <C>fail</C>.</Returns>
  <Description>
    If <A>digraph</A> is a digraph, then <C>DigraphLongestSimpleCircuit</C>
    returns the longest <E>simple circuit</E> in <A>digraph</A>. <P/>

    A <E>simple circuit</E> in <A>digraph</A> is a non-trivial directed path
    in <A>digraph</A> from a vertex <C>v</C> back to <C>v</C>, in which no
    vertex is visited more than once. Since a circuit of length <C>n</C> is
    determined by its first <C>n</C> vertices, a circuit <M>v_{1} \rightarrow
      \cdots \rightarrow v_{n} \rightarrow v_{1}</M> can be represented as
    the list <M>[v_{1}, \ldots, v_{n}]</M>. Note that a loop is a simple
    circuit. <P/>

    If <A>digraph</A> has no simple circuits, then this attribute returns
    <C>fail</C>.  If <A>digraph</A> has multiple simple circuits of maximum
    length, then this attribute returns one of them.<P/>

    See <Ref Attr="DigraphAllSimpleCircuits"/>. <P/>

    <Example><![CDATA[
gap> gr := Digraph([[], [3], [2, 4], [5, 4], [4]]);;
gap> DigraphLongestSimpleCircuit(gr);
[ 4, 5 ]
gap> gr := ChainDigraph(10);;
gap> DigraphLongestSimpleCircuit(gr);
fail
gap> gr := Digraph([[3], [1], [1, 4], [1, 1]]);;
gap> DigraphLongestSimpleCircuit(gr);
[ 1, 3, 4 ]]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphLoops">
<ManSection>
  <Attr Name="DigraphLoops" Arg="digraph"/>
  <Returns>A list of vertices.</Returns>
  <Description>
    If <A>digraph</A> is a digraph, then <C>DigraphLoops</C> returns the list
    consisting of the <Ref Attr="DigraphVertices"/> of <A>digraph</A>
    at which there is a loop. See <Ref Prop="DigraphHasLoops"/>. <P/>

    <Example><![CDATA[
gap> gr := Digraph([[2], [3], []]);
<digraph with 3 vertices, 2 edges>
gap> DigraphHasLoops(gr);
false
gap> DigraphLoops(gr);
[  ]
gap> gr := Digraph([[3, 5], [1], [2, 4, 3], [4], [2, 1]]);
<digraph with 5 vertices, 9 edges>
gap> DigraphLoops(gr);
[ 3, 4 ]]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphDegeneracy">
<ManSection>
  <Attr Name="DigraphDegeneracy" Arg="digraph"/>
  <Returns>A non-negative integer, or <K>fail</K>.</Returns>
  <Description>
    If <A>digraph</A> is a symmetric digraph without multiple edges - see
    <Ref Prop="IsSymmetricDigraph"/> and <Ref Prop="IsMultiDigraph"/> - then
    this attribute returns the degeneracy of <A>digraph</A>. <P/>

    The degeneracy of a digraph is the least integer <C>k</C> such
    that every induced of <A>digraph</A> contains a vertex whose number of
    neighbours (excluding itself) is at most <C>k</C>. Note that this means
    that loops are ignored.<P/>

    If <A>digraph</A> is not symmetric or has multiple edges then this
    attribute returns <K>fail</K>.
    <Example><![CDATA[
gap> gr := DigraphSymmetricClosure(ChainDigraph(5));;
gap> DigraphDegeneracy(gr);
1
gap> gr := CompleteDigraph(5);;
gap> DigraphDegeneracy(gr);
4
gap> gr := Digraph([[1], [2, 4, 5], [3, 4], [2, 3, 4], [2], []]);
<digraph with 6 vertices, 10 edges>
gap> DigraphDegeneracy(gr);
1]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphDegeneracyOrdering">
<ManSection>
  <Attr Name="DigraphDegeneracyOrdering" Arg="digraph"/>
  <Returns>A list of integers, or <K>fail</K>.</Returns>
  <Description>
    If <A>digraph</A> is a digraph for which
    <C>DigraphDegeneracy(</C><A>digraph</A><C>)</C> is a non-negative integer
    <C>k</C> - see <Ref Attr="DigraphDegeneracy"/> - then this attribute
    returns a degeneracy ordering of the vertices of the vertices of
    <A>digraph</A>.<P/>

    A degeneracy ordering of <A>digraph</A> is a list <C>ordering</C> of the
    vertices of <A>digraph</A> ordered such that for any
    position <C>i</C> of the list, the vertex <C>ordering[i]</C> has at most
    <C>k</C> neighbours in later position of the list.<P/>

    If <C>DigraphDegeneracy(</C><A>digraph</A><C>)</C> returns <K>fail</K>,
    then this attribute returns <K>fail</K>.
    <Example><![CDATA[
gap> gr := DigraphSymmetricClosure(ChainDigraph(5));;
gap> DigraphDegeneracyOrdering(gr);
[ 5, 4, 3, 2, 1 ]
gap> gr := CompleteDigraph(5);;
gap> DigraphDegeneracyOrdering(gr);
[ 5, 4, 3, 2, 1 ]
gap> gr := Digraph([[1], [2, 4, 5], [3, 4], [2, 3, 4], [2], []]);
<digraph with 6 vertices, 10 edges>
gap> DigraphDegeneracyOrdering(gr);
[ 1, 6, 5, 2, 4, 3 ]]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="MaximalSymmetricSubdigraph">
<ManSection>
  <Attr Name="MaximalSymmetricSubdigraph" Arg="digraph"/>
  <Attr Name="MaximalSymmetricSubdigraphWithoutLoops" Arg="digraph"/>
  <Returns>A digraph.</Returns>
  <Description>
    If <A>digraph</A> is a digraph, then <C>MaximalSymmetricSubdigraph</C>
    returns a symmetric digraph without multiple edges which has the same
    vertex set as <A>digraph</A>, and whose edge list is formed from
    <A>digraph</A> by ignoring the multiplicity of edges, and by ignoring
    edges <C>[u,v]</C> for which there does not exist an edge <C>[v,u]</C>.
    <P/>

    The digraph returned by <C>MaximalSymmetricSubdigraphWithoutLoops</C> is
    the same, except that loops are removed.<P/>

    See <Ref Prop="IsSymmetricDigraph"/>, <Ref Prop="IsMultiDigraph"/>, and
    <Ref Prop="DigraphHasLoops"/> for more information.
    <Example><![CDATA[
gap> gr := Digraph([[2, 2], [1, 3], [4], [3, 1]]);
<multidigraph with 4 vertices, 7 edges>
gap> not IsSymmetricDigraph(gr) and IsMultiDigraph(gr);
true
gap> OutNeighbours(gr);
[ [ 2, 2 ], [ 1, 3 ], [ 4 ], [ 3, 1 ] ]
gap> sym := MaximalSymmetricSubdigraph(gr);
<digraph with 4 vertices, 4 edges>
gap> IsSymmetricDigraph(sym) and not IsMultiDigraph(sym);
true
gap> OutNeighbours(sym);
[ [ 2 ], [ 1 ], [ 4 ], [ 3 ] ]
]]></Example>
  </Description>
</ManSection>
<#/GAPDoc>
