@@ -784,3 +784,165 @@ function(D)
784784 fi ;
785785 od ;
786786end );
787+
788+ InstallMethod(IsCograph,
789+ " for an immutable digraph" ,
790+ [ IsImmutableDigraph] ,
791+ function (D )
792+ local V, P, x, N, parts, unused_parts, p, C, k, y, M, X, X_a,
793+ used_pivots, C_origin, po, lpart, rpart, zl, zr, origin,
794+ sigma, posx, prec, succ, N_prec, N_succ;
795+
796+ # D must be a symmetric digraph without loops or multiple edges
797+ if not IsSymmetricDigraph(D) then ;
798+ Error(" IsCograph: argument must be a symmetric digraph" );
799+ elif DigraphHasLoops(D) then ;
800+ Error(" IsCograph: argument must be a digraph without loops" );
801+ elif IsMultiDigraph(D) then ;
802+ Error(" IsCograph: argument must be a digraph without multiple edges" );
803+ fi ;
804+
805+ V := DigraphVertices(D);
806+
807+ if Length(V) < 4 then
808+ return true ;
809+ fi ;
810+
811+ P := [ V] ;
812+ used_pivots := [] ;
813+ origin := V[ 1 ] ;
814+
815+ # If origin is an isolated or universal vertex, then recurse
816+ # on D[V \ {origin}]
817+ if Length(OutNeighboursOfVertex(D, origin)) = 0 or
818+ Length(OutNeighboursOfVertex(D, origin)) = Length(V) - 1 then
819+ return IsCograph(DigraphRemoveVertex(D, origin));
820+ fi ;
821+
822+ while not ForAll(P, p -> Length(p) <= 1 ) do
823+ C_origin := First(P, p -> origin in p);
824+
825+ # Initialise
826+ N := IntersectionSet(OutNeighboursOfVertex(D, origin), C_origin);
827+ parts := [ N, [ origin] , Difference(C_origin, UnionSet(N, [ origin] ))] ;
828+ unused_parts := Filtered([ parts[ 1 ] , parts[ 3 ]] , p -> Length(p) > 0 );
829+ k := Position(P, C_origin);
830+ Remove(P, k);
831+ for p in parts do
832+ if Length(p) > 0 then
833+ Add(P, p, k);
834+ fi ;
835+ od ;
836+
837+ # Refine
838+ while Length(unused_parts) > 0 do
839+ C := unused_parts[ 1 ] ;
840+ y := C[ 1 ] ;
841+ Add(used_pivots, y);
842+ N := OutNeighboursOfVertex(D, y);
843+ M := Filtered(P, p -> Length(IntersectionSet(p, N)) > 0 and
844+ not IsSubset(N, p) and
845+ p <> C);
846+ for X in M do
847+ X_a := IntersectionSet(X, N);
848+ k := Position(P, X);
849+ Remove(P, k);
850+ Add(P, X_a, k);
851+ Add(P, Difference(X, X_a), k);
852+ if X in unused_parts then
853+ Remove(unused_parts, Position(unused_parts, X));
854+ Add(unused_parts, X_a);
855+ Add(unused_parts, Difference(X, X_a));
856+ else
857+ x := IntersectionSet(used_pivots, X)[ 1 ] ;
858+ if x in X_a then
859+ Add(unused_parts, Difference(X, X_a));
860+ else
861+ Add(unused_parts, X_a);
862+ fi ;
863+ fi ;
864+ od ;
865+ Remove(unused_parts, Position(unused_parts, C));
866+ od ;
867+
868+ # Choose new origin
869+ lpart := [] ;
870+ rpart := [] ;
871+ po := Position(P, [ origin] );
872+ for p in P{[ 1 .. po - 1 ]} do
873+ if Length(p) > 1 then
874+ Add(lpart, p);
875+ fi ;
876+ od ;
877+ for p in P{[ po + 1 .. Length(P)]} do
878+ if Length(p) > 1 then
879+ Add(rpart, p);
880+ fi ;
881+ od ;
882+
883+ if IsEmpty(lpart) then
884+ if IsEmpty(rpart) then
885+ continue ;
886+ fi ;
887+ origin := IntersectionSet(used_pivots, rpart[ 1 ] )[ 1 ] ;
888+ elif IsEmpty(rpart) then
889+ origin := IntersectionSet(used_pivots, Last(lpart))[ 1 ] ;
890+ else
891+ zl := IntersectionSet(used_pivots, Last(lpart))[ 1 ] ;
892+ zr := IntersectionSet(used_pivots, rpart[ 1 ] )[ 1 ] ;
893+ if zl in OutNeighboursOfVertex(D, zr) then
894+ origin := zl;
895+ else
896+ origin := zr;
897+ fi ;
898+ fi ;
899+ od ;
900+
901+ # Recognition Test
902+ sigma := [ 0 ] ;
903+ for p in P do
904+ Add(sigma, p[ 1 ] );
905+ od ;
906+ Add(sigma, Length(V) + 1 );
907+
908+ # move left to right
909+ posx := 2 ;
910+ x := sigma[ posx] ;
911+ while x <> Length(V) + 1 do
912+ # calculate neighbours of x, predecessor and successor
913+ prec := sigma[ posx - 1 ] ;
914+ succ := sigma[ posx + 1 ] ;
915+ N := Filtered(sigma, n -> n in OutNeighboursOfVertex(D, x));
916+ # deal with cases where predecessor or successor is a marker
917+ if prec <> 0 then
918+ N_prec := Filtered(sigma, n -> n in OutNeighboursOfVertex(D, prec));
919+ else
920+ N_prec := [ 0 ] ;
921+ fi ;
922+ if succ <> Length(V) + 1 then
923+ N_succ := Filtered(sigma, n -> n in OutNeighboursOfVertex(D, succ));
924+ else
925+ N_succ := [ 0 ] ;
926+ fi ;
927+ # if x shares a neighbourhood with predecessor or successor,
928+ # remove the predecessor and move right
929+ if N = N_prec or Union(N, [ x] ) = Union(N_prec, [ prec] ) then
930+ Remove(sigma, posx - 1 );
931+ posx := posx - 1 ;
932+ elif N = N_succ or Union(N, [ x] ) = Union(N_succ, [ succ] ) then
933+ Remove(sigma, posx);
934+ x := succ;
935+ else
936+ posx := posx + 1 ;
937+ x := succ;
938+ fi ;
939+ od ;
940+ # continue until we hit end marker
941+ # if only markers remain, G is a cograph
942+ return Length(Difference(sigma, [ 0 , Length(V) + 1 ] )) = 1 ;
943+ end );
944+
945+ InstallMethod(IsCograph,
946+ " for a mutable digraph" ,
947+ [ IsMutableDigraph] ,
948+ D -> IsCograph(DigraphImmutableCopy(D)));
0 commit comments