#############################################################################
##
#W  basics2.gi              Manuel Delgado <mdelgado@fc.up.pt>
#W                          Pedro Garcia-Sanchez <pedro@ugr.es>
#W                          Jose Morais <jjoao@netcabo.pt>
##
##
#H  @(#)$Id: basics2.gi,v 0.92 $
##
#Y  Copyright 2005 by Manuel Delgado, 
#Y  Pedro Garcia-Sanchez and Jose Joao Morais
#Y  We adopt the copyright regulations of GAP as detailed in the 
#Y  copyright notice in the GAP manual.
##
#############################################################################

#############################################################################
##
#O  IsSubsemigroupOfNumericalSemigroup(S,T)
## 
##  Test whether the numerical semigroup T is contained in the 
##  numerical semigroup S
##
#############################################################################
InstallMethod( IsSubsemigroupOfNumericalSemigroup,
        "method for numerical semigroups",
        true,
        [IsNumericalSemigroup and IsNumericalSemigroupByGenerators,
         IsNumericalSemigroup and IsNumericalSemigroupByGenerators],0,
        function(S,T)
    return
IsSubset(GeneratorsOfNumericalSemigroup(S),GeneratorsOfNumericalSemigroup(T));
end);


InstallMethod( IsSubsemigroupOfNumericalSemigroup,
        "method for numerical semigroups",
        true,
        [IsNumericalSemigroup,IsNumericalSemigroup],0,
        function(S,T)
    return IsSubset(GapsOfNumericalSemigroup(T),GapsOfNumericalSemigroup(S));
end);


#############################################################################
##
#F  IntersectionOfNumericalSemigroups(S,T)
## 
##  Returns the intersection of the numerical
##  semigroups S and T.
##
#############################################################################
InstallGlobalFunction(IntersectionOfNumericalSemigroups, function(S,T)
    local D, g, gs,gt, R;
    if not (IsNumericalSemigroup(S) and IsNumericalSemigroup(T)) then
        Error("The arguments of IntersectionOfNumericalSemigroups must be numerical semigroups");
    fi;
    gs := FrobeniusNumberOfNumericalSemigroup(S);
    gt := FrobeniusNumberOfNumericalSemigroup(T);
    S := Union(SmallElementsOfNumericalSemigroup(S),[gs+1..gt+1]);
    T := Union(SmallElementsOfNumericalSemigroup(T),[gt+1..gs+1]);
    R := Intersection(S,T);
    while Gcd(R) <> 1 do
        Add(R,R[Length(R)]+1);
    od;
    D := Difference([0..R[Length(R)]], R);
    g := D[Length(D)];
    return NumericalSemigroupBySmallElements(Intersection(R,[0..g+1]));
end);


#############################################################################
##
#F  RepresentsGapsOfNumericalSemigroup(L)
##
##  Tests if the given list L represents the gaps of
##  some numerical semigroup.
##
#############################################################################
InstallGlobalFunction(RepresentsGapsOfNumericalSemigroup, function(L)
    local ld, ns;
    
    if not (IsList(L) and ForAll(L, i -> IsPosInt(i))) then
        Error("The argument must be a list of positive integers");
    fi;
    ld := Union(List(L,DivisorsInt));
    ns := Difference([0..ld[Length(ld)]+1],ld);
    return RepresentsSmallElementsOfNumericalSemigroup(ns);
end);
    
    
#############################################################################
##
#F  NumericalSemigroupsWithFrobeniusNumber(g)
##
##  Computes the set of numerical semigroups with Frobenius number g.
##  The algorithm is based on 
##  "Fundamental gaps in numerical semigroup".
##
#############################################################################
InstallGlobalFunction(NumericalSemigroupsWithFrobeniusNumber, function(g)
    local fg, fundamentalGapsRepresentingNSGenerator;
    
    if(not(IsInt(g)) or g<-1) then
        Error("the argument must be an integer.\n");
    fi;
    if(g=0) then
        return [];
    fi;
    if(g=-1) then
        return [NumericalSemigroup("generators",[1])];
    fi;
    
    
  
    fundamentalGapsRepresentingNSGenerator := function(g)
        local initial,final,i,la, ll,list,listNodivs, x, ld;
        
        ll:=[[g]];
        initial:=1;
        final:=Length(ll);
    
        repeat
            for i in [initial..final] do
                list:=ll[i];
                
                
                ld := Union(List(ll[i],DivisorsInt));
                if not RepresentsSmallElementsOfNumericalSemigroup(
                           Difference([0..ld[Length(ld)]+1],ld)) then
                    Unbind(ll[i]);
                fi;
               listNodivs:=Filtered([1..(list[1]-1)],x-> not ForAny(list,i -> i mod x = 0) );
                for x in listNodivs do
                    Append(ll,[Union([x],list)]);
                od;
            od;

            initial:=final+1;
            final:=Length(ll);
        until initial >= final;
    
        return Compacted(ll);
    end;
    
    fg := fundamentalGapsRepresentingNSGenerator(g);

    if not RepresentsGapsOfNumericalSemigroup(fg[1]) then
        fg := fg{[2..Length(fg)]};
    fi;
    return List(fg,x->NumericalSemigroupByFundamentalGaps(x));
end);

