1############################################################################# 2## 3#W good-semigroups.gd Manuel Delgado <mdelgado@fc.up.pt> 4#W Pedro A. Garcia-Sanchez <pedro@ugr.es> 5## 6#Y Copyright 2016-- Centro de Matemática da Universidade do Porto, Portugal and IEMath-GR, Universidad de Granada, Spain 7############################################################################# 8 9#################################################### 10## 11#F NumericalDuplication(S,E,b) 12## returns 2S\cup(2E+b) 13#################################################### 14InstallGlobalFunction(NumericalDuplication, function(S,E,b) 15 local smallS, doubS, smallE, f, small, mgsE, mgsS; 16 17 if not(IsNumericalSemigroup(S)) or not(IsIdealOfNumericalSemigroup(E)) then 18 Error("The first argument must be a numerical semigroup, and the second an ideal"); 19 fi; 20 21 if not(IsInt(b)) then 22 Error("The third argument must be an integer"); 23 fi; 24 25 if not(b mod 2=1) then 26 Error("The third argument must be an odd integer"); 27 fi; 28 29 # if not(b in S) then 30 # Error("The third argument must belong to the first argument"); 31 # fi; 32 33 mgsE:=MinimalGeneratingSystem(E); 34 # if not(ForAll(mgsE, x -> x in S)) then 35 # Error("The second argument must be a integral ideal of the first"); 36 # fi; 37 38 mgsS:=MinimalGenerators(S); 39 40 if not(ForAll(Cartesian(mgsE,mgsE), p->Sum(p)+b in S)) then 41 Error("The arguments do not define a semigroup (E+E+b is not included in S)"); 42 fi; 43 44 return NumericalSemigroup(Union(2*mgsS, 2*mgsE+b)); 45end); 46 47 48 49################################################### 50## 51#F NumericalSemigroupDuplication(S,E) 52## returns S\bowtie E 53################################################### 54InstallGlobalFunction(NumericalSemigroupDuplication,function(S,E) 55 local M, mgsE; 56 57 58 if not(IsNumericalSemigroup(S)) or not(IsIdealOfNumericalSemigroup(E)) then 59 Error("The first argument must be a numerical semigroup, and the second an ideal"); 60 fi; 61 62 mgsE:=MinimalGeneratingSystem(E); 63 if not(ForAll(mgsE, x -> x in S)) then 64 Error("The second argument must be an integral ideal of the first"); 65 fi; 66 67 M:=Objectify(GoodSemigroupsType, rec()); 68 SetNumericalSemigroupGS(M,S); 69 SetIdealGS(M,E); 70 SetDefinedByDuplication(M,true); 71 72 return M; 73end); 74 75 76################################################### 77## 78#F AmalgamationOfNumericalSemigroups(S,E,c) 79## returns S\bowtie^f E, f multiplication by c 80################################################### 81InstallGlobalFunction(AmalgamationOfNumericalSemigroups, function(S,E,c) 82 local M, T, msg; 83 84 if not(IsNumericalSemigroup(S)) or not(IsIdealOfNumericalSemigroup(E)) then 85 Error("The first argument must be a numerical semigroup, and the second an ideal"); 86 fi; 87 88 if not(IsPosInt(c)) then 89 Error("The third argument must be a positive integer"); 90 fi; 91 92 T:=AmbientNumericalSemigroupOfIdeal(E); 93 msg:=MinimalGeneratingSystem(S); 94 if not(ForAll(msg, x-> c*x in T)) then 95 Error("Multiplication by the third argument must be a morphism from the first argument to the ambient semigroup of the second"); 96 fi; 97 98 M:=Objectify(GoodSemigroupsType, rec()); 99 SetNumericalSemigroupGS(M,S); 100 SetIdealGS(M,E); 101 SetMorphismGS(M,c); 102 SetDefinedByAmalgamation(M,true); 103 104 return M; 105end); 106 107################################################### 108## 109#F CartesianProductOfNumericalSemigroups(S1,S2) 110## Computes the cartesian product of S1 and S2, which 111## is a good semigroup 112################################################### 113InstallGlobalFunction(CartesianProductOfNumericalSemigroups, function(S1,S2) 114 local M; 115 116 if not(IsNumericalSemigroup(S1)) or not(IsNumericalSemigroup(S2)) then 117 Error("The arguments must be numerical semigroups"); 118 fi; 119 120 M:=Objectify(GoodSemigroupsType, rec()); 121 SetNumericalSemigroupListGS(M,[S1,S2]); 122 SetDefinedByCartesianProduct(M,true); 123 124 return M; 125end); 126 127 128 129################################################### 130## 131#F RepresentsSmallElementsOfGoodSemigroup(X) 132## detects if X is a good semiring 133################################################### 134InstallGlobalFunction(RepresentsSmallElementsOfGoodSemigroup, function(X) 135 local c, inf, conG2, C; 136 137 inf:=function(x,y) 138 return [Minimum(x[1],y[1]), Minimum(x[2],y[2])]; 139 end; 140 141 if not(IsRectangularTable(X)) and ForAll(X, x->Length(x)=2) then 142 Error("The argument must be a list of pairs of positive integers"); 143 fi; 144 145 if not(ForAll(X, x->IsInt(x[1]) and IsInt(x[2]) and x[1]>=0 and x[2]>=0)) then 146 Error("The argument must be a list of pairs of positive integers"); 147 fi; 148 149 C:=[0,0]; 150 if not(C in X) then 151 Info(InfoNumSgps,2,"Zero is not in the set."); 152 return false; 153 fi; 154 155 C[1]:=Maximum(List(X,x->x[1])); 156 C[2]:=Maximum(List(X,x->x[2])); 157 if not(C in X) then 158 Info(InfoNumSgps,2,"The maximum is not in the set."); 159 return false; 160 fi; 161 162 c:=Cartesian(X,X); 163 if ForAny(c, p->not(inf(p[1]+p[2],C) in X)) then 164 Info(InfoNumSgps,2,"The set is not closed under addition modulo inf the maximum."); 165 return false; 166 fi; 167 168 if ForAny(c, p->not(inf(p[1], p[2]) in X)) then 169 Info(InfoNumSgps,2,"The set is not closed under infimums."); 170 return false; 171 fi; 172 conG2:=First(X, x->x[1]<C[1] and ForAny(X,y-> x[1]=y[1] and x[2]<y[2] and not(ForAny(X, z->x[2]=z[2] and z[1]>x[1])))); 173 if conG2<>fail then 174 Info(InfoNumSgps,2,"The set is not a good semiring: ",conG2); 175 return false; 176 fi; 177 conG2:=First(X, x->x[2]<C[2] and ForAny(X,y-> x[2]=y[2] and x[1]<y[1] and not(ForAny(X, z->x[1]=z[1] and z[2]>x[2])))); 178 if conG2<>fail then 179 Info(InfoNumSgps,2,"The set is not a good semiring: ",conG2); 180 return false; 181 fi; 182 return true; 183end); 184 185 186################################################### 187## 188#F GoodSemigroup(X,C) 189## define the good semigroup from the set of points G 190## with conductor C 191################################################### 192InstallGlobalFunction(GoodSemigroup, function(Gn,C) 193 local M, p1, p2, c, CC, sm, SemiRing_NS, gen, inf, G; 194 195 if not(IsRectangularTable(Gn)) and ForAll(Gn, x->IsList(x) and Length(x)=2) then 196 Error("The first argument must be a list of pairs of positive integers"); 197 fi; 198 199 if not(ForAll(Gn, x->IsInt(x[1]) and IsInt(x[2]) and x[1]>=0 and x[2]>=0)) then 200 Error("The first argument must be a list of pairs of positive integers"); 201 fi; 202 203 if not(IsList(C)) and Length(C)=2 then 204 Error("The second argument must be a list (pair) of nonnegative integers"); 205 fi; 206 207 if not(IsInt(C[1]) and IsInt(C[2]) and C[1]>=0 and C[2]>=0) then 208 Error("The second argument must be a list (pair) of nonnegative integers"); 209 fi; 210 211 inf:=function(u,v) 212 return [Minimum(u[1],v[1]),Minimum(u[2],v[2])]; 213 end; 214 215 ############################################################### 216 ## 217 #F SemiRing_NS(G,C) 218 ## G is a set of points; 219 ## computes the saturation wrt sum (cutted by C) and inf 220 ################################################################ 221 SemiRing_NS:=function(G,C) 222 local O, OO, new,i,j, o; 223 224 225 O:=G; 226 # sum saturation 227 repeat 228 new:=[]; 229 for i in [1..Length(O)] do 230 for j in [i.. Length(O)] do 231 o:=inf(C,O[i]+O[j]); 232 233 if not(o in O) then 234 Add(new, o); 235 fi; 236 od; 237 od; 238 O:=Union(O,new); 239 until new=[]; 240 241 O:=Union(O,[[0,0]]); 242 #inf saturation 243 repeat 244 new:=[]; 245 for i in [1..Length(O)] do 246 for j in [i.. Length(O)] do 247 o:=inf(O[i],O[j]); 248 if not(o in O) then 249 Add(new, o); 250 fi; 251 od; 252 od; 253 O:=Union(O,new); 254 until new=[]; 255 256 # #good saturation x coordinate 257 # repeat 258 # new:=First(O, x->x[1]<C[1] and ForAny(O,y-> x[1]=y[1] and x[2]<y[2] and not(ForAny(O, z->x[2]=z[2] and z[1]>x[1])))); 259 # if new<>fail then 260 # Add(O,[C[1],new[2]]); 261 # fi; 262 263 # until new=fail; 264 # #good saturation y coordinate 265 # repeat 266 # new:=First(O, x->x[2]<C[2] and ForAny(O,y-> x[2]=y[2] and x[1]<y[1] and not(ForAny(O, z->x[1]=z[1] and z[2]>x[2])))); 267 # if new<>fail then 268 # Add(O,[new[1],C[2]]); 269 # fi; 270 271 # until new=fail; 272 return O; 273 end; # of SemiRing_NS 274 275 G:=ShallowCopy(Gn); 276 p1:=List(G,x->x[1]); 277 p2:=List(G,x->x[2]); 278 279 CC:=[Maximum(p1), Maximum(p2)]; 280 if not(C[1]>=CC[1] and C[2]>=CC[2]) then 281 Info(InfoNumSgps, 2, "The conductor is not larger than the maximum of the given set"); 282 G:=List(G, x->inf(x,C)); 283 fi; 284 285 286 sm:=Union(SemiRing_NS(G,C),[C]); 287 if not(RepresentsSmallElementsOfGoodSemigroup(sm)) then 288 Error("The given set does not generate a good semigroup"); 289 fi; 290 291 c:=C; 292 while ((c-[0,1]) in sm) or ((c-[1,0]) in sm) do 293 if ((c-[0,1]) in sm) and ((c-[1,0]) in sm) then #c-[1,1] also in sm 294 c:=c-[1,1]; 295 elif c-[0,1] in sm then 296 c:=c-[0,1]; 297 else 298 c:=c-[1,0]; 299 fi; 300 od; 301 if C<>c then #sm must be redefined, and gens 302 Info(InfoNumSgps,2,"Conductor redefined"); 303 sm:=Filtered(sm, x->x[1]<=c[1] and x[2]<=c[2]); 304 gen:=List(G, x->inf(x,c));#x[1]<=c[1] and x[2]<=c[2]); 305 else 306 gen:=ShallowCopy(G); 307 fi; 308 309 M:=Objectify(GoodSemigroupsType, rec()); 310 SetGenerators(M,gen); 311 SetConductor(M,c); 312 SetSmallElements(M,sm); 313 return M; 314end); 315 316################################################### 317## 318#M ConductorOfGoodSemigroup(M) 319#M Conductor(M) 320## returns the conductor of M 321################################################## 322InstallMethod(ConductorOfGoodSemigroup, 323 "Calculates the conductor of the semigroup", 324 [IsGoodSemigroup ],50, 325 function(M) 326 local e,s,c,ce,cs,c1,c2; 327 328 if HasConductor(M) then 329 return(Conductor(M)); 330 fi; 331 332 if HasSmallElements(M) then 333 s:=SmallElements(M); 334 c:=s[Length(s)]; 335 SetConductor(M,c); 336 return c; 337 fi; 338 339 if IsGoodSemigroupByDuplication(M) then 340 Info(InfoNumSgps,2,"Using semigroup duplication formula"); 341 e:=IdealGS(M); 342 ce:=Conductor(e); 343 SetConductor(M,[ce,ce]); 344 return [ce,ce]; 345 fi; 346 347 if IsGoodSemigroupByAmalgamation(M) then 348 Info(InfoNumSgps,2,"Using amalgamation formula"); 349 e:=IdealGS(M); 350 ce:=Conductor(e); 351 s:=NumericalSemigroupGS(M); 352 c:=MorphismGS(M); 353 cs:=CeilingOfRational(ce/c); 354 while true do 355 cs:=cs-1; 356 if (cs in s) and not(2*cs in e) then 357 SetConductor(M,[cs+1,ce]); 358 return [cs+1,ce]; 359 fi; 360 if cs<0 then 361 SetConductor(M,[0,ce]); 362 return [0,ce]; 363 fi; 364 od; 365 fi; 366 367 if IsGoodSemigroupByCartesianProduct(M) then 368 Info(InfoNumSgps,2,"This is a cartesian product, so the two conductors in a list"); 369 return([Conductor(NumericalSemigroupListGS(M)[1]), 370 Conductor(NumericalSemigroupListGS(M)[2])]); 371 fi; 372 373 return fail; 374 375end); 376 377################################################### 378## 379#A SmallElements(M) 380#A SmallElementsOfGoodSemigroup(M) 381## returns de small elements of M, that is, 382## the elements below the conductor 383################################################## 384InstallMethod(SmallElementsOfGoodSemigroup, 385 "Calculates the small elements of the semigroup", 386 [IsGoodSemigroup ],50, 387 function(M) 388 local C,box, sm; 389 390 if HasSmallElements(M) then 391 return SmallElements(M); 392 fi; 393 394 if IsGoodSemigroupByCartesianProduct(M) then 395 sm:=Cartesian(SmallElements(NumericalSemigroupListGS(M)[1]), 396 SmallElements(NumericalSemigroupListGS(M)[2])); 397 SetSmallElements(M,sm); 398 return sm; 399 fi; 400 C:=Conductor(M); 401 box:=Cartesian([0..C[1]],[0..C[2]]); 402 sm:=Intersection(box,M); 403 SetSmallElements(M,sm); 404 return sm; 405end); 406 407 408############################################################### 409## 410#A IsSymmetric(M) 411## Determines if M is symmetric 412############################################################### 413InstallMethod(IsSymmetricGoodSemigroup, 414"Determines if the good semigroup is symmetric", 415[IsGoodSemigroup], function(M) 416 local sm, w1, w2, b1,b2, c; 417 c:=Conductor(M); 418 sm:=SmallElementsOfGoodSemigroup(M); 419 w1:=Length(Set(sm,x->x[1])); 420 w2:=Length(Set(sm,x->x[2])); 421 b1:=Length(Filtered(sm, x-> x[1]=c[1] and x[2]<c[2])); 422 b2:=Length(Filtered(sm, x-> x[2]=c[2] and x[1]<c[1])); 423 return Sum(c)=w1+w2+b1+b2-2; 424end); 425 426InstallMethod(IsSymmetric, 427"Tests wheter the semigroup is symmetric", 428[IsGoodSemigroup], IsSymmetricGoodSemigroup 429); 430 431 432################################################### 433## 434#A MinimalGenerators(M) 435#A MinimalGoodGeneratingSystemOfGoodSemigroup(M) 436## returns the unique minimal good generating of the 437## good semigroup M 438################################################### 439InstallMethod(MinimalGoodGeneratingSystemOfGoodSemigroup, 440 "Calculates the minimal generating system of the semigroup", 441 [IsGoodSemigroup ],50, 442 function(M) 443 local filter,mingen,C; 444 445 ## G is a given set of small elements 446 ## filter outputs a subset that generates all 447 filter:=function(G,C) 448 449 local member1, member2, gen, g, gg, visited, left; 450 451 452 member1:=function(X,x) 453 if x[1]*x[2]=0 then 454 return x[2]<=0 and x[1]=0; 455 fi; 456 if x[1]<0 or x[2]< 0 then 457 return false; 458 fi; 459 460 return ForAny(X, y->member1(X,x-y)); 461 462 end; 463 464 member2:=function(X,x) 465 if x[1]*x[2]=0 then 466 return x[1]<=0 and x[2]=0; 467 fi; 468 if x[1]<0 or x[2]< 0 then 469 return false; 470 fi; 471 472 return ForAny(X, y->member2(X,x-y)); 473 474 end; 475 476 gen:=Set(ShallowCopy(G)); 477 RemoveSet(gen,[0,0]); 478 479 # removing those that can be infimums of two others to make faster 480 # the next test 481 for g in G do 482 if g[1]<C[1] then 483 if First(gen, x->x[1]=g[1] and x[2]>g[2])<>fail then 484 RemoveSet(gen,g); 485 continue; 486 fi; 487 fi; 488 489 if g[2]<C[2] then 490 if First(gen, x->x[2]=g[2] and x[2]>g[2])<>fail then 491 RemoveSet(gen,g); 492 continue; 493 fi; 494 fi; 495 od; 496 497 if gen=[] then 498 return []; 499 fi; 500 501 visited:=[]; 502 left:=gen; 503 while left<>[] and gen<>[] do 504 g:=left[1]; 505 AddSet(visited,g); 506 left:=Difference(gen,visited); 507 gg:=Difference(gen,[g]); 508 if g[1]=C[1] then 509 if member2(gg,g) then 510 RemoveSet(gen,g); 511 fi; 512 elif g[2]=C[2] then 513 if member1(gg,g) then 514 RemoveSet(gen,g); 515 fi; 516 else 517 if member1(gg,g) and member2(gg,g) then 518 RemoveSet(gen,g); 519 fi; 520 fi; 521 od; 522 return gen; 523 end; 524 525 if IsGoodSemigroupByCartesianProduct(M) then 526 Print("ToDo\n"); 527 return fail; 528 fi; 529 530 C:=Conductor(M); 531 if HasGenerators(M) then 532 mingen:=filter(Generators(M),C); 533 #SetGenerators(M,mingen); 534 return mingen; 535 fi; 536 537 mingen:=filter(SmallElementsOfGoodSemigroup(M),C); 538 SetGenerators(M,mingen); 539 return mingen; 540end); 541 542############################################################### 543## 544#F GoodSemigroupBySmallElements(M) 545## Constructs good semigroup from a set of small elements 546############################################################### 547InstallGlobalFunction(GoodSemigroupBySmallElements, function(X) 548 local M, C, c, sm; 549 if not(IsRectangularTable(X)) and ForAll(X, x->Length(x)=2) then 550 Error("The argument must be a list of pairs of positive integers"); 551 fi; 552 553 if not(ForAll(X, x->IsInt(x[1]) and IsInt(x[2]) and x[1]>=0 and x[2]>=0)) then 554 Error("The argument must be a list of pairs of positive integers"); 555 fi; 556 557 if not(RepresentsSmallElementsOfGoodSemigroup(X)) then 558 Error("This set is not the set of small elements of a good semigroup"); 559 fi; 560 561 C:=[Maximum(List(X,x->x[1])),Maximum(List(X,x->x[2]))]; 562 563 #now we see if C is the minimum conductor 564 c:=C; 565 sm:=ShallowCopy(X); 566 while ((c-[0,1]) in sm) or ((c-[1,0]) in sm) do 567 if ((c-[0,1]) in sm) and ((c-[1,0]) in sm) then #c-[1,1] also in sm 568 c:=c-[1,1]; 569 elif c-[0,1] in sm then 570 c:=c-[0,1]; 571 else 572 c:=c-[1,0]; 573 fi; 574 od; 575 if C<>c then #small elements must be redefined 576 Info(InfoNumSgps,2,"Conductor redefined"); 577 sm:=Filtered(X, x->x[1]<=c[1] and x[2]<=c[2]); 578 fi; 579 580 M:=Objectify(GoodSemigroupsType, rec()); 581 #SetGenerators(M,gen); 582 SetConductor(M,c); 583 SetSmallElements(M,sm); 584 return M; 585end); 586 587############################################################### 588## 589#F ArfGoodSemigroupClosure(M) 590## Constructs Arf good semigroup closure of M 591############################################################### 592InstallGlobalFunction(ArfGoodSemigroupClosure,function(s) 593 local CompatibilityLevelOfMultiplicitySequences, s1, s2, t1, t2, sm, sma, c, included, i, cand, ca, c1, c2, k, seq1, seq2, tail1, tail2, car; 594 595 CompatibilityLevelOfMultiplicitySequences:=function(M) 596 local ismultseq, k, s, max, D, i,j, inarf; 597 # tests whether x is in the Arf semigroup with multiplicity 598 # sequence j 599 inarf:=function(x,j) 600 local l; 601 if x>Sum(j) then 602 return true; 603 fi; 604 if x=0 then 605 return true; 606 fi; 607 if x<j[1] then 608 return false; 609 fi; 610 l:=List([1..Length(j)], i-> Sum(j{[1..i]})); 611 return x in l; 612 end; 613 614 # tests if m is a multiplicity sequence 615 ismultseq := function(m) 616 local n; 617 n:=Length(m); 618 return ForAll([1..n-1], i-> inarf(m[i], m{[i+1..n]})); 619 end; 620 621 if not(IsTable(M)) then 622 Error("The first argument must be a list of multiplicity sequences"); 623 fi; 624 625 if Length(M)<>2 then 626 Error("We are so far only considering Arf good semigroups in N^2"); 627 fi; 628 629 if not(ForAll(Union(M), IsPosInt)) then 630 Error("The first argument must be a list of multiplicity sequences"); 631 fi; 632 633 if not(ForAll(M, ismultseq)) then 634 Error("The first argument must be a list of multiplicity sequences"); 635 fi; 636 637 s:=[]; 638 max:= Maximum(List(M, Length)); 639 640 for i in [1..2] do 641 s[i]:=[]; 642 for j in [1..Length(M[i])] do 643 s[i][j]:=First([j+1..Length(M[i])], k-> M[i][j]=Sum(M[i]{[j+1..k]})); 644 if s[i][j]=fail then 645 s[i][j]:=M[i][j]-Sum(M[i]{[j+1..Length(M[i])]})+Length(M[i])-j; 646 else 647 s[i][j]:=s[i][j]-j; 648 fi; 649 od; 650 od; 651 for i in [1..2] do 652 s[i]:=Concatenation(s[i],List([Length(s[i])+1..max],_->1)); 653 od; 654 655 D:=Filtered([1..max], j->s[1][j]<>s[2][j]); 656 k:=[]; 657 if D=[] then 658 k:=infinity; 659 else 660 k:=Minimum(Set(D, j->j+Minimum(s[1][j],s[2][j]))); 661 fi; 662 return k; 663 end; 664 665 if not(IsGoodSemigroup(s)) then 666 Error("The argument must be a good semigroup"); 667 fi; 668 669 670 671 sm := SmallElementsOfGoodSemigroup(s); 672 c:= Conductor(s); 673 s1:=Set(sm, x->x[1]); 674 s2:=Set(sm, x->x[2]); 675 s1:=NumericalSemigroupBySmallElements(s1); 676 s2:=NumericalSemigroupBySmallElements(s2); 677 t1:=ArfNumericalSemigroupClosure(s1); 678 t2:=ArfNumericalSemigroupClosure(s2); 679 c1:=Conductor(t1); 680 c2:=Conductor(t2); 681 seq1:=MultiplicitySequenceOfNumericalSemigroup(t1); 682 seq2:=MultiplicitySequenceOfNumericalSemigroup(t2); 683 k:=CompatibilityLevelOfMultiplicitySequences([seq1,seq2]); 684 685 t1:=Intersection([0..c[1]],t1); 686 t2:=Intersection([0..c[2]],t2); 687 ca:=[c1,c2]; 688 i:=1; 689 included:=true; 690 while included do 691 if i>Length(t1) or i>Length(t2) then 692 i:=i-1; 693 sma:=List([1..i], i->[t1[i],t2[i]]); 694 return GoodSemigroupBySmallElements(sma); 695 fi; 696 if i>k+1 then 697 i:=i-1; 698 sma:=List([1..i], i->[t1[i],t2[i]]); 699 return GoodSemigroupBySmallElements(sma); 700 fi; 701 sma:=Union(List([1..i], i->[t1[i],t2[i]]), Cartesian(t1{[i+1..Length(t1)]}, t2{[i+1..Length(t2)]})); 702 if First(sm, x->not(x in sma))<> fail then 703 included:=false; 704 else 705 i:=i+1; 706 fi; 707 od; 708 i:=i-1; 709 tail1:=Intersection(t1{[i+1..Length(t1)]},[0..c[1]]); 710 tail2:=Intersection(t2{[i+1..Length(t2)]},[0..c[2]]); 711 car:=Cartesian(tail1,tail2); 712 sma:=Union(List([1..i], i->[t1[i],t2[i]]), car); 713 714 return GoodSemigroupBySmallElements(sma); 715end); 716 717InstallMethod(ArfClosure, 718"Computes the Arf closure of a good semigroup", 719[IsGoodSemigroup], 720 ArfGoodSemigroupClosure 721); 722 723############################################################### 724## 725#F MaximalElementsOfGoodSemigroup(M) 726## returns the set of maximal elements of M 727############################################################### 728InstallGlobalFunction(MaximalElementsOfGoodSemigroup,function(g) 729 local sm; 730 if not(IsGoodSemigroup(g)) then 731 Error("The argument must be a good semigroup"); 732 fi; 733 734 sm:=SmallElements(g); 735 return Filtered(Difference(sm,[Conductor(g)]), x->not(ForAny(sm, 736 y->((y[1]=x[1] and y[2]>x[2]) or (y[1]>x[1] and y[2]=x[2]))))); 737end); 738 739############################################################### 740## 741#F IrreducibleMaximalElementsOfGoodSemigroup(M) 742## returns the set of irreducible maximal elements of M 743############################################################### 744InstallGlobalFunction(IrreducibleMaximalElementsOfGoodSemigroup, 745function(g) 746 local mx; 747 mx:=MaximalElementsOfGoodSemigroup(g); 748 if Length(mx)=1 then 749 return mx; 750 fi; 751 return Filtered(Difference(mx,[[0,0]]), x->not(ForAny(Difference(mx,[[0,0]]), y->y<>x and (y[1]<=x[1]) and (y[2]<=x[2]) and ((x-y) in mx)))); 752end); 753 754############################################################### 755## 756#F GoodSemigroupByMaximalElements(S1,S2,mx,c) 757## returns the good semigroup determined by removing from 758## S1 x S2 the set of points "above" a maximal element; c is 759## the conductor 760############################################################### 761InstallGlobalFunction(GoodSemigroupByMaximalElements, 762function(s1,s2,mx,c) 763 local l1,l2, m1,m2,c1,c2,q, v, cc, g1,g2; 764 765 if not(IsNumericalSemigroup(s1)) then 766 Error("The first argument must be a numerical semigroup"); 767 fi; 768 if not(IsNumericalSemigroup(s2)) then 769 Error("The second argument must be a numerical semigroup"); 770 fi; 771 772 l1:=List(mx,x->x[1]); 773 l2:=List(mx,x->x[2]); 774 q:=c; 775 # removed because this is true only for curves 776 #if ForAny(mx, x-> not(q-x in mx)) then 777 # Error("There is no symmetry in the third argument"); 778 #fi; 779 g1:=Intersection([0..q[1]+1],s1); 780 g2:=Intersection([0..q[2]+1],s2); 781 cc:=Cartesian(g1,g2); 782 return GoodSemigroupBySmallElements(Difference(cc, 783 Filtered(cc, x->ForAny(mx, 784 y->((y[1]=x[1] and x[2]>y[2]) or (x[1]>y[1] and y[2]=x[2])))) 785 )); 786end); 787 788 789################################################### 790## 791#M BelongsToGoodSemigroup 792## decides if a vector is in the semigroup 793################################################## 794InstallMethod(BelongsToGoodSemigroup, 795 "Tests if the vector is in the semigroup", 796 [IsHomogeneousList, IsGoodSemigroup], 50, 797 function(v, a) 798 local S,T,E,c,s,t,sprime, X, saturation, C,edge1,edge2, sm, edge; 799 800 801 # G is a set of points; 802 # computes the saturation wrt sum (cutted by the edges) and inf 803 saturation:=function(G) 804 local inf, O, OO, new,i,j, o; 805 806 inf:=function(u,v) 807 return [Minimum(u[1],v[1]),Minimum(u[2],v[2])]; 808 end; 809 810 O:=G; 811 # sum saturation 812 repeat 813 new:=[]; 814 for i in [1..Length(O)] do 815 for j in [i.. Length(O)] do 816 o:=inf(C,O[i]+O[j]); 817 818 if not(o in O) then 819 Add(new, o); 820 fi; 821 od; 822 od; 823 O:=Union(O,new); 824 until new=[]; 825 826 O:=Union(O,[[0,0]]); 827 #inf saturation 828 repeat 829 new:=[]; 830 for i in [1..Length(O)] do 831 for j in [i.. Length(O)] do 832 o:=inf(O[i],O[j]); 833 if not(o in O) then 834 Add(new, o); 835 fi; 836 od; 837 od; 838 O:=Union(O,new); 839 until new=[]; 840 841 # #good saturation x coordinate 842 # repeat 843 # new:=First(O, x->x[1]<C[1] and ForAny(O,y-> x[1]=y[1] and x[2]<y[2] and not(ForAny(O, z->x[2]=z[2] and z[1]>x[1])))); 844 # if new<>fail then 845 # Add(O,[C[1],new[2]]); 846 # fi; 847 848 # until new=fail; 849 # #good saturation y coordinate 850 # repeat 851 # new:=First(O, x->x[2]<C[2] and ForAny(O,y-> x[2]=y[2] and x[1]<y[1] and not(ForAny(O, z->x[1]=z[1] and z[2]>x[2])))); 852 # if new<>fail then 853 # Add(O,[new[1],C[2]]); 854 # fi; 855 856 # until new=fail; 857 return O; 858 end; 859 860 if Length(v)<>2 then 861 Error("The first argument must be a list with two integers (a pair)"); 862 fi; 863 if not(ForAll(v, IsInt)) then 864 Error("The first argument must be a list with two integers (a pair)"); 865 fi; 866 if IsGoodSemigroupByDuplication(a) then 867 S:=NumericalSemigroupGS(a); 868 E:=IdealGS(a); 869 if v[1]=v[2] then 870 return v[1] in S; 871 fi; 872 873 if v[1]<v[2] then 874 return (v[1] in E) and (v[2] in S); 875 fi; 876 877 if v[2]<v[1] then 878 return (v[2] in E) and (v[1] in S); 879 fi; 880 fi; 881 if IsGoodSemigroupByAmalgamation(a) then 882 S:=NumericalSemigroupGS(a); 883 E:=IdealGS(a); 884 c:=MorphismGS(a); 885 T:=UnderlyingNSIdeal(E); 886 s:=v[1]; 887 t:=v[2]; 888 if not(s in S) then 889 return false; 890 fi; 891 if not(t in T) then 892 return false; 893 fi; 894 895 if t=c*s then 896 return true; 897 fi; 898 899 if (c*s in E) and (t in E) then 900 return true; 901 fi; 902 903 if t< c*s then 904 return t in E; 905 fi; 906 if t>c*s then 907 if not(c*s in E) then 908 return false; 909 fi; 910 if t in E then 911 return true; 912 fi; 913 if not(IsInt(t/c)) then 914 return false; 915 fi; 916 return t/c in S; 917 fi; 918 919 fi; 920 921 if IsGoodSemigroupByCartesianProduct(a) then 922 return v[1] in NumericalSemigroupListGS(a)[1] and 923 v[2] in NumericalSemigroupListGS(a)[2]; 924 fi; 925 926 if HasSmallElements(a) then 927 C:=Conductor(a); 928 929 if v[1]>=C[1] and v[2]>=C[2] then 930 return true; 931 fi; 932 933 sm:=SmallElements(a); 934 935 if v[1]>C[1] then 936 edge:=Filtered(sm,x->x[1]=C[1]); 937 return ForAny(edge, x->x[2]=v[2]); 938 fi; 939 940 if v[2]>C[2] then 941 edge:=Filtered(sm,x->x[2]=C[2]); 942 return ForAny(edge, x->x[1]=v[1]); 943 fi; 944 945 return v in sm; 946 947 fi; 948 949 950 if HasGenerators(a) then 951 X:=Generators(a); 952 C:=Conductor(a); 953 954 if v[1]>=C[1] and v[2]>=C[2] then 955 return true; 956 fi; 957 958 if not(HasSmallElements(a)) then 959 SetSmallElements(a,saturation(X)); 960 fi; 961 sm:=SmallElements(a); 962 963 if v[1]>C[1] then 964 edge:=Filtered(sm,x->x[1]=C[1]); 965 return ForAny(edge, x->x[2]=v[2]); 966 fi; 967 968 if v[2]>C[2] then 969 edge:=Filtered(sm,x->x[2]=C[2]); 970 return ForAny(edge, x->x[1]=v[1]); 971 fi; 972 973 return v in sm; 974 fi; 975 976 return false; 977 978end); 979 980 981################################################### 982## 983#M BelongsToGoodSemigroup 984## decides if a vector is in the semigroup 985################################################## 986InstallMethod( \in, 987 "for good semigroups", 988 [ IsHomogeneousList, IsGoodSemigroup], 989 function( v, a ) 990 return BelongsToGoodSemigroup(v,a); 991end); 992 993################################################### 994## 995#M Equality of good semigroups 996## decides if the two good semigroups are equal 997################################################## 998InstallMethod( \=, 999 "for good semigroups", 1000 [ IsGoodSemigroup, IsGoodSemigroup], 1001 function( a, b ) 1002 return Conductor(a)=Conductor(b) and SmallElements(a)=SmallElements(b); 1003end); 1004 1005 1006 ############################################################################# 1007 ## 1008 #M ViewObj(S) 1009 ## 1010 ## This method for good semigroups. 1011 ## 1012 ############################################################################# 1013 InstallMethod( ViewObj, 1014 "Displays an Affine Semigroup", 1015 [IsGoodSemigroup], 1016 function( S ) 1017 Print("<Good semigroup>"); 1018 1019 end); 1020 1021 ############################################################################# 1022 ## 1023 #M ViewString(S) 1024 ## 1025 ## This method for good semigroups. 1026 ## 1027 ############################################################################# 1028 InstallMethod( ViewString, 1029 "String of an Affine Semigroup", 1030 [IsGoodSemigroup], 1031 function( S ) 1032 return ("Good semigroup"); 1033 1034 end); 1035 1036 1037 ############################################################################# 1038 ## 1039 #M Display(S) 1040 ## 1041 ## This method for good semigroups. ## under construction... (= View) 1042 ## 1043 ############################################################################# 1044InstallMethod( Display, 1045 "Displays an Affine Semigroup", 1046 [IsGoodSemigroup], 1047 function( S ) 1048 Print("<Good semigroup>"); 1049 end); 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061##################################################### 1062## 1063#F ProjectionOfGoodSemigroup:=function(S,num) 1064## Given a good semigroup S it returns the num-th numerical semigroup projection 1065##################################################### 1066 1067InstallGlobalFunction(ProjectionOfGoodSemigroup, 1068function(S,num) 1069 local small,S1,S2; 1070 if not(IsGoodSemigroup(S)) then 1071 Error("The first argument must be a good semigroup"); 1072 fi; 1073 1074 if not(num=1 or num=2) then 1075 Error("The second argument must be 1 or 2"); 1076 fi; 1077 small:=SmallElements(S); 1078 1079 if num=1 then 1080 return NumericalSemigroupBySmallElements(Set([1..Length(small)],i->small[i][1])); 1081 fi; 1082 if num=2 then 1083 return NumericalSemigroupBySmallElements(Set([1..Length(small)],i->small[i][2])); 1084 fi; 1085end); 1086 1087 1088##################################################### 1089## 1090#F GenusOfGoodSemigroup:=function(S) 1091## Given a good semigroup S it returns its genus 1092##################################################### 1093InstallGlobalFunction(GenusOfGoodSemigroup, 1094function(S) 1095 if not(IsGoodSemigroup(S)) then 1096 Error("The argument must be a good semigroup"); 1097 fi; 1098 return Length(MaximalElementsOfGoodSemigroup(S))+Genus(ProjectionOfGoodSemigroup(S,1))+Genus(ProjectionOfGoodSemigroup(S,2)); 1099end); 1100 1101 1102InstallMethod(Genus,"Genus for a good semigroup",[IsGoodSemigroup], GenusOfGoodSemigroup ); 1103 1104##################################################### 1105## 1106#F LengthOfGoodSemigroup:=function(S) 1107## Given a good semigroup S it returns its length 1108##################################################### 1109InstallGlobalFunction(LengthOfGoodSemigroup, 1110function(S) 1111 local c; 1112 if not(IsGoodSemigroup(S)) then 1113 Error("The argument must be a good semigroup"); 1114 fi; 1115 c:=Conductor(S); 1116 return c[1]+c[2]-GenusOfGoodSemigroup(S); 1117end); 1118 1119InstallMethod(Length,"for a good semigroup",[IsGoodSemigroup], LengthOfGoodSemigroup ); 1120##################################################### 1121#F AperySetOfGoodSemigroup:=function(S) 1122## Given a good semigroup S it returns a list with the elements of the Apery Set 1123##################################################### 1124InstallGlobalFunction(AperySetOfGoodSemigroup, 1125function(S) 1126 local c,small,i,j,AddElementsOverTheConductor; 1127 1128 AddElementsOverTheConductor:=function(v,w) 1129 local ags,i,j; 1130 1131 if Length(v)=1 then 1132 ags:=[]; 1133 for i in [v[1]..w[1]] do 1134 ags:=Union(ags,[[i]]); 1135 od; 1136 1137 else 1138 ags:=[]; 1139 for i in AddElementsOverTheConductor(v{[1..Length(v)-1]},w{[1..Length(v)-1]}) do 1140 for j in [v[Length(v)]..w[Length(v)]] do 1141 ags:=Union(ags,[Concatenation(i,[j])]); 1142 od; 1143 od; 1144 fi; 1145 1146 return ags; 1147 end; 1148 1149 if not(IsGoodSemigroup(S)) then 1150 Error("The argument must be a good semigroup"); 1151 fi; 1152 1153 c:=Conductor(S); 1154 small:=SmallElements(S); 1155 1156 #First we add to the small elements the elements on the infinite lines that can to become elements of the AperySet. 1157 1158 for i in Filtered(small,j->j[1]=c[1]) do 1159 for j in [c[1]+1..c[1]+small[2][1]] do 1160 small:=Union(small,[[j,i[2]]]); 1161 od; 1162 od; 1163 1164 for i in Filtered(small,j->j[2]=c[2]) do 1165 for j in [c[2]+1..c[2]+small[2][2]] do 1166 small:=Union(small,[[i[1],j]]); 1167 od; 1168 od; 1169 1170 return Filtered(Union(small,AddElementsOverTheConductor(c,c+small[2])),i-> not i-small[2] in small); 1171end); 1172 1173##################################################### 1174#F StratifiedAperySetOfGoodSemigroup:=function(S) 1175## Given a good semigroup S, it returns a list 1176# where the elements are the levels of the AperySet 1177##################################################### 1178InstallGlobalFunction(StratifiedAperySetOfGoodSemigroup, 1179function(S) 1180local Dominance,ce,small,A,ags,temp,temp2; 1181 1182 Dominance:=function(v,w,cond) 1183 return v=w or ForAll([1..Length(v)], i->v[i]<w[i] or w[i]=cond[i]); 1184 end; 1185 1186 if not(IsGoodSemigroup(S)) then 1187 Error("The argument must be a good semigroup"); 1188 fi; 1189 1190 small:=SmallElements(S); 1191 ce:=Conductor(S)+small[2]; 1192 A:=AperySetOfGoodSemigroup(S); 1193 ags:=[]; 1194 while A<>[] do 1195 temp:=Filtered(A,i->Length(Filtered(A,j->Dominance(i,j,ce)))=1); 1196 temp2:=Filtered(temp,i->Filtered(temp,j->j[1]=i[1] and j[2]>i[2])=[] or Filtered(temp,j->j[2]=i[2] and j[1]>i[1])=[]); 1197 ags:=Union(ags,[temp2]); 1198 A:=Filtered(A,i->not i in temp2); 1199 od; 1200 Info(InfoNumSgps,2,"Number of levels ", Length(ags)); 1201 return ags; 1202end); 1203 1204 1205##################################################### 1206#F AbsoluteIrreduciblesOfGoodSemigroup:=function(S) 1207## Given a good semigroup S, the function returns the irreducible absolutes of S. 1208# These are the elements that generates S as semiring. 1209##################################################### 1210InstallGlobalFunction(AbsoluteIrreduciblesOfGoodSemigroup, 1211function(S) 1212local ElementsOnTheEdge,TransformToInf,c,small,irrabsf,irrabsi,infi,edge,i; 1213 1214 if not(IsGoodSemigroup(S)) then 1215 Error("The argument must be a good semigroup"); 1216 fi; 1217 1218 #This function check if an elements has a coordinate equal to the conductor. 1219 ElementsOnTheEdge:=function(vs,c) 1220 return vs[1]=c[1] or vs[2]=c[2]; 1221 end; 1222 1223 #This function transforms the elements with a coordinate equal to the conductor in infinities. 1224 TransformToInf:=function(vs,c) 1225 local a,i; 1226 a:=ShallowCopy(vs); 1227 for i in Filtered([1..2],j->vs[j]=c[j]) do 1228 a[i]:=infinity; 1229 od; 1230 return a; 1231 end; 1232 1233 c:=Conductor(S); 1234 small:=Difference(SmallElements(S),[[0,0]]); 1235 #Computation of finite irreducible absolutes. 1236 irrabsf:=IrreducibleMaximalElementsOfGoodSemigroup(S); 1237 1238 #I take the elements of S different from the conductor but with a coordinate equal to this one. 1239 edge:=Filtered(small,k->k<>c and ElementsOnTheEdge(k,c)); 1240 1241 infi:=[]; 1242 1243 #Here I add to Infi the infinities in the square over the conductor (built considering the multiplicity) 1244 for i in [0..small[1][1]-1] do 1245 infi:=Union(infi,[[c[1]+i,infinity]]); 1246 od; 1247 1248 for i in [0..small[1][2]-1] do 1249 infi:=Union(infi,[[infinity,c[2]+i]]); 1250 od; 1251 1252 #Here I add the infinities under the conductor 1253 for i in edge do 1254 infi:=Union(infi,[TransformToInf(i,c)]); 1255 od; 1256 1257 #Computation of infinite irreducible absolutes 1258 irrabsi:=Filtered(infi,i->Filtered(small,j->i-j in infi)=[]); 1259 1260 return Union(irrabsi,irrabsf); 1261end); 1262 1263 1264##################################################### 1265#F TracksOfGoodSemigroup:=function(S) 1266## Given a good semigroup S, the function returns the tracks of S. 1267##################################################### 1268InstallGlobalFunction(TracksOfGoodSemigroup, 1269function(S) 1270local CompareGS,MinimumGS,I,RemoveLabels,GluePieceOfTrack,ComputePieceOfTrack,T,temp; 1271 1272 if not(IsGoodSemigroup(S)) then 1273 Error("The argument must be a good semigroup"); 1274 fi; 1275 1276 CompareGS:=function(v,w) 1277 1278 return ForAll([1..Length(v)], i->v[i]<=w[i]); 1279 end; 1280 1281 MinimumGS:=function(v,w) 1282 return List([1..Length(v)],i->Minimum(v[i],w[i])); 1283 end; 1284 1285 #It glues a new piece of track to an existing track. T is the list of all piece of track. V is a list of two elements, 1286 # V[1] represents not complete tracks and V[2] the complete tracks. 1287 #The function add a new piece to the incomplete tracks and returns the updated V. 1288 GluePieceOfTrack:=function(T,V) 1289 local ags,temp,i,j; 1290 ags:=[[],[]]; 1291 ags[2]:=ShallowCopy(V[2]); 1292 for i in V[1] do 1293 temp:=i[Length(i)]; 1294 if temp="last" then 1295 ags[2]:=Union(ags[2],[i]); 1296 else 1297 for j in Filtered(T,k->k[1]=temp) do 1298 ags[1]:=Union(ags[1],[Concatenation(i,[j[2]])]); 1299 od; 1300 fi; 1301 od; 1302 return ags; 1303 end; 1304 1305 #This funcion compute all possibles piece of track of a good semigroups having irreducible absolutes I 1306 ComputePieceOfTrack:=function(I) 1307 local IsAPOT,MaximalRed,ags,first,last,i; 1308 1309 #It check if between two irreducible absolutes there is a piece of track. It check if their minimum overcome 1310 #the maximum in both direction or is equal to this one in entrambe le direzioni o coincide 1311 IsAPOT:=function(a,b) 1312 local min; 1313 if CompareGS(a[1],b[1]) or CompareGS(b[1],a[1]) then return false; else if a[1][1]>b[1][1] then return false; else 1314 1315 min:=MinimumGS(a[1],b[1]); return min[2]>=a[3] and min[1]>=b[2]; 1316 fi; fi; 1317 end; 1318 1319 #If (x,y) is an irreducible absolute it returns (x1,y1), where (x,y1) is the greatest irr. abs. under (x,y) 1320 # and (x1,y) is the greatest irr. abs. on the left of (x,y). 1321 MaximalRed:=function(v,I) 1322 local Factorize,ind,temp,temp2,temp3; 1323 1324 Factorize:=function(n,l) 1325 local a,b,ags,i,c,j,a1; 1326 1327 if l=[] then 1328 return []; 1329 1330 else 1331 a1:=Filtered([1..Length(l)],i->l[i]<>infinity); 1332 a:=List(a1,k->l[k]); 1333 b:=FactorizationsIntegerWRTList(n,a); 1334 ags:=[]; 1335 for i in b do 1336 c:=List([1..Length(l)],o->0); 1337 j:=1; 1338 while j<=Length(a1) do 1339 c[a1[j]]:=i[j]; j:=j+1; 1340 od; 1341 ags:=Union(ags,[c]); 1342 od; 1343 return ags; 1344 fi; 1345 1346 end; 1347 1348 if not v in I then 1349 return [0,0]; 1350 1351 else 1352 if infinity in v then 1353 temp3:=[0,0]; 1354 ind:=First([1,2],i->v[i]<>infinity); 1355 temp3[3-ind]:=0; 1356 temp:=Filtered(I,i->i[ind]<v[ind]); 1357 temp2:=List(List(Factorize(v[ind],List(temp,i->i[ind])),j->Sum(List([1..Length(j)],k->j[k]*temp[k]))),k1->k1[3-ind]); 1358 1359 if temp2=[] then 1360 temp3[ind]:=0; 1361 return Reversed(temp3); 1362 1363 else 1364 temp3[ind]:=Maximum(temp2); 1365 return Reversed(temp3); 1366 fi; 1367 else 1368 temp3:=[0,0]; 1369 1370 for ind in [1,2] do 1371 temp:=Filtered(I,i->i[ind]<v[ind]); 1372 temp2:=List(List(Factorize(v[ind],List(temp,i->i[ind])),j->Sum(List([1..Length(j)],k->j[k]*temp[k]))),k1->k1[3-ind]); 1373 1374 if temp2=[] then 1375 temp3[ind]:=0; 1376 else 1377 temp3[ind]:=Maximum(temp2); 1378 fi; 1379 od; 1380 return Reversed(temp3); 1381 fi; 1382 fi; 1383 end; 1384 1385 1386 #If (x,y) is an irreducible absolute it returns ((x,y),x1,y1), where (x,y1) is the greatest irr. abs. under (x,y) 1387 # and (x1,y) is the greatest irr. abs. on the left of (x,y). 1388 I:=List(I,i->Concatenation([i],MaximalRed(i,I))); 1389 1390 #I add all the Piece Of Track 1391 ags:=List(Filtered(Cartesian(I,I),i->IsAPOT(i[1],i[2])),k->[k[1][1],k[2][1]]); 1392 1393 #I add the point of start and the point of end 1394 first:=Filtered(I,i->i[2]=0); 1395 last:=Filtered(I,i->i[3]=0); 1396 1397 for i in first do 1398 ags:=Union(ags,[["first",i[1]]]); 1399 od; 1400 1401 for i in last do 1402 ags:=Union(ags,[[i[1],"last"]]); 1403 od; 1404 1405 return ags; 1406 end; 1407 1408 #This function removes the label "first" and "last" in the tracks. 1409 RemoveLabels:=function(T) 1410 return List(T,i->Filtered(i,j->j<>"last" and j<>"first")); 1411 end; 1412 1413 I:=AbsoluteIrreduciblesOfGoodSemigroup(S); 1414 T:=ComputePieceOfTrack(I); 1415 1416 #The idea is to create the list of all tracks, adding one by one the piece of tracks in all possible way, reccalling 1417 #GluePieceOfTrack until all possible track are completed (V[1]=[]) 1418 temp:=[[["first"]],[]]; 1419 temp:=GluePieceOfTrack(T,temp); 1420 1421 while temp[1]<>[] do 1422 temp:=GluePieceOfTrack(T,temp); 1423 od; 1424 1425 return RemoveLabels(temp[2]); 1426 1427end); 1428 1429############################################################### 1430## 1431#P IsLocal(S) 1432## Determines if S is local 1433############################################################### 1434 1435InstallMethod(IsLocal, 1436"Determines if the good semigroup is local", 1437[IsGoodSemigroup], function(S) 1438local small; 1439small:=Difference(SmallElements(S),[[0,0]]); 1440return ForAll([1..Length(small)],i->small[i][1]<>0); 1441end); 1442 1443############################################################### 1444## 1445#A Multiplicity(S) 1446## Determines the multiplicity of S 1447############################################################### 1448 1449InstallMethod(Multiplicity, 1450"Returns the multiplicity of a local good semigroup", 1451[IsGoodSemigroup], function(S) 1452local small; 1453if not(IsLocal(S)) then 1454 Error("The good semigroup must be local"); 1455fi; 1456 1457small:=SmallElements(S); 1458return small[2]; 1459end); 1460 1461 1462