1#############################################################################
2##
3#W  affine.gi           Manuel Delgado <mdelgado@fc.up.pt>
4#W                      Pedro Garcia-Sanchez <pedro@ugr.es>
5##
6#Y  Copyright 2015-- Centro de Matemática da Universidade do Porto, Portugal and Universidad de Granada, Spain
7#############################################################################
8##
9#if not TestPackageAvailability("4ti2Interface") = fail then
10#    LoadPackage("4ti2");
11#fi;
12##
13
14
15# using the parent InfoNumSgps
16#InfoAffSgps:=NewInfoClass("InfoAffSgps");;
17#SetInfoLevel(InfoAffSgps,1);;
18
19
20######################################################################
21# Computes the set of primitive elements of an affine semigroup, that
22# is, the set of elements whose factorizations are involved in the
23# minimal generators of the congruence associated to the monod
24# (generators as a monoid; not to be confused with minimal presentations
25# to this end, use BettiElementsOfAffineSemigroup)
26# # REQUERIMENTS: 4ti2Interface
27######################################################################
28
29#InstallGlobalFunction(PrimitiveElementsOfAffineSemigroup,function(ls)
30#    local dir, filename, exec, filestream, matrix,
31#				 facs, mat, trunc;# ls;
32
33
34	#if not(IsAffineSemigroup(a)) then
35	#	Error("The argument must be an affine semigroup");
36	#fi;
37
38	#ls:=GeneratorsAS(a);
39
40#    dir := DirectoryTemporary();
41#    filename := Filename( dir, "gap_4ti2_temp_matrix" );
42#
43#	mat:=TransposedMat(ls);
44#    4ti2Interface_Write_Matrix_To_File( mat, Concatenation( filename, ".mat" ) );
45#    exec := IO_FindExecutable( "graver" );
46#    filestream := IO_Popen2( exec, [ filename ]);
47#    while IO_ReadLine( filestream.stdout ) <> "" do od;
48#    matrix := 4ti2Interface_Read_Matrix_From_File( Concatenation( filename, ".gra" ) );
49#
50#    trunc:=function(ls)
51#		return List(ls, y->Maximum(y,0));
52#	end;
53
54#	matrix:=Set(matrix,trunc);
55#    return Set(matrix, x->x*ls);
56#end);
57
58
59#########
60#InstallGlobalFunction(ElasticityOfAffineSemigroup,
61#        function(ls)
62#     local dir, filename, exec, filestream, matrix,
63# 				  mat, truncplus, truncminus;
64
65# 	if not(IsHomogeneousList(ls)) then
66# 		Error("The argument must be a homogeneous list.");
67# 	fi;
68
69# 	if not(ForAll(ls,IsListOfIntegersNS)) then
70# 		Error("The argument must be a list of lists of integers.");
71# 	fi;
72
73# 	if not(Length(Set(ls, Length))=1) then
74# 		Error("All lists in the first argument must have the same length.");
75# 	fi;
76
77#     dir := DirectoryTemporary();
78#     filename := Filename( dir, "gap_4ti2_temp_matrix" );
79
80# 	mat:=TransposedMat(ls);
81#     4ti2Interface_Write_Matrix_To_File( mat, Concatenation( filename, ".mat" ) );
82#     exec := IO_FindExecutable( "graver" );
83#     filestream := IO_Popen2( exec, [ filename ]);
84#     while IO_ReadLine( filestream.stdout ) <> "" do od;
85#     matrix := 4ti2Interface_Read_Matrix_From_File( Concatenation( filename, ".gra" ) );
86
87#     truncplus:=function(ls)
88# 		return Sum(List(ls, y->Maximum(y,0)));
89# 	end;
90
91#     truncminus:=function(ls)
92# 		return Sum(List(ls, y->-Minimum(y,0)));
93# 	end;
94
95# 	return Maximum(Set(matrix, y->truncplus(y)/truncminus(y)));
96# end);
97#####
98
99
100
101
102
103####################################################################
104# Decides if the vector v belongs to the affine semigroup a
105#
106####################################################################
107InstallMethod( \in,
108        "for affine semigroups",
109        [ IsHomogeneousList, IsAffineSemigroup],
110        function( v, a )
111    return BelongsToAffineSemigroup(v,a);
112end);
113
114InstallMethod(BelongsToAffineSemigroup,
115        "To test whether an element of N^n belongs to an affine semigroup",
116        true,
117        [ IsHomogeneousList, IsAffineSemigroup and HasGenerators],50,
118
119        function(v,a)
120    local belongs, gen;
121
122      #determines if an element x is in the affine semigroup
123      # spanned by gen
124    belongs:=function(x,gen)
125	if gen=[] then
126            return false;
127	fi;
128
129	if ForAll(x,i->i=0) then
130            return true;
131	fi;
132
133	if ForAny(x,i->i<0) then
134            return false;
135	fi;
136
137	return belongs(x-gen[1],gen) or belongs(x,gen{[2..Length(gen)]});
138    end;
139
140    if not(IsListOfIntegersNS(v)) then
141        Error("The first argument must be a list of integers.");
142    fi;
143
144    gen:=Generators(a);
145    if not(IsRectangularTable(Concatenation(gen,[v]))) then
146        Error("The dimension of the vector and the affine semigroup do not coincide.");
147    fi;
148
149    return belongs(v,gen);
150
151end);
152
153InstallMethod(BelongsToAffineSemigroup,
154        "To test whether a list of elements of N^n belongs to an affine semigroup",
155        true,
156        [ IsHomogeneousList, IsAffineSemigroup and HasEquations],100,
157
158        function(v,a)
159    local equ,eq,md,ev,i;
160
161    equ:=Equations(a);
162    if not(IsListOfIntegersNS(v)) then
163        Error("The first argument must be a list of integers.");
164    fi;
165    if ForAny(v,x->x<0) then
166        return false;
167    fi;
168
169    eq:=equ[1];
170    md:=equ[2];
171    if Length(eq[1])<>Length(v) then
172        Error("The dimension of the vector and the affine semigroup do not coincide.");
173    fi;
174    ev:=ShallowCopy(eq*v);
175
176    Info(InfoNumSgps,2,"Testing membership with equations.");
177
178    for i in [1..Length(md)] do
179        ev[i]:=ev[i] mod md[i];
180    od;
181
182    return ForAll(ev,x->x=0);
183
184end);
185
186InstallMethod(BelongsToAffineSemigroup,
187        "To test whether a list of elements of N^n belongs to an affine semigroup",
188        true,
189        [ IsHomogeneousList, IsAffineSemigroup and HasPMInequality],100,
190
191        function(v,a)
192    local f, b, g, ineq;
193
194    ineq:=PMInequality(a);
195    if not(IsListOfIntegersNS(v)) then
196        Error("The first argument must be a list of integers.");
197    fi;
198    if ForAny(v,x->x<0) then
199        return false;
200    fi;
201
202    f:=ineq[1];
203    b:=ineq[2];
204    g:=ineq[3];
205    if Length(ineq[1])<>Length(v) then
206        Error("The dimension of the vector and the affine semigroup do not coincide.");
207    fi;
208
209    return ((f*v) mod b) <= g*v;
210
211end);
212
213InstallMethod(BelongsToAffineSemigroup,
214        "To test whether an element of N^n belongs to an affine semigroup",
215        true,
216        [ IsHomogeneousList, IsAffineSemigroup and HasInequalities],70,
217
218        function(v,a)
219    local equ,ev;
220
221    equ:=AffineSemigroupInequalities(a);
222    if not(IsListOfIntegersNS(v)) then
223        Error("The first argument must be a list of integers.");
224    fi;
225    if ForAny(v,x->x<0) then
226        return false;
227    fi;
228
229    if Length(equ[1])<>Length(v) then
230        Error("The dimension of the vector and the affine semigroup do not coincide.");
231    fi;
232    ev:=equ*v;
233
234    Info(InfoNumSgps,2,"Testing membership with inequalities.");
235
236    return ForAll(ev,x->x>=0);
237
238end);
239
240InstallMethod(BelongsToAffineSemigroup,
241        "To test whether an element of N^n belongs to an affine semigroup",
242        true,
243        [ IsHomogeneousList, IsAffineSemigroup and HasGaps],70,
244        function(v,a)
245            local gaps;
246
247            if not(IsListOfIntegersNS(v)) then
248                Error("The first argument must be a list of integers.");
249            fi;
250            if ForAny(v,x->x<0) then
251                return false;
252            fi;
253            gaps:=Gaps(a);
254            if Length(gaps[1])<>Length(v) then
255                Error("The dimension of the vector and the affine semigroup do not coincide.");
256            fi;
257
258            Info(InfoNumSgps,2,"Testing membership with gaps.");
259            return not(v in gaps);
260end);
261
262#############################################################
263# Computes a basis of a subgroup of Z^n with defining equations
264# Ax =0 \in Z_m1\times\Z_mt \times Z^k, k is n-length(m),
265# m=[m1,...,mt]
266#############################################################
267InstallGlobalFunction(BasisOfGroupGivenByEquations,function(A,m)
268    local n,r, AA, i, er, b, homEqToBasis;
269
270    # Compute a basis of a subgroup of Z^n with defining equations Ax=0
271    homEqToBasis:=function(A)
272	local snf, b, r, n;
273	snf:= SmithNormalFormIntegerMatTransforms(A);
274	r:=snf.rank;
275	n:=Length(A[1]);
276	b:=TransposedMat(snf.coltrans);
277	return b{[r+1..n]};
278    end;
279
280
281    if not(IsRectangularTable(A)) then
282        Error("The first argument must be a matrix.");
283    fi;
284    if not(IsInt(A[1][1])) then
285        Error("The first argument must be a matrix of integers.");
286    fi;
287
288    n:=Length(A[1]);
289    r:=Length(A);
290
291    if m=[] then
292        AA:=ShallowCopy(TransposedMat(A));
293    else
294        if not(IsListOfIntegersNS(m)) then
295            Error("The second argument must be a lists of integers.");
296        fi;
297
298        if not(ForAll(m,x->x>0)) then
299            Error("The second argument must be a list of positive integers");
300        fi;
301
302        AA:=ShallowCopy(TransposedMat(A));
303        er:=List([1..r],_->0);
304        for i in [1..Length(m)] do
305            if m[i]<>0 then
306                er[i]:=m[i];
307                Add(AA,ShallowCopy(er));
308                er[i]:=0;
309            fi;
310        od;
311    fi;
312    AA:=TransposedMat(AA);
313
314    b:=TransposedMat(homEqToBasis(AA));
315
316    b:=b{[1..n]};
317    return LLLReducedBasis(TransposedMat(b)).basis;
318end);
319
320#############################################################
321#  Computes the defining equations of the group of Z^n
322#  generated by M
323#  the output is [A,m] such that Ax=0 mod m are the equations
324############################################################
325InstallGlobalFunction(EquationsOfGroupGeneratedBy,function(M)
326    local A, m, snf, nones;
327
328    if not(IsRectangularTable(M)) then
329        Error("The first argument must be a matrix.");
330    fi;
331    if not(IsInt(M[1][1])) then
332        Error("The first argument must be a matrix of integers.");
333    fi;
334
335    snf:=SmithNormalFormIntegerMatTransforms(M);
336    A:=TransposedMat(snf.coltrans);
337    m:=DiagonalOfMat(snf.normal);
338    nones:=Length(Filtered(m,x->x=1));
339
340    m:=Filtered(DiagonalOfMat(snf.normal),x->x<>0);
341    A:=A{[nones+1..Length(A)]};
342    m:=m{[nones+1..Length(m)]};
343
344    return [A,m];
345end);
346
347
348##############################################################
349# Determines if there is a gluing of the two affine semigroups,
350# and if so, returns the gluing of them; fail otherwise
351##############################################################
352InstallGlobalFunction(GluingOfAffineSemigroups,function(a1,a2)
353    local int, d, intersectionOfSubgroups, g1, g2;
354
355
356    #computes the intersection of two groups of Z^n
357    # given by generators
358    intersectionOfSubgroups:=function(g1,g2)
359        local eq1, eq2, A, m;
360
361        eq1:=EquationsOfGroupGeneratedBy(g1);
362        eq2:=EquationsOfGroupGeneratedBy(g2);
363        A:=Concatenation(eq1[1],eq2[1]);
364        m:=Concatenation(eq1[2],eq2[2]);
365
366        return BasisOfGroupGivenByEquations(A,m);
367    end;
368
369    if not(IsAffineSemigroup(a1)) or not(IsAffineSemigroup(a2)) then
370        Error("The arguments must be affine semigroups.");
371    fi;
372
373    g1:=GeneratorsOfAffineSemigroup(a1);
374    g2:=GeneratorsOfAffineSemigroup(a2);
375    if not(IsRectangularTable(Concatenation(g1,g2)))then
376        Error("The semigroups must have the same dimension.");
377    fi;
378
379    int:=intersectionOfSubgroups(g1,g2);
380    if Length(int)<> 1 then
381        return false;
382    fi;
383
384    d:=int[1];
385    if ForAny(d, i->i<0) then
386        d:=-d;
387    fi;
388    if BelongsToAffineSemigroup(d,a1) and
389       BelongsToAffineSemigroup(d,a2) then
390        return AffineSemigroup(Concatenation(g1,g2));
391    fi;
392    return fail;
393
394end);
395
396###################### ContejeanDevieAlgorithm
397
398#############################################################################################
399# l contains the list of coefficients of a system of linear equations. forten gives the
400#  set of minimal generators of the affine semigroup of nonnegative soultions of this equation
401##############################################################################################
402InstallMethod(HilbertBasisOfSystemOfHomogeneousEquations,
403        "Computes the Hilbert basis of a system of linear Diophantine equations, some evetually in congruences.",[IsRectangularTable,IsHomogeneousList],1,
404  function(ls,md)
405  local  contejeanDevieAlgorithm, contejeanDevieAlgorithmWithCongruences, leq;
406
407  ## local functions ...
408    #less than or equal to with the usual partial order
409  leq:= function(v1,v2)
410      local v;
411      v:=v2-v1;
412      return (First(v,n->n<0)=fail);
413  end;
414
415  contejeanDevieAlgorithm:= function(l)
416    local solutions, m, x, explored, candidates, tmp, k,zero, lx;
417
418
419    Info(InfoNumSgps,2,"Using Contejean and Devie algorithm.");
420
421
422    solutions:=[];
423    explored:=[];
424
425    #if not(IsRectangularTable(l)) then
426    #  Error("The argument must be a matrix.");
427    #fi;
428    if not(IsInt(l[1][1])) then
429      Error("The matrix must be of integers.");
430    fi;
431
432
433    m:=IdentityMat(Length(l[1]));
434    zero:=List([1..Length(l)],_->0);
435    candidates:=m;
436    while (not(candidates=[])) do
437      x:=candidates[1];
438      explored:=Union([x],explored);
439      candidates:=candidates{[2..Length(candidates)]};
440      lx:=l*x;
441      if(lx=zero) then
442        solutions:=Union([x],solutions);
443        #    Print(x);
444      else
445        tmp:=Set(Filtered(m,n->(lx*(l*n)<0)),y->y+x);
446        tmp:=Difference(tmp,explored);
447        tmp:=Filtered(tmp,n->(First(solutions,y->leq(y,n))=fail));
448        candidates:=Union(candidates,tmp);
449      fi;
450    od;
451    return solutions;
452  end;
453
454  contejeanDevieAlgorithmWithCongruences:=function(ls,md)
455    local l,n,m,diag,dim,d, hil, zero;
456
457    #if not(IsRectangularTable(ls)) then
458    #  Error("The first argument must be a matrix.");
459    #fi;
460
461    if not(IsListOfIntegersNS(md)) or ForAny(md, x->not(IsPosInt(x))) then
462      Error("The second argument must be a list of positive integers.");
463    fi;
464
465    n:=Length(ls);
466    dim:=Length(ls[1]);
467    m:=Length(md);
468    if m>n then
469      Error("There are more modulus than equations.");
470    fi;
471
472    diag:=Concatenation(md,List([1..n-m],_->0));
473    d:=DiagonalMat(diag);
474    l:=TransposedMat(Concatenation(TransposedMat(ls),d,-d));
475    zero:=List([1..dim],_->0);
476
477    hil:=Difference(List(contejeanDevieAlgorithm(l), x->x{[1..dim]}),[zero]);
478    return hil;
479
480    #return Filtered(hil, y->Filtered(hil,x->leq(x,y))=[y]);
481  end;
482  ## end of local functions ...
483  Info(InfoNumSgps,1,"Using contejeanDevieAlgorithm for Hilbert Basis. Please, consider using NormalizInterface, 4ti2Interface or 4ti2gap.");
484  #ls := arg[1][1];
485  #md := arg[1][2];
486  if md = [] then
487    return contejeanDevieAlgorithm(ls);
488  else
489    return contejeanDevieAlgorithmWithCongruences(ls,md);
490
491  fi;
492end);
493
494##############################################################################################
495#
496# ls is a matrix of integers. It computes the set minimal nonzero nonnegative integer solutions
497# of ls*x>=0
498#
499InstallMethod(HilbertBasisOfSystemOfHomogeneousInequalities,
500        "Computes the Hilbert basis of a set of inequalities",
501        [IsRectangularTable],1,
502        function(ls)
503    local mat, neq, dim, id, hil,zero ;
504    #if not(IsRectangularTable(ls)) then
505    #  Error("The argument must be a matrix.");
506    #fi;
507    if not(IsInt(ls[1][1])) then
508      Error("The matrix must be of integers.");
509    fi;
510
511    neq:=Length(ls);
512    dim:=Length(ls[1]);
513    zero:=List([1..dim],_->0);
514
515    id:=IdentityMat(neq);
516    mat:=TransposedMat(Concatenation(TransposedMat(ls),-id));
517    hil:=HilbertBasisOfSystemOfHomogeneousEquations(mat,[]);
518    return List(hil,x->x{[1..dim]});
519
520
521end);
522
523########################################################################
524# Computes the set of factorizations of v in terms of the elements of ls
525# That is, a Hilbert basis for ls*X=v
526# If ls contains vectors that generate a nonreduced monoid, then it
527# may enter in an infinite loop
528########################################################################
529InstallMethod(FactorizationsVectorWRTList,
530        "Computes the set of factorizations of the first argument in terms of the elements of the second",
531        [IsHomogeneousList, IsMatrix],1,
532        function(v,ls)
533    local len, e1, opt1, opt2, i, mat, dim;
534    # REQUERIMENTS: NormalizInterface
535    #if NumSgpsCanUseNI then
536    #    TryNextMethod();
537    #fi;
538
539    mat:=TransposedMat(Concatenation(ls,[-v]));
540
541    if not(IsListOfIntegersNS(v)) then
542        Error("The first argument must be a list of integers.");
543    fi;
544
545    if not(ForAll(ls,IsListOfIntegersNS)) then
546        Error("The second argument must be a list of lists of integers.");
547    fi;
548
549    if not(IsRectangularTable(mat)) then
550        Error("The list in the second argument must have the same length as the lists in the first argument.");
551    fi;
552
553    len:=Length(ls);
554    if ls=[] then
555        return [];
556    fi;
557    if ForAll(v,x->x=0) then
558        return [List([1..len],_->0)];
559    fi;
560    if ForAny(v,x->x<0) then
561        return [];
562    fi;
563
564    if Length(ls)=1 then
565        dim:=Length(ls[1]);
566
567        i:=First([1..dim],x->ls[1][x]<>0);
568
569        if i=fail then
570            Error("The second argument cannot contain the zero vector.");
571        fi;
572        if (v[i] mod ls[1][i]=0) and v=v[i]/ls[1][i]*ls[1] then
573            return [ [v[i]/ls[1][i]] ];
574        fi;
575        return [];
576    fi;
577    e1:=List([1..len-1],_->0);
578    e1:=Concatenation([1],e1);
579    opt1:=[];
580    if ForAll(v-ls[1],x->x>=0) then
581        opt1:=List(FactorizationsVectorWRTList(v-ls[1],ls), x->x+e1);
582    fi;
583    opt2:=List(FactorizationsVectorWRTList(v,ls{[2..len]}),
584               x->Concatenation([0],x));
585#    return Concatenation(opt1,opt2);
586    return Union(opt1,opt2);
587end);
588
589###############################################################################
590#O Factorizations
591# Vactorizations of a vector in terms of the minimal generating set of the
592# affine semigroup
593########################################################################
594InstallMethod(Factorizations,
595    "factorizations of an element in terms of the generators of the affine semigroup",
596    [IsHomogeneousList,IsAffineSemigroup],
597    function(n,a)
598        local fac,gen;
599        if not(n in a) then
600            Error("The first argument is not an element of the second");
601        fi;
602        gen:=MinimalGeneratingSystem(a);
603        fac:=FactorizationsVectorWRTList(n,gen);
604        return fac;
605    end);
606
607InstallMethod(Factorizations,
608    "factorizations of an element in terms of the generators of the affine semigroup",
609    [IsAffineSemigroup,IsHomogeneousList],
610    function(a,n)
611        local fac,gen;
612        if not(n in a) then
613            Error("The second argument is not an element of the first");
614        fi;
615        gen:=MinimalGeneratingSystem(a);
616        fac:=FactorizationsVectorWRTList(n,gen);
617        return fac;
618    end);
619
620
621############################################################
622# computes a set of generators of the kernel congruence
623# of the monoid morphism associated to the matrix m with
624# nonnegative integer coefficients
625############################################################
626InstallMethod(GeneratorsOfKernelCongruence,
627  "Computes a set of generators of the kernel congruence of the monoid morphism associated to a matrix",
628	[IsRectangularTable],1,
629	function( m )
630
631    local i, p, rel, rgb, msg, pol, ed, monomial, candidates, mp,
632          R,id, ie, vars, mingen, exps, bintopair, dim, zero, gen,
633          pres,c, rclass;
634
635    # REQUERIMENTS: SingularInterface or Singular
636    #if NumSgpsCanUseSI or NumSgpsCanUseSingular then
637    #    TryNextMethod();
638    #fi;
639
640    bintopair:=function(p)
641        local m1,m2, d1, d2;
642        m1:=LeadingMonomialOfPolynomial(p, MonomialLexOrdering());
643        m2:=m1-p;
644        d1:=List([1..ed], i->DegreeIndeterminate(m1,i));;
645        d2:=List([1..ed], i->DegreeIndeterminate(m2,i));;
646        return Set([d1,d2]);
647    end;
648
649    if not(ForAll(m, l->ForAll(l, x->(x=0) or IsPosInt(x)))) then
650        Error("The argument must be a matrix of nonnegative integer.");
651    fi;
652
653    msg:=ShallowCopy(m);
654    ed:=Length(msg);
655    if ed=0 then
656        return [];
657    fi;
658    zero:=List([1..ed],_->0);
659    dim:=Length(msg[1]);
660    vars:=List([1..ed+dim],i->X(Rationals,i));
661    R:=PolynomialRing(Rationals,vars);
662    p:=List([1..ed], i->X(Rationals,i)-
663            Product(List([1..dim], j->X(Rationals,j+ed)^msg[i][j])));
664    rgb:=ReducedGroebnerBasis( p,
665                 EliminationOrdering(List([1..dim],i->X(Rationals,i+ed))));
666    rgb:=Filtered(rgb,
667                 q->ForAll([1..dim], i->DegreeIndeterminate(q,i+ed)=0));
668    candidates:=Set(rgb,q->bintopair(q));
669    return candidates;
670end);
671
672############################################################
673# computes a canonical basis of the kernel congruence
674# of the monoid morphism associated to the matrix m with
675# nonnegative integer coefficients wrt the term ordering
676# the kernel is the pairs (x,y) such that xm=ym
677############################################################
678InstallMethod(CanonicalBasisOfKernelCongruence,
679	"Computes a canonical basis for the congruence of of the monoid morphism associated to the matrix",
680	[IsRectangularTable, IsMonomialOrdering],1,
681  function( m, ord )
682
683    local i, p, rel, rgb, msg, pol, ed, monomial, candidates, mp,
684          R,id, ie, vars, mingen, exps, bintopair, dim, zero, gen,
685          pres,c, rclass;
686
687
688    bintopair:=function(p)
689        local m1,m2, d1, d2;
690        m1:=LeadingMonomialOfPolynomial(p, ord);
691        m2:=m1-p;
692        d1:=List([1..ed], i->DegreeIndeterminate(m1,i));;
693        d2:=List([1..ed], i->DegreeIndeterminate(m2,i));;
694        return [d1,d2];
695    end;
696
697    if not(ForAll(m, l->ForAll(l, x->(x=0) or IsPosInt(x)))) then
698        Error("The argument must be a matrix of nonnegative integers.");
699    fi;
700
701    msg:=ShallowCopy(m);
702    ed:=Length(msg);
703    if ed=0 then
704        return [];
705    fi;
706    zero:=List([1..ed],_->0);
707    dim:=Length(msg[1]);
708    vars:=List([1..ed+dim],i->X(Rationals,i));
709    R:=PolynomialRing(Rationals,vars);
710    p:=List([1..ed], i->X(Rationals,i)-
711            Product(List([1..dim], j->X(Rationals,j+ed)^msg[i][j])));
712    rgb:=ReducedGroebnerBasis( p,
713                 EliminationOrdering(List([1..dim],i->X(Rationals,i+ed))));
714    rgb:=Filtered(rgb,
715                 q->ForAll([1..dim], i->DegreeIndeterminate(q,i+ed)=0));
716		if rgb = [] then
717			return [];
718		fi;
719		rgb:=ReducedGroebnerBasis(rgb,ord);
720    candidates:=Set(rgb,q->bintopair(q));
721    return candidates;
722end);
723
724############################################################
725# computes the Graver basis of matrix with integer entries
726############################################################
727InstallMethod(GraverBasis,
728        "Computes the Graver basis of the matrix",
729        [IsRectangularTable],1,
730function(a)
731  #PLAIN implementation
732	local msg, mgs, ed, dim, prlft, lft,zero, zeroes, id, aid, zeroid;
733
734    if not(IsInt(a[1][1])) then
735      Error("The entries of the matrix must be integers.");
736    fi;
737    Info(InfoNumSgps,1,"Using Lawrence lifting for computing Graver Basis. Please, consider using NormalizInterface, 4ti2Interface or 4ti2gap.");
738    mgs:=TransposedMat(a);
739    ed:=Length(mgs);
740    dim:=Length(mgs[1]);
741    #lft:=LawrenceLiftingOfAffineSemigroup(a);
742    #prlft:=MinimalPresentationOfAffineSemigroup(lft);
743    id:=IdentityMat(ed);
744    zero:=List([1..ed],_->0);
745    zeroes:=List([1..dim],_->zero);
746
747    msg:=TransposedMat(mgs);
748    aid:=TransposedMat(Concatenation(msg,id));
749    zeroid:=TransposedMat(Concatenation(zeroes,id));
750
751    lft:=(Concatenation(aid,zeroid));
752    prlft:=GeneratorsOfKernelCongruence(lft);
753    Info(InfoNumSgps,2,"The kernel congruence is ", prlft);
754    prlft:=Filtered(prlft, p->p[1]<>p[2]);
755    return Set(Union(prlft), p->p{[1..ed]}-p{[ed+1..ed+ed]});
756end);
757
758############################################################
759# computes a minimal presentation of a
760############################################################
761InstallMethod(MinimalPresentationOfAffineSemigroup,
762	"Computes the minimal presentation of an affine semigroup",
763	[IsAffineSemigroup],1,
764	function( a )
765
766    local i, p, rel, rgb, msg, pol, ed, monomial, candidates, mp,
767          R,id, ie, vars, mingen, exps, bintopair, dim, zero, gen,
768          pres,c, rclass;
769
770    msg:=MinimalGenerators(a);
771    ed:=Length(msg);
772    if ed=0 then
773        return [];
774    fi;
775    dim:=Length(msg[1]);
776    candidates:=GeneratorsOfKernelCongruence(msg);
777    candidates:=Set(candidates,c->c[1]*msg);
778    Info(InfoNumSgps,2, "Candidates to Betti elements",candidates);
779    pres:=[];
780    for c in candidates do
781        exps:=FactorizationsVectorWRTList(c,msg);
782        rclass:=RClassesOfSetOfFactorizations(exps);
783        if Length(rclass)>1 then
784            pres:=Concatenation(pres,List([2..Length(rclass)],
785                          i->Set([rclass[1][1],rclass[i][1]])));
786        fi;
787    od;
788    return pres;
789end);
790
791InstallMethod(MinimalPresentation,
792"Computes the minimal presentation of an affine semigroup",
793[IsAffineSemigroup],
794MinimalPresentationOfAffineSemigroup
795);
796
797###################################################################
798# Betti elements of the affine semigroup a
799###################################################################
800InstallMethod(BettiElements,
801	"Computes the Betti elements of an affine semigroup",
802	[IsAffineSemigroup],1,
803	function(a)
804    local msg, pr;
805
806    msg:=MinimalGenerators(a);
807
808    pr:=MinimalPresentationOfAffineSemigroup(a);
809
810    return Set(pr, p->p[1]*msg);
811
812end);
813
814
815#############################################################################
816##
817#P  IsUniquelyPresentedAffineSemigroup(a)
818##
819##  For an affine semigroup a, checks it it has a unique minimal presentation
820##  Based in GS-O
821##
822#############################################################################
823InstallMethod(IsUniquelyPresented,
824         "Tests if the affine semigroup S has a unique minimal presentation",
825         [IsAffineSemigroup],1,
826        function(a)
827    local gs;
828    gs:=MinimalGenerators(a);
829    return ForAll(BettiElementsOfAffineSemigroup(a),
830                  b->Length(FactorizationsVectorWRTList(b,gs))=2);
831end);
832
833#############################################################################
834##
835#P  IsGenericAffineSemigroup(a)
836##
837##  For an affine semigroup a, checks it it has a generic presentation,
838##  that is, in every relation all generators appear.
839##  These semigroups are uniquely presented; see B-GS-G.
840##
841#############################################################################
842InstallMethod(IsGenericAffineSemigroup,
843         "Tests if the affine semigroup S has a generic presentation",
844         [IsAffineSemigroup],1,
845        function(a)
846	local mp;
847    mp:=MinimalPresentationOfAffineSemigroup(a);
848    return ForAll(mp,p->Product(p[1]+p[2])<>0);
849end);
850
851InstallTrueMethod(IsUniquelyPresentedAffineSemigroup, IsGenericAffineSemigroup);
852
853#############################################################################
854##
855#F ShadedSetOfElementInAffineSemigroup(x,a)
856## computes the shading set of x in a as defined in
857## -  Székely, L. A.; Wormald, N. C. Generating functions for the Frobenius problem
858##      with 2 and 3 generators. Math. Chronicle 15 (1986), 49–57.
859#############################################################################
860InstallGlobalFunction(ShadedSetOfElementInAffineSemigroup, function(x,a)
861
862    local msg;
863
864    if not IsAffineSemigroup(a) then
865        Error("The second argument must be an affine semigroup.\n");
866    fi;
867
868    if not ( x in a ) then
869        Error("The first argument must be an element of the second.\n");
870    fi;
871
872    msg:=MinimalGenerators(a);
873    return Filtered(Combinations(msg), c-> (x-Sum(c)) in a);
874end);
875
876###############################################################################
877#F DeltaSetOfAffineSemigroup
878# Computes the Delta set of the affine semigroup a
879# uses the algorithm presented in [GSONW]
880###########################################################################
881InstallGlobalFunction(DeltaSetOfAffineSemigroup,
882  function(a)
883
884    local p, msg, candidates, zero, hgens, m;
885
886    if not(IsAffineSemigroup(a)) then
887      Error("The argument must be an affine semigroup");
888    fi;
889
890    m:=MinimalGenerators(a);
891
892    if Length(m)=0 then
893      return [];
894    fi;
895    zero:=List([1..Length(m[1])],_->0);
896    msg:=List(Union(m,[zero]), x->Concatenation([1],x));
897    candidates:=Set(CanonicalBasisOfKernelCongruence(msg, MonomialLexOrdering()), l->l[1][1]);
898    RemoveSet(candidates,0);
899    return candidates;
900  end);
901
902InstallMethod(DeltaSet,
903    "for affine semigroups",
904    [IsAffineSemigroup],
905    DeltaSetOfAffineSemigroup);
906
907######################################################################
908# Computes the catenary degree of the affine semigroup a
909######################################################################
910InstallGlobalFunction(CatenaryDegreeOfAffineSemigroup,
911        function(a)
912    local betti, b, max, c, ls;
913    if not(IsAffineSemigroup(a)) then
914        Error("The argument must be an affine semigroup");
915    fi;
916
917    ls:=MinimalGenerators(a);
918
919    Info(InfoNumSgps,2,"Computing the Betti elements of the affine semigroup.");
920    betti:=BettiElementsOfAffineSemigroup(a);
921    Info(InfoNumSgps,2,"The Betti elements are ",betti);
922    max:=0;
923    for b in betti do
924        Info(InfoNumSgps,2,"Computing the catenary degree of ",b);
925        c:=CatenaryDegreeOfSetOfFactorizations(
926                   FactorizationsVectorWRTList(b,ls));
927        Info(InfoNumSgps,2,"which equals ",c);
928        if c>max then max:=c; fi;
929    od;
930    return max;
931end);
932
933InstallMethod(CatenaryDegree,
934    "Computes the catenary degree of an affine semigroup",
935    [IsAffineSemigroup],
936    CatenaryDegreeOfAffineSemigroup);
937
938######################################################################
939# Computes the equal catenary degree of the affine semigroup a
940# uses [GSOSN]
941######################################################################
942InstallGlobalFunction(EqualCatenaryDegreeOfAffineSemigroup,
943        function(a)
944    local ls, lsh, ah, primeq;
945
946    if not(IsAffineSemigroup(a)) then
947        Error("The argument must be an affine semigroup");
948    fi;
949
950    ls:=MinimalGenerators(a);
951    lsh:=List(ls, x-> Concatenation(x,[1]));
952    ah:=AffineSemigroup(lsh);
953    primeq:=BettiElementsOfAffineSemigroup(ah);
954
955    return Maximum(Set(primeq, x->CatenaryDegreeOfSetOfFactorizations(
956            FactorizationsVectorWRTList(x,lsh))));
957
958end);
959
960######################################################################
961# Computes the homogeneous catenary degree of the affine semigroup a
962# uses [GSOSN]
963######################################################################
964InstallGlobalFunction(HomogeneousCatenaryDegreeOfAffineSemigroup,
965        function(a)
966    local ls, lsh, ah, primeq, one;
967
968    if not(IsAffineSemigroup(a)) then
969        Error("The argument must be an affine semigroup");
970    fi;
971
972    ls:=MinimalGenerators(a);
973    if ls=[] then return 0;
974    fi;
975
976    lsh:=List(ls, x-> Concatenation(x,[1]));
977    one:=List(ls[1],_->0);
978    Add(one,1);
979    Add(lsh,one);
980
981    ah:=AffineSemigroup(lsh);
982    primeq:=BettiElementsOfAffineSemigroup(ah);
983
984    return Maximum(Set(primeq, x->CatenaryDegreeOfSetOfFactorizations(
985            FactorizationsVectorWRTList(x,lsh))));
986
987end);
988
989######################################################################
990# Computes the monotone catenary degree of the affine semigroup a
991# uses [PH] and Alfredo Sanchez-R.-Navarro thesis
992######################################################################
993InstallGlobalFunction(MonotoneCatenaryDegreeOfAffineSemigroup,
994        function(a)
995    local ls, lsh, ah, primeq, one, dim;
996
997    if not(IsAffineSemigroup(a)) then
998        Error("The argument must be an affine semigroup");
999    fi;
1000
1001    ls:=MinimalGenerators(a);
1002
1003    if ls=[] then return 0;
1004    fi;
1005    dim:=Length(ls[1]);
1006
1007    lsh:=List(ls, x-> Concatenation(x,[1]));
1008    one:=List(ls[1],_->0);
1009    Add(one,1);
1010    Add(lsh,one);
1011
1012    ah:=AffineSemigroup(lsh);
1013    primeq:=DegreesOfPrimitiveElementsOfAffineSemigroup(ah);
1014    primeq:=Set(primeq, x->x{[1..dim]});
1015
1016    return Maximum(Set(primeq, x->MonotoneCatenaryDegreeOfSetOfFactorizations(
1017            FactorizationsVectorWRTList(x,ls))));
1018
1019end);
1020
1021
1022###############################################################################
1023##
1024#O OmegaPrimalityOfElementInAffineSemigroup
1025#
1026# Computes the omega-primality of v in the monoid a
1027###########################################################################
1028InstallMethod(OmegaPrimalityOfElementInAffineSemigroup,
1029        "Computes the omega-primality of x in the monoid s",
1030        [IsHomogeneousList,IsAffineSemigroup],1,
1031        function(x,s)
1032
1033    local i, j, p, rel, rgb, msg, pol, ed,  degree, monomial,  facts, fact, mp,id, reduce, nonnegative,
1034          mu1,A,B,C, lt, tl, exp, new;
1035
1036    msg:=MinimalGenerators(s);
1037    ed:=Length(msg);
1038    mp:=MinimalPresentationOfAffineSemigroup(s);
1039    p := [];
1040    # list of exponents to monomial
1041    monomial:=function(l)
1042        local i;
1043        pol:=1;
1044        for i in [1..ed] do
1045            pol:=pol*Indeterminate(Rationals,i)^l[i];
1046        od;
1047        return pol;
1048    end;
1049    ## monomial to exponents
1050    exp:=function(mon)
1051        return List([1..ed],i-> DegreeIndeterminate(mon,i));
1052    end;
1053    ##computes the degree of a monomial
1054    degree:=function(mon)
1055        return Sum(exp(mon));
1056    end;
1057    ##nonnegative
1058    nonnegative:=function(l)
1059        return ForAll(l, x-> x>=0);
1060    end;
1061
1062    for rel in mp do
1063        Add( p, monomial(rel[1])-monomial(rel[2]));
1064    od;
1065
1066    facts:=FactorizationsVectorWRTList(x,msg);
1067    if facts=[] then
1068        return 0;
1069    fi;
1070    Info(InfoNumSgps,2,"Factorizations of the element :", facts);
1071    fact:=facts[Length(facts)];
1072    id:=IdentityMat(ed);
1073
1074    for i in [1..ed] do
1075        Add(p,monomial(fact+id[i])-monomial(fact));
1076    od;
1077
1078    # for j in [2..Length(facts)] do
1079    #     for i in [1..ed] do
1080    #         Add(p,monomial(facts[j]+id[i])-monomial(facts[j]));
1081    #     od;
1082    # od;
1083
1084    Info(InfoNumSgps,2,"Computing a Groebner basis");
1085    #a canonical system of generators of sigma_I
1086    rgb := ReducedGroebnerBasis( p, MonomialGrevlexOrdering() );
1087
1088
1089    #normal form wrt rgb
1090    reduce:=function(r)
1091        return PolynomialReducedRemainder(r,rgb, MonomialGrevlexOrdering());
1092    end;
1093
1094    #leading term
1095    lt:=function(r)
1096        return LeadingMonomialOfPolynomial(r,MonomialGrevlexOrdering());
1097    end;
1098
1099    #tail
1100    tl:=function(r)
1101        return lt(r)-r;
1102    end;
1103
1104    mu1:=reduce(monomial(fact));
1105    #A:=Set([mu1]);
1106    A:=Union(Set([mu1]),Set(facts,monomial));
1107
1108    Info(InfoNumSgps,2,"Computing minimal elements of the ideal.");
1109    while true do
1110        B:=[];
1111        for i in A do
1112            for rel in rgb do
1113                new:=Lcm(i,tl(rel))/tl(rel)*lt(rel);
1114                if First(A, a->nonnegative(exp(new)-exp(a)))=fail then
1115                    AddSet(B,new);
1116                    Info(InfoNumSgps,2,"New possible minimal element: ",exp(new));
1117                fi;
1118            od;
1119        od;
1120        if IsSubset(A,B) then
1121            A:=Filtered(A, i->First(Difference(A,[i]), j-> nonnegative(exp(i)-exp(j)))=fail);
1122            return Maximum(Set(Set(A,exp),Sum));
1123        fi;
1124        A:=Union(A,B);
1125    od;
1126end);
1127
1128InstallMethod(OmegaPrimality,
1129    "for an element in an affine semigroup",
1130    [IsHomogeneousList,IsAffineSemigroup],
1131    OmegaPrimalityOfElementInAffineSemigroup);
1132
1133
1134InstallMethod(OmegaPrimality,
1135    "for an element in an affine semigroup",
1136    [IsAffineSemigroup,IsHomogeneousList],
1137    function(a,l)
1138        return OmegaPrimalityOfElementInAffineSemigroup(l,a);
1139    end);
1140
1141
1142######################################################################
1143# Computes the omega primality of the affine semigroup a
1144######################################################################
1145InstallGlobalFunction(OmegaPrimalityOfAffineSemigroup,
1146        function(a)
1147    local ls;
1148
1149    if not(IsAffineSemigroup(a)) then
1150        Error("The argument must be an affine semigroup");
1151    fi;
1152
1153    ls:=MinimalGenerators(a);
1154    return Maximum(Set(ls, v-> OmegaPrimalityOfElementInAffineSemigroup(v,a)));
1155end);
1156
1157InstallMethod(OmegaPrimality,
1158    "for affine semigroups",
1159    [IsAffineSemigroup],
1160    OmegaPrimalityOfAffineSemigroup);
1161
1162#############################################################################
1163##
1164#F  ElasticityOfFactorizationsElementWRTAffineSemigroup(n,s)
1165##
1166##  Computes the quotient (maximum length)/(minimum lenght) of the
1167##  factorizations of an element <n> as linear combinations
1168##  with nonnegative coefficients of the minimal generators
1169##  of the semigroup <s>.
1170##
1171#############################################################################
1172InstallGlobalFunction(ElasticityOfFactorizationsElementWRTAffineSemigroup, function(n,s)
1173    local gen,max,min,lenfact;
1174
1175    if not IsAffineSemigroup(s) then
1176        Error("The second argument must be an affine semigroup.\n");
1177    fi;
1178
1179    if not IsListOfIntegersNS(n) then
1180        Error("The first argument must be a list of integers.\n");
1181    fi;
1182
1183    if not (n in s) then
1184        Error("The first argument does not belong to the second.\n");
1185    fi; #this ensures that the lengths won't be zero
1186
1187    gen:=MinimalGeneratingSystem(s);
1188    lenfact:=Set(FactorizationsVectorWRTList(n,gen),Sum);
1189    min:=Minimum(lenfact);
1190    max:=Maximum(lenfact);
1191    if min=0 then
1192        Error("The element seems to be the zero vector.\n");
1193    fi;
1194
1195    return max/min;
1196end);
1197
1198InstallMethod(Elasticity,
1199    "Elasticity of the factorizations of an element in an affine semigroup",
1200    [IsHomogeneousList,IsAffineSemigroup],
1201    ElasticityOfFactorizationsElementWRTAffineSemigroup);
1202
1203InstallMethod(Elasticity,
1204    "Elasticity of the factorizations in an affine semigroup of one of its elements",
1205    [IsAffineSemigroup, IsHomogeneousList],
1206    function(a,v)
1207        return  ElasticityOfFactorizationsElementWRTAffineSemigroup(v,a);
1208    end);
1209
1210
1211#####################################################################
1212# Computes the elasticity of the affine semigroup a
1213#####################################################################
1214InstallGlobalFunction(ElasticityOfAffineSemigroup,
1215    function(s)
1216
1217    local gens, positive, negative, cir, el,a, elt,
1218        cols,rows, e, comb, c, i, circ,mat, matt, sum, sp, sn;
1219
1220    # computes x^+
1221    positive:=function(x)
1222        local p,i;
1223
1224        p:=[];
1225        for i in [1..Length(x)] do
1226            p[i]:=Maximum(x[i],0);
1227        od;
1228
1229        return p;
1230    end;
1231
1232    # computes x^-
1233    negative:=function(x)
1234        local p,i;
1235
1236        p:=[];
1237        for i in [1..Length(x)] do
1238            p[i]:=-Minimum(x[i],0);
1239        od;
1240
1241        return p;
1242    end;
1243
1244
1245    if not(IsAffineSemigroup(s)) then
1246        Error("The argument must be an affine semigroup.");
1247    fi;
1248    gens:=MinimalGenerators(s);
1249    a:=TransposedMat(gens);
1250    el:=1;
1251    #we compute the circuits as explained in Eisenbud-Sturmfels Lemma 8.8
1252    rows:=Length(a);
1253    cols:=Length(a[1]);
1254    e:=IdentityMat(cols);
1255    mat:=TransposedMat(a);
1256    comb:=IteratorOfCombinations([1..cols],rows+1);
1257    #Print("Combinations ",comb,"\n");
1258    Info(InfoNumSgps,2,"Running over ",NrCombinations([1..cols],rows+1)," combinations to compute circuits");
1259    for c in comb do
1260        sum:=0;
1261        for i in [1..rows+1] do
1262            matt:=mat{Difference(c,[c[i]])};
1263            #Print("c ",c," da ",matt,"\n");
1264            sum:=sum+(-1)^(i+1)*DeterminantIntMat(matt)*e[c[i]];
1265        od;
1266        if ForAny(sum, x->x<>0) then
1267            sum:=sum/Gcd(sum);
1268            sp:=Sum(positive(sum));
1269            sn:=Sum(negative(sum));
1270            if sp>=sn then
1271                elt:=sp/sn;
1272            else
1273                elt:=sn/sp;
1274            fi;
1275            if elt>el then
1276                Info(InfoNumSgps,2, "new elasticity reached ", elt);
1277                el:=elt;
1278            fi;
1279        fi;
1280    od;
1281
1282    return el;
1283end);
1284
1285InstallMethod(Elasticity,
1286    "Computes the elasticity of an affine semigroup",
1287    [IsAffineSemigroup],
1288    ElasticityOfAffineSemigroup
1289    );
1290
1291###################################################################
1292#lawrence Lifting
1293###################################################################
1294InstallGlobalFunction(LawrenceLiftingOfAffineSemigroup,function(a)
1295	local dim,ed, msg, id, lft, zero, zeroes, aid, zeroid;
1296
1297    if not(IsAffineSemigroup(a)) then
1298        Error("The argument must be an affine semigroup.");
1299    fi;
1300
1301    msg:=MinimalGenerators(a);
1302    ed:=Length(msg);
1303    dim:=Length(msg[1]);
1304    id:=IdentityMat(ed);
1305    zero:=List([1..ed],_->0);
1306    zeroes:=List([1..dim],_->zero);
1307
1308    msg:=TransposedMat(msg);
1309    aid:=TransposedMat(Concatenation(msg,id));
1310    zeroid:=TransposedMat(Concatenation(zeroes,id));
1311
1312
1313
1314    lft:=(Concatenation(aid,zeroid));
1315    return AffineSemigroup(lft);
1316end);
1317
1318#####################################################
1319# Degrees of primitive elements with Lawrence lifting
1320#####################################################
1321InstallMethod(DegreesOfPrimitiveElementsOfAffineSemigroup,
1322        "Computes the set of primitive elements of an affine semigroup",
1323        [IsAffineSemigroup],1,
1324        function(a)
1325	local msg, mgs, ed, dim, prlft, lft,zero, zeroes, id, aid, zeroid;
1326
1327    Info(InfoNumSgps,2,"Using Lawrence lifting for computing primitive elements.");
1328    mgs:=MinimalGenerators(a);
1329    ed:=Length(mgs);
1330    dim:=Length(mgs[1]);
1331    #lft:=LawrenceLiftingOfAffineSemigroup(a);
1332    #prlft:=MinimalPresentationOfAffineSemigroup(lft);
1333    id:=IdentityMat(ed);
1334    zero:=List([1..ed],_->0);
1335    zeroes:=List([1..dim],_->zero);
1336
1337    msg:=TransposedMat(mgs);
1338    aid:=TransposedMat(Concatenation(msg,id));
1339    zeroid:=TransposedMat(Concatenation(zeroes,id));
1340
1341    lft:=(Concatenation(aid,zeroid));
1342    prlft:=GeneratorsOfKernelCongruence(lft);
1343    Info(InfoNumSgps,2,"The kernel congruence is ", prlft);
1344
1345    return Union(Set(prlft, p->(p[1]{[ed+1..ed+ed]})*mgs),mgs);
1346end);
1347
1348#####################################################################
1349# Computes the tame degree of the affine semigroup a
1350#####################################################################
1351InstallMethod(TameDegreeOfAffineSemigroup,
1352        "Computes the tame degree of an affine semigroup",
1353        [IsAffineSemigroup],1,
1354        function(a)
1355  local prim, tams, p, max, ls;
1356
1357  ls:=MinimalGenerators(a);
1358
1359  Info(InfoNumSgps,2,"Computing primitive elements of ", ls);
1360  prim:=DegreesOfPrimitiveElementsOfAffineSemigroup(a);
1361  Info(InfoNumSgps,2,"Primitive elements of ", ls, ": ",prim);
1362  max:=0;
1363  for p in prim do
1364    Info(InfoNumSgps,2,"Computing the tame degree of ",p);
1365    tams:=TameDegreeOfSetOfFactorizations(
1366                  FactorizationsVectorWRTList(p,ls));
1367    Info(InfoNumSgps,2,"The tame degree of ",p, " is ",tams);
1368    if tams>max then
1369      max:=tams;
1370    fi;
1371  od;
1372  return max;
1373end);
1374
1375InstallMethod(TameDegree,
1376    "Tame degree for affine semigroups",
1377    [IsAffineSemigroup],
1378    TameDegreeOfAffineSemigroup);
1379
1380###############################################################################
1381##
1382##########################################################################
1383##
1384#F NumSgpsUseNormaliz
1385#  Loads the package NormalizInterface and reads affine-extra-ni
1386##########################################################################
1387InstallGlobalFunction(NumSgpsUseNormaliz, function()
1388    if LoadPackage("NormalizInterface")=true then
1389        ReadPackage("numericalsgps", "gap/affine-extra-ni.gi");
1390        NumSgpsCanUseNI:=true;
1391        return true;
1392    else
1393        return fail;
1394    fi;
1395
1396end);
1397
1398
1399##########################################################################
1400##
1401#F NumSgpsUseSingular
1402#  Loads the package singular and reads affine-extra-s
1403##########################################################################
1404InstallGlobalFunction(NumSgpsUseSingular, function()
1405    if IsPackageMarkedForLoading("SingularInterface","0.0") then
1406        Print("SingularInterface is already loaded and it is incompatible with Singular.\n");
1407        return fail;
1408    fi;
1409
1410    if NumSgpsCanUseSingular then
1411        return true;
1412    fi;
1413
1414    if LoadPackage("singular")=true then
1415        ReadPackage("numericalsgps", "gap/affine-extra-s.gi");
1416        ReadPackage("numericalsgps", "gap/polynomials-extra-s.gd");
1417        ReadPackage("numericalsgps", "gap/polynomials-extra-s.gi");
1418        NumSgpsCanUseSingular:=true;
1419        if NumSgpsCanUse4ti2 then
1420          ReadPackage("numericalsgps","gap/apery-extra-4ti2i-sing.gi");
1421        fi;
1422        return true;
1423    else
1424        return fail;
1425    fi;
1426
1427end);
1428
1429##########################################################################
1430##
1431#F NumSgpsUseSingularInterface
1432#  Loads the package SingularInterface and reads affine-extra-si
1433##########################################################################
1434InstallGlobalFunction(NumSgpsUseSingularInterface, function()
1435    if IsPackageMarkedForLoading("Singular","0.0") then
1436        Print("Singular is already loaded and it is incompatible with SingularInterface.\n");
1437        return fail;
1438    fi;
1439
1440    if LoadPackage("SingularInterface")=true then
1441        ReadPackage("numericalsgps", "gap/affine-extra-si.gi");
1442        NumSgpsCanUseSI:=true;
1443        return true;
1444    else
1445        return fail;
1446    fi;
1447
1448end);
1449
1450##########################################################################
1451##
1452#F NumSgpsUse4ti2
1453#  Loads the package 4ti2Interface and reads affine-extra-4ti2
1454##########################################################################
1455InstallGlobalFunction(NumSgpsUse4ti2, function()
1456    if LoadPackage("4ti2Interface")=true then
1457        ReadPackage("numericalsgps", "gap/affine-extra-4ti2.gi");
1458        ReadPackage("numericalsgps", "gap/frobenius-extra-4ti2i.gi");
1459        if NumSgpsCanUseSingular then
1460          ReadPackage("numericalsgps","gap/apery-extra-4ti2i-sing.gi");
1461        fi;
1462        NumSgpsCanUse4ti2:=true;
1463        return true;
1464    else
1465        return fail;
1466    fi;
1467
1468end);
1469
1470##########################################################################
1471##
1472#F NumSgpsUse4ti2gap
1473#  Loads the package 4ti2gap and reads affine-extra-4ti2gap
1474##########################################################################
1475InstallGlobalFunction(NumSgpsUse4ti2gap, function()
1476    if LoadPackage("4ti2gap")=true then
1477        ReadPackage("numericalsgps", "gap/affine-extra-4ti2gap.gi");
1478        ReadPackage("numericalsgps", "gap/frobenius-extra-4ti2gap.gi");
1479        NumSgpsCanUse4ti2gap:=true;
1480        return true;
1481    else
1482        return fail;
1483    fi;
1484
1485end);
1486
1487##########################################################################
1488##
1489#F NumSgpsUseGradedModules
1490#  Loads the package GradedModules and reads affine-extra-gm
1491##########################################################################
1492InstallGlobalFunction(NumSgpsUseGradedModules, function()
1493    if LoadPackage("GradedModules")=true then
1494        ReadPackage("numericalsgps", "gap/affine-extra-gm.gi");
1495        NumSgpsCanUseGradedModules:=true;
1496        return true;
1497    else
1498        return fail;
1499    fi;
1500
1501end);
1502