############################################################################
##
#W  basics.gi                       Manuel Delgado <mdelgado@fc.up.pt>
#W                                    Jose Morais    <jjoao@netcabo.pt>
##
#H  @(#)$Id: basics.gi,v 0.992 $
##
#Y  Copyright (C)  2005,  CMUP, Universidade do Porto, Portugal
##
##
###########################################################################
##
##
###########################################################################
##
#M HasCommutingIdempotents(M)
##
## Tests whether the idempotents of a semigroup <M> commute
##
InstallMethod(HasCommutingIdempotents, "for finite semigroups", true,
                 [IsSemigroup], 0, 
    function(M)
    local e1, e2, E;
    E := Idempotents(M);
    for e1 in E do
        for e2 in E do
            if e1*e2 <> e2*e1 then
                Info(InfoSgpViz,2, e1, " and ", e2, " don't commute");
                return false;
            fi;
        od;
    od;
    return true;
end);


#####################################33###################################
##
#M IsInverseSemigroup(S)
##
## Tests whether a finite semigroup is inverse
##
InstallMethod(IsInverseSemigroup, "for finite semigroups", true,
              [IsSemigroup], 0,
function(S)
    return HasCommutingIdempotents(S) and IsRegularSemigroup(S);
end);

#############################################################################
##
#F PartialTransformation(L)
##
## A partial transformation is a partial function of a set of integers of 
## the form  {1,..., n}. It is given by means of the list of images. When 
## an element has no image, we write 0. 
##
## Returns a transformation on a set with one more element that acts like 
## a zero
##
InstallGlobalFunction(PartialTransformation, function(L)    
    local i, n, K;
    n := Length(L);
    #check that it represents a partial transformation.
       
    if ForAny([1..n], i-> (IsBound(L[i]) and not L[i] in [0..n])) then
        Error ("<L> does not describe a partial transformation");
    fi;
    
    K := ShallowCopy(L);
    for i in [1..n] do
        if K[i] = 0 then
            K[i] := n+1;
        fi;
    od;
    K[n+1] := n+1;
    return TransformationNC(K);
end);

############################################################################
##
#F RightCayleyGraph  
##
## Computes the right Cayley graph of a finite monoid or semigroup. It uses the GAP 
## buit-in function CayleyGraphSemigroup to compute the Cayley Graph 
## and returns it as an automaton without initial and final states.
##
##
InstallGlobalFunction(RightCayleyGraph, function(M)
    local i, n, cg, one, table, tr, p;
    
    if not IsSemigroup(M) then
        Error("<M> must be a semigroup");
    fi;
    if IsFpSemigroup(M) or IsFpMonoid(M) then
        cg := CayleyGraphSemigroup(Range(IsomorphismTransformationSemigroup(M)));
    else
        cg := CayleyGraphSemigroup(M);
    fi;
    
    tr := ShallowCopy(TransposedMat(cg));
    
    if MultiplicativeNeutralElement(M) in GeneratorsOfSemigroup(M) then
        n := Length(GeneratorsOfSemigroup(M))-1;
        if n = 0 then
            return Automaton("det", 1, 1, [[1]], [], []);
        fi;
        
        p := Position(GeneratorsOfSemigroup(M),MultiplicativeNeutralElement(M));
        Unbind(tr[p]);
        table := Compacted(tr);
        if n <> Length(table) then
            Error("error in RightCayleyGraph");
        fi;
    else
        table := tr;
        n := Length(GeneratorsOfSemigroup(M));
    fi;
    return Automaton("det", Size(M), n, table, [], []);
end);

###########################################################################
##
#F DrawRightCayleyGraph
##
## Drawss the right Cayley graph of a finite monoid or semigroup.
##
InstallGlobalFunction(DrawRightCayleyGraph, function(M)
    DrawAutomaton(RightCayleyGraph(M));
end);

