1############################################################################ 2## 3## bipart.gi 4## Copyright (C) 2013-15 James D. Mitchell 5## 6## Licensing information can be found in the README file of this package. 7## 8############################################################################# 9## 10 11############################################################################# 12# Family and type. 13# 14# One per degree to avoid lists with bipartitions of different degrees 15# belonging to IsAssociativeElementCollection. 16############################################################################# 17 18BindGlobal("TYPES_BIPART", []); 19BindGlobal("TYPE_BIPART", 20function(n) 21 local fam, type; 22 23 n := n + 1; # since the degree can be 0 24 25 if IsBound(TYPES_BIPART[n]) then 26 return TYPES_BIPART[n]; 27 fi; 28 29 fam := NewFamily(Concatenation("BipartitionFamily", String(n - 1)), 30 IsBipartition, 31 CanEasilySortElements, 32 CanEasilySortElements); 33 34 type := NewType(fam, 35 IsBipartition and IsInternalRep); 36 TYPES_BIPART[n] := type; 37 return type; 38end); 39 40############################################################################# 41# Pickler 42############################################################################# 43 44InstallMethod(IO_Pickle, "for a bipartition", 45[IsFile, IsBipartition], 46function(file, x) 47 if IO_Write(file, "BIPA") = fail then 48 return IO_Error; 49 fi; 50 return IO_Pickle(file, IntRepOfBipartition(x)); 51end); 52 53IO_Unpicklers.BIPA := function(file) 54 local blocks; 55 56 blocks := IO_Unpickle(file); 57 if blocks = IO_Error then 58 return IO_Error; 59 fi; 60 return BIPART_NC(blocks); 61end; 62 63############################################################################# 64# Implications 65############################################################################# 66 67InstallTrueMethod(IsPermBipartition, IsTransBipartition 68 and IsDualTransBipartition); 69 70InstallTrueMethod(IsBlockBijection, IsPermBipartition); 71 72############################################################################# 73# GAP level - directly using interface to C/C++ level 74############################################################################# 75 76# Fundamental attributes 77 78InstallMethod(DegreeOfBipartition, "for a bipartition", 79[IsBipartition], BIPART_DEGREE); 80 81InstallMethod(NrBlocks, "for a bipartition", 82[IsBipartition], BIPART_NR_BLOCKS); 83 84InstallMethod(NrLeftBlocks, "for a bipartition", 85[IsBipartition], BIPART_NR_LEFT_BLOCKS); 86 87InstallMethod(RankOfBipartition, "for a bipartition", 88[IsBipartition], x -> BIPART_RANK(x, 0)); 89 90# Constructors 91 92InstallGlobalFunction(Bipartition, 93function(classes) 94 local n, copy, i, j; 95 96 if not IsList(classes) 97 or ForAny(classes, x -> not IsHomogeneousList(x) 98 or not IsDuplicateFree(x)) then 99 ErrorNoReturn("Semigroups: Bipartition: usage,\n", 100 "the argument <classes> must consist of duplicate-free ", 101 "homogeneous lists,"); 102 fi; 103 104 n := Sum(classes, Length) / 2; 105 106 if n >= 2 ^ 29 then 107 ErrorNoReturn("Semigroups: Bipartition: usage,\n", 108 "the maximum degree of a bipartition ", 109 "is 2 ^ 29 - 1,"); 110 elif not ForAll(classes, x -> ForAll(x, 111 i -> (IsPosInt(i) or IsNegInt(i)) 112 and AbsInt(i) <= n)) then 113 ErrorNoReturn("Semigroups: Bipartition: usage,\n", 114 "the argument <classes> must consist of lists of ", 115 "integers from [-", n, " .. -1, 1 .. ", n, "],"); 116 elif not IsEmpty(classes) 117 and Union(classes) <> Concatenation([-n .. -1], [1 .. n]) then 118 ErrorNoReturn("Semigroups: Bipartition: usage,\n", 119 "the union of the argument <classes> must be ", 120 "[-", n, " .. -1, 1 .. ", n, "],"); 121 fi; 122 123 copy := List(classes, ShallowCopy); 124 for i in [1 .. Length(copy)] do 125 for j in [1 .. Length(copy[i])] do 126 if copy[i][j] < 0 then 127 copy[i][j] := AbsInt(copy[i][j]) + n; 128 fi; 129 od; 130 od; 131 132 Perform(copy, Sort); 133 Sort(copy); 134 135 for i in [1 .. Length(copy)] do 136 for j in [1 .. Length(copy[i])] do 137 if copy[i][j] > n then 138 copy[i][j] := -copy[i][j] + n; 139 fi; 140 od; 141 od; 142 return BIPART_NC(copy); 143end); 144 145InstallMethod(BipartitionByIntRep, "for a list", [IsList], 146function(blocks) 147 local n, next, seen, i; 148 149 n := Length(blocks); 150 if not IsEvenInt(n) then 151 ErrorNoReturn("Semigroups: BipartitionByIntRep: usage,\n", 152 "the length of the argument <blocks> must be an even ", 153 "integer,"); 154 elif n >= 2 ^ 30 then 155 ErrorNoReturn("Semigroups: BipartitionByIntRep: usage,\n", 156 "the length of the argument <blocks> must not exceed ", 157 "2 ^ 30 - 1,"); 158 elif not ForAll(blocks, i -> IsPosInt(i) and i <= n) then 159 ErrorNoReturn("Semigroups: BipartitionByIntRep: usage,\n", 160 "the elements of the argument <blocks> must be positive ", 161 "integers not exceeding ", n, ","); 162 fi; 163 164 next := 0; 165 seen := BlistList([1 .. Maximum(blocks)], []); 166 167 for i in [1 .. n] do 168 if not seen[blocks[i]] then 169 next := next + 1; 170 if blocks[i] <> next then 171 ErrorNoReturn("Semigroups: BipartitionByIntRep: usage,\n", 172 "expected ", next, " but found ", blocks[i], 173 ", in position ", i, ","); 174 fi; 175 seen[blocks[i]] := true; 176 fi; 177 od; 178 return BIPART_NC(blocks); 179end); 180 181InstallMethod(IdentityBipartition, "for zero", [IsZeroCyc], 182function(n) 183 return Bipartition([]); 184end); 185 186InstallMethod(IdentityBipartition, "for a positive integer", [IsPosInt], 187function(n) 188 local blocks, i; 189 190 if n >= 2 ^ 29 then 191 ErrorNoReturn("Semigroups: IdentityBipartition: usage,\n", 192 "the argument <n> must not exceed 2 ^ 29 - 1,"); 193 fi; 194 blocks := EmptyPlist(2 * n); 195 196 for i in [1 .. n] do 197 blocks[i] := i; 198 blocks[i + n] := i; 199 od; 200 201 return BIPART_NC(blocks); 202end); 203 204InstallMethod(RandomBipartition, "for a random source and pos int", 205[IsRandomSource, IsPosInt], 206function(rs, n) 207 local out, nrblocks, vals, j, i; 208 209 if n >= 2 ^ 29 then 210 ErrorNoReturn("Semigroups: RandomBipartition: usage,\n", 211 "the argument <n> must not exceed 2 ^ 29 - 1,"); 212 fi; 213 out := EmptyPlist(2 * n); 214 nrblocks := 0; 215 vals := [1]; 216 217 for i in [1 .. 2 * n] do 218 j := Random(rs, vals); 219 if j = nrblocks + 1 then 220 nrblocks := nrblocks + 1; 221 Add(vals, nrblocks + 1); 222 fi; 223 out[i] := j; 224 od; 225 226 return BIPART_NC(out); 227end); 228 229InstallMethod(RandomBipartition, "for a pos int", [IsPosInt], 230function(n) 231 return RandomBipartition(GlobalMersenneTwister, n); 232end); 233 234InstallMethod(RandomBlockBijection, "for a random source and pos int", 235[IsRandomSource, IsPosInt], 236function(rs, n) 237 local out, nrblocks, j, free, i; 238 239 if n >= 2 ^ 29 then 240 ErrorNoReturn("Semigroups: RandomBlockBipartition: usage,\n", 241 "the argument <n> must not exceed 2 ^ 29 - 1,"); 242 fi; 243 244 out := EmptyPlist(2 * n); 245 out[1] := 1; 246 nrblocks := 1; 247 248 for i in [2 .. n] do 249 j := Random(rs, [1 .. nrblocks + 1]); 250 if j = nrblocks + 1 then 251 nrblocks := nrblocks + 1; 252 fi; 253 out[i] := j; 254 od; 255 256 free := [n + 1 .. 2 * n]; 257 for i in [1 .. nrblocks] do 258 j := Random(rs, free); 259 out[j] := i; 260 RemoveSet(free, j); 261 od; 262 263 for i in free do 264 out[i] := Random(rs, [1 .. nrblocks]); 265 od; 266 267 return BIPART_NC(out); 268end); 269 270InstallMethod(RandomBlockBijection, "for a pos int", [IsPosInt], 271function(n) 272 return RandomBlockBijection(GlobalMersenneTwister, n); 273end); 274 275# Operators 276 277InstallMethod(PermLeftQuoBipartition, "for a bipartition and bipartition", 278IsIdenticalObj, [IsBipartition, IsBipartition], 279function(x, y) 280 281 if LeftBlocks(x) <> LeftBlocks(y) or RightBlocks(x) <> RightBlocks(y) then 282 ErrorNoReturn("Semigroups: PermLeftQuoBipartition: usage,\n", 283 "the arguments must have equal left and right blocks,"); 284 fi; 285 return BIPART_PERM_LEFT_QUO(x, y); 286end); 287 288# Attributes 289 290InstallMethod(DomainOfBipartition, "for a bipartition", [IsBipartition], 291function(x) 292 local out; 293 out := []; 294 for x in ExtRepOfObj(LeftBlocks(x)) do 295 if IsPosInt(x[1]) then 296 Append(out, x); 297 fi; 298 od; 299 return out; 300end); 301 302InstallMethod(CodomainOfBipartition, "for a bipartition", [IsBipartition], 303function(x) 304 local out; 305 out := []; 306 for x in ExtRepOfObj(RightBlocks(x)) do 307 if IsPosInt(x[1]) then 308 Append(out, -x); 309 fi; 310 od; 311 return out; 312end); 313 314InstallMethod(ExtRepOfObj, "for a bipartition", [IsBipartition], 315BIPART_EXT_REP); 316 317InstallMethod(IntRepOfBipartition, "for a bipartition", [IsBipartition], 318BIPART_INT_REP); 319 320# xx ^ * - linear - 2 * degree 321 322InstallMethod(LeftProjection, "for a bipartition", [IsBipartition], 323BIPART_LEFT_PROJ); 324 325InstallMethod(RightProjection, "for a bipartition", [IsBipartition], 326BIPART_RIGHT_PROJ); 327 328# linear - 2 * degree 329 330InstallMethod(StarOp, "for a bipartition", [IsBipartition], BIPART_STAR); 331 332InstallMethod(ChooseHashFunction, "for a bipartition", 333[IsBipartition, IsInt], 334 function(x, hashlen) 335 return rec(func := BIPART_HASH, 336 data := hashlen); 337end); 338 339############################################################################# 340# GAP level 341############################################################################# 342 343# Attributes 344 345# not a synonym since NrTransverseBlocks also applies to blocks 346 347InstallMethod(NrTransverseBlocks, "for a bipartition", [IsBipartition], 348RankOfBipartition); 349 350InstallMethod(NrRightBlocks, "for a bipartition", [IsBipartition], 351x -> NrBlocks(x) - NrLeftBlocks(x) + NrTransverseBlocks(x)); 352 353InstallMethod(OneMutable, "for a bipartition", 354[IsBipartition], x -> IdentityBipartition(DegreeOfBipartition(x))); 355 356InstallMethod(OneMutable, "for a bipartition collection", 357[IsBipartitionCollection], x -> 358IdentityBipartition(DegreeOfBipartitionCollection(x))); 359 360# the Other is to avoid warning on opening GAP 361 362InstallOtherMethod(InverseMutable, "for a bipartition", [IsBipartition], 363function(x) 364 if IsBlockBijection(x) or IsPartialPermBipartition(x) then 365 return Star(x); 366 fi; 367 return fail; 368end); 369 370# Properties 371 372InstallMethod(IsBlockBijection, "for a bipartition", 373[IsBipartition], 374function(x) 375 return NrBlocks(x) = NrLeftBlocks(x) and NrRightBlocks(x) = NrLeftBlocks(x); 376end); 377 378InstallMethod(IsPartialPermBipartition, "for a bipartition", 379[IsBipartition], 380function(x) 381 return NrLeftBlocks(x) = DegreeOfBipartition(x) 382 and NrRightBlocks(x) = DegreeOfBipartition(x); 383end); 384 385# a bipartition is a transformation if and only if the second row is a 386# permutation of [1 .. n], where n is the degree. 387 388InstallMethod(IsTransBipartition, "for a bipartition", 389[IsBipartition], 390function(x) 391 return NrLeftBlocks(x) = NrTransverseBlocks(x) 392 and NrRightBlocks(x) = DegreeOfBipartition(x); 393end); 394 395InstallMethod(IsDualTransBipartition, "for a bipartition", [IsBipartition], 396function(x) 397 return NrRightBlocks(x) = NrTransverseBlocks(x) 398 and NrLeftBlocks(x) = DegreeOfBipartition(x); 399end); 400 401InstallMethod(IsPermBipartition, "for a bipartition", 402[IsBipartition], 403function(x) 404 return IsPartialPermBipartition(x) 405 and NrTransverseBlocks(x) = DegreeOfBipartition(x); 406end); 407 408# Fundamental operators 409 410InstallMethod(\*, "for a bipartition and a perm", 411[IsBipartition, IsPerm], 412function(x, p) 413 if LargestMovedPoint(p) <= DegreeOfBipartition(x) then 414 return x * AsBipartition(p, DegreeOfBipartition(x)); 415 fi; 416 ErrorNoReturn("Semigroups: \\* (for a bipartition and perm): usage,\n", 417 "the largest moved point of the perm must not be greater\n", 418 "than the degree of the bipartition,"); 419end); 420 421InstallMethod(\*, "for a perm and a bipartition", 422[IsPerm, IsBipartition], 423function(p, x) 424 if LargestMovedPoint(p) <= DegreeOfBipartition(x) then 425 return AsBipartition(p, DegreeOfBipartition(x)) * x; 426 fi; 427 ErrorNoReturn("Semigroups: \\* (for a perm and bipartition): usage,\n", 428 "the largest moved point of the perm must not be greater\n", 429 "than the degree of the bipartition,"); 430end); 431 432InstallMethod(\*, "for a bipartition and a transformation", 433[IsBipartition, IsTransformation], 434function(x, f) 435 if DegreeOfTransformation(f) <= DegreeOfBipartition(x) then 436 return x * AsBipartition(f, DegreeOfBipartition(x)); 437 fi; 438 ErrorNoReturn("Semigroups: \\* (for a bipartition and transformation): ", 439 "usage,\n", 440 "the degree of the transformation must not be greater\n", 441 "than the degree of the bipartition,"); 442end); 443 444InstallMethod(\*, "for a transformation and a bipartition", 445[IsTransformation, IsBipartition], 446function(f, g) 447 if DegreeOfTransformation(f) <= DegreeOfBipartition(g) then 448 return AsBipartition(f, DegreeOfBipartition(g)) * g; 449 fi; 450 ErrorNoReturn("Semigroups: \\* (for a transformation and bipartition): ", 451 "usage,\n", 452 "the degree of the transformation must not be greater\n", 453 "than the degree of the bipartition,"); 454end); 455 456InstallMethod(\*, "for a bipartition and a partial perm", 457[IsBipartition, IsPartialPerm], 458function(f, g) 459 local n; 460 n := DegreeOfBipartition(f); 461 if ForAll([1 .. n], i -> i ^ g <= n) then 462 return f * AsBipartition(g, DegreeOfBipartition(f)); 463 fi; 464 ErrorNoReturn("Semigroups: \\* (for a bipartition and partial perm): usage,", 465 "\nthe partial perm must map [1 .. ", String(n), "] into\n", 466 "[1 .. ", String(n), "],"); 467end); 468 469InstallMethod(\*, "for a partial perm and a bipartition", 470[IsPartialPerm, IsBipartition], 471function(f, g) 472 local n; 473 n := DegreeOfBipartition(g); 474 if ForAll([1 .. n], i -> i ^ f <= n) then 475 return AsBipartition(f, DegreeOfBipartition(g)) * g; 476 fi; 477 ErrorNoReturn("Semigroups: \\* (for a partial perm and a bipartition): ", 478 "usage,\n", 479 "the partial perm must map [1 .. ", String(n), "] into\n", 480 "[1 .. ", String(n), "],"); 481end); 482 483InstallMethod(\^, "for a bipartition and permutation", 484[IsBipartition, IsPerm], 485function(f, p) 486 return p ^ -1 * f * p; 487end); 488 489# Other operators 490 491InstallMethod(PartialPermLeqBipartition, "for a bipartition and a bipartition", 492IsIdenticalObj, [IsBipartition, IsBipartition], 493function(x, y) 494 495 if not (IsPartialPermBipartition(x) and IsPartialPermBipartition(y)) then 496 ErrorNoReturn("Semigroups: PartialPermLeqBipartition: usage,\n", 497 "the arguments must be partial perm bipartitions,"); 498 fi; 499 500 return AsPartialPerm(x) < AsPartialPerm(y); 501end); 502 503# Changing representations 504 505InstallMethod(AsBipartition, "for a permutation and zero", 506[IsPerm, IsZeroCyc], 507function(f, n) 508 return Bipartition([]); 509end); 510 511InstallMethod(AsBipartition, "for a permutation", 512[IsPerm], x -> AsBipartition(x, LargestMovedPoint(x))); 513 514InstallMethod(AsBipartition, "for a partial perm", 515[IsPartialPerm], 516function(x) 517 return AsBipartition(x, Maximum(DegreeOfPartialPerm(x), 518 CodegreeOfPartialPerm(x))); 519end); 520 521InstallMethod(AsBipartition, "for a partial perm and zero", 522[IsPartialPerm, IsZeroCyc], 523function(f, n) 524 return Bipartition([]); 525end); 526 527InstallMethod(AsBipartition, "for a transformation", 528[IsTransformation], x -> AsBipartition(x, DegreeOfTransformation(x))); 529 530InstallMethod(AsBipartition, "for a transformation and zero", 531[IsTransformation, IsZeroCyc], 532function(f, n) 533 return Bipartition([]); 534end); 535 536InstallMethod(AsBipartition, "for a bipartition", [IsBipartition], IdFunc); 537 538InstallMethod(AsBipartition, "for a bipartition", [IsBipartition, IsZeroCyc], 539function(f, n) 540 return Bipartition([]); 541end); 542 543InstallMethod(AsBipartition, "for a pbr and pos int", 544[IsPBR, IsZeroCyc], 545function(x, deg) 546 return Bipartition([]); 547end); 548 549InstallMethod(AsBipartition, "for a pbr and pos int", 550[IsPBR, IsPosInt], 551function(x, deg) 552 if not IsBipartitionPBR(x) then 553 ErrorNoReturn("Semigroups: AsBipartition (for a pbr): usage,\n", 554 "the argument does not satisfy 'IsBipartitionPBR',"); 555 fi; 556 557 return AsBipartition(AsBipartition(x), deg); 558end); 559 560InstallMethod(AsBipartition, "for a pbr", 561[IsPBR], 562function(x) 563 if not IsBipartitionPBR(x) then 564 ErrorNoReturn("Semigroups: AsBipartition (for a pbr): usage,\n", 565 "the argument does not satisfy 'IsBipartitionPBR',"); 566 fi; 567 return Bipartition(Union(ExtRepOfObj(x))); 568end); 569 570InstallMethod(AsBlockBijection, "for a partial perm", 571[IsPartialPerm], 572function(x) 573 return AsBlockBijection(x, Maximum(DegreeOfPartialPerm(x), 574 CodegreeOfPartialPerm(x)) + 1); 575end); 576 577# Viewing, printing etc 578 579InstallMethod(ViewString, "for a bipartition", 580[IsBipartition], 581function(x) 582 local str, ext, i; 583 584 if DegreeOfBipartition(x) = 0 then 585 return "\><empty bipartition>\<"; 586 fi; 587 588 if IsBlockBijection(x) then 589 str := "\>\><block bijection:\< "; 590 else 591 str := "\>\><bipartition:\< "; 592 fi; 593 594 ext := ExtRepOfObj(x); 595 Append(str, "\>"); 596 Append(str, String(ext[1])); 597 Append(str, "\<"); 598 599 for i in [2 .. Length(ext)] do 600 Append(str, ", \>"); 601 Append(str, String(ext[i])); 602 Append(str, "\<"); 603 od; 604 Append(str, ">\<"); 605 return str; 606end); 607 608InstallMethod(String, "for a bipartition", [IsBipartition], 609function(x) 610 return Concatenation("Bipartition(", String(ExtRepOfObj(x)), ")"); 611end); 612 613InstallMethod(PrintString, "for a bipartition", 614[IsBipartition], 615function(x) 616 local ext, str, i; 617 if DegreeOfBipartition(x) = 0 then 618 return "\>\>Bipartition(\< \>[]\<)\<"; 619 fi; 620 ext := ExtRepOfObj(x); 621 str := Concatenation("\>\>Bipartition(\< \>[ ", PrintString(ext[1])); 622 for i in [2 .. Length(ext)] do 623 Append(str, ",\< \>"); 624 Append(str, PrintString(ext[i])); 625 od; 626 Append(str, " \<]"); 627 Append(str, " )\<"); 628 return str; 629end); 630 631InstallMethod(PrintString, "for a bipartition collection", 632[IsBipartitionCollection], 633function(coll) 634 local str, i; 635 636 if IsGreensClass(coll) or IsSemigroup(coll) then 637 TryNextMethod(); 638 fi; 639 640 str := "\>[ "; 641 for i in [1 .. Length(coll)] do 642 if not i = 1 then 643 Append(str, " "); 644 fi; 645 Append(str, "\>"); 646 Append(str, PrintString(coll[i])); 647 if not i = Length(coll) then 648 Append(str, ",\<\n"); 649 else 650 Append(str, " ]\<\n"); 651 fi; 652 od; 653 return str; 654end); 655 656# Bipartition collections 657 658InstallMethod(DegreeOfBipartitionCollection, "for a bipartition semigroup", 659[IsBipartitionSemigroup], 660function(S) 661 return DegreeOfBipartitionSemigroup(S); 662end); 663 664InstallMethod(DegreeOfBipartitionCollection, "for a bipartition collection", 665[IsBipartitionCollection], 666function(coll) 667 return DegreeOfBipartition(coll[1]); 668end); 669 670############################################################################# 671# All of the methods in this section could be done in C/C++ 672############################################################################# 673 674# Change representations . . . 675 676InstallMethod(AsBipartition, "for a permutation and pos int", 677[IsPerm, IsPosInt], 678function(x, n) 679 if n >= 2 ^ 29 then 680 ErrorNoReturn("Semigroups: AsBipartition: usage,\n", 681 "the argument <n> must not exceed 2 ^ 29 - 1,"); 682 elif OnSets([1 .. n], x) <> [1 .. n] then 683 ErrorNoReturn("Semigroups: AsBipartition (for a permutation and pos int):", 684 "\nthe permutation <p> in the 1st argument must permute ", 685 "[1 .. ", String(n), "],"); 686 fi; 687 return BIPART_NC(Concatenation([1 .. n], ListPerm(x ^ -1, n))); 688end); 689 690InstallMethod(AsPartialPerm, "for a bipartition", [IsBipartition], 691function(x) 692 local n, blocks, nrleft, im, out, i; 693 694 if not IsPartialPermBipartition(x) then 695 ErrorNoReturn("Semigroups: AsPartialPerm (for a bipartition):\n", 696 "the argument does not define a partial perm,"); 697 fi; 698 699 n := DegreeOfBipartition(x); 700 blocks := IntRepOfBipartition(x); 701 nrleft := NrLeftBlocks(x); 702 im := [1 .. n] * 0; 703 704 for i in [n + 1 .. 2 * n] do 705 if blocks[i] <= nrleft then 706 im[blocks[i]] := i - n; 707 fi; 708 od; 709 710 out := EmptyPlist(n); 711 for i in [1 .. n] do 712 out[i] := im[blocks[i]]; 713 od; 714 return PartialPermNC(out); 715end); 716 717InstallMethod(AsPermutation, "for a bipartition", [IsBipartition], 718function(x) 719 local n, blocks, im, out, i; 720 721 if not IsPermBipartition(x) then 722 ErrorNoReturn("Semigroups: AsPermutation (for a bipartition):\n", 723 "the argument does not define a permutation,"); 724 fi; 725 726 n := DegreeOfBipartition(x); 727 blocks := IntRepOfBipartition(x); 728 im := EmptyPlist(n); 729 730 for i in [n + 1 .. 2 * n] do 731 im[blocks[i]] := i - n; 732 od; 733 734 out := EmptyPlist(n); 735 for i in [1 .. n] do 736 out[i] := im[blocks[i]]; 737 od; 738 return PermList(out); 739end); 740 741InstallMethod(AsTransformation, "for a bipartition", [IsBipartition], 742function(x) 743 local n, blocks, nr, im, out, i; 744 745 if not IsTransBipartition(x) then 746 ErrorNoReturn("Semigroups: AsTransformation (for a bipartition):\n", 747 "the argument does not define a transformation,"); 748 fi; 749 750 n := DegreeOfBipartition(x); 751 blocks := IntRepOfBipartition(x); 752 nr := NrLeftBlocks(x); 753 im := EmptyPlist(n); 754 755 for i in [n + 1 .. 2 * n] do 756 if blocks[i] <= nr then 757 im[blocks[i]] := i - n; 758 fi; 759 od; 760 761 out := EmptyPlist(n); 762 for i in [1 .. n] do 763 out[i] := im[blocks[i]]; 764 od; 765 return TransformationNC(out); 766end); 767 768InstallMethod(AsBipartition, "for a partial perm and pos int", 769[IsPartialPerm, IsPosInt], 770function(x, n) 771 local r, out, y, j, i; 772 773 if n >= 2 ^ 29 then 774 ErrorNoReturn("Semigroups: AsBipartition: usage,\n", 775 "the argument <n> must not exceed 2 ^ 29 - 1,"); 776 fi; 777 778 r := n; 779 out := EmptyPlist(2 * n); 780 y := x ^ -1; 781 782 for i in [1 .. n] do 783 out[i] := i; 784 j := i ^ y; 785 if j <> 0 then 786 out[n + i] := j; 787 else 788 r := r + 1; 789 out[n + i] := r; 790 fi; 791 od; 792 return BIPART_NC(out); 793end); 794 795InstallMethod(AsBipartition, "for a transformation and a positive integer", 796[IsTransformation, IsPosInt], 797function(f, n) 798 local r, ker, out, g, i; 799 800 if n >= 2 ^ 29 then 801 ErrorNoReturn("Semigroups: AsBipartition: usage,\n", 802 "the argument <n> must not exceed 2 ^ 29 - 1,"); 803 fi; 804 if n < DegreeOfTransformation(f) then 805 # Verify f is a transformation on [1 .. n]. 806 for i in [1 .. n] do 807 if i ^ f > n then 808 ErrorNoReturn("Semigroups: AsBipartition (for a transformation and ", 809 "pos int):\n", 810 "the argument must map [1 .. ", String(n), "] to ", 811 "itself,"); 812 fi; 813 od; 814 fi; 815 816 r := RankOfTransformation(f, n); 817 ker := FlatKernelOfTransformation(f, n); 818 819 out := EmptyPlist(2 * n); 820 g := List([1 .. n], x -> 0); 821 822 # The inverse of f. 823 for i in [1 .. n] do 824 g[i ^ f] := i; 825 od; 826 827 for i in [1 .. n] do 828 out[i] := ker[i]; 829 if g[i] <> 0 then 830 out[n + i] := ker[g[i]]; 831 else 832 r := r + 1; 833 out[n + i] := r; 834 fi; 835 od; 836 return BIPART_NC(out); 837end); 838 839InstallMethod(AsBipartition, "for a bipartition and pos int", 840[IsBipartition, IsPosInt], 841function(f, n) 842 local deg, blocks, out, nrblocks, nrleft, lookup, j, i; 843 844 if n >= 2 ^ 29 then 845 ErrorNoReturn("Semigroups: AsBipartition: usage,\n", 846 "the argument <n> must not exceed 2 ^ 29 - 1,"); 847 fi; 848 deg := DegreeOfBipartition(f); 849 if n = deg then 850 return f; 851 fi; 852 blocks := IntRepOfBipartition(f); 853 out := []; 854 nrblocks := 0; 855 856 if n < deg then 857 for i in [1 .. n] do 858 out[i] := blocks[i]; 859 if out[i] > nrblocks then 860 nrblocks := nrblocks + 1; 861 fi; 862 od; 863 nrleft := nrblocks; 864 lookup := EmptyPlist(NrBlocks(f)); 865 for i in [n + 1 .. 2 * n] do 866 j := blocks[i + deg - n]; 867 if j > nrleft then 868 if not IsBound(lookup[j]) then 869 nrblocks := nrblocks + 1; 870 lookup[j] := nrblocks; 871 fi; 872 j := lookup[j]; 873 fi; 874 out[i] := j; 875 od; 876 else # n > deg 877 for i in [1 .. deg] do 878 out[i] := blocks[i]; 879 od; 880 nrblocks := NrLeftBlocks(f); 881 for i in [deg + 1 .. n] do 882 nrblocks := nrblocks + 1; 883 out[i] := nrblocks; 884 od; 885 nrleft := nrblocks; # = n - deg + NrLeftBlocks(f) 886 for i in [n + 1 .. n + deg] do 887 if blocks[i - n + deg] <= nrleft - n + deg then # it's a left block 888 out[i] := blocks[i - n + deg]; 889 else 890 out[i] := blocks[i - n + deg] + n - deg; 891 fi; 892 od; 893 nrblocks := NrBlocks(f) + n - deg; 894 for i in [n + deg + 1 .. 2 * n] do 895 nrblocks := nrblocks + 1; 896 out[i] := nrblocks; 897 od; 898 fi; 899 return BIPART_NC(out); 900end); 901 902# same as AsBipartition except that all undefined points are in a single block 903# together with an extra (pair of) points. 904 905InstallMethod(AsBlockBijection, "for a partial perm and pos int", 906[IsPartialPerm, IsPosInt], 907function(f, n) 908 local bigblock, nr, out, i; 909 910 if n >= 2 ^ 29 then 911 ErrorNoReturn("Semigroups: AsBlockBijection: usage,\n", 912 "the argument <n> must not exceed 2 ^ 29 - 1,"); 913 fi; 914 915 if n <= Maximum(DegreeOfPartialPerm(f), CodegreeOfPartialPerm(f)) then 916 ErrorNoReturn("Semigroups: AsBlockBijection (for a partial perm and pos ", 917 "int):\n", 918 "the 2nd argument must be strictly greater than the maximum ", 919 "of the\ndegree and codegree of the 1st argument,"); 920 fi; 921 922 nr := 0; 923 out := [1 .. 2 * n] * 0; 924 bigblock := n; 925 926 for i in [1 .. n - 1] do 927 if i ^ f = 0 then 928 if bigblock = n then 929 nr := nr + 1; 930 bigblock := nr; 931 fi; 932 out[i] := bigblock; 933 else 934 nr := nr + 1; 935 out[i] := nr; 936 out[n + i ^ f] := nr; 937 fi; 938 od; 939 940 out[n] := bigblock; 941 out[2 * n] := bigblock; 942 943 for i in [n + 1 .. 2 * n - 1] do 944 if out[i] = 0 then 945 out[i] := bigblock; 946 fi; 947 od; 948 949 return BIPART_NC(out); 950end); 951 952InstallMethod(AsBlockBijection, "for a bipartition and pos int", 953[IsBipartition, IsPosInt], 954function(x, n) 955 if not IsPartialPermBipartition(x) then 956 ErrorNoReturn("Semigroups: AsBlockBijection (for a bipartition and pos ", 957 "int):\n", 958 "the argument <x> must be a partial perm bipartition,"); 959 fi; 960 return AsBlockBijection(AsPartialPerm(x), n); 961end); 962 963InstallMethod(AsBlockBijection, "for a bipartition", 964[IsBipartition], 965function(x) 966 if not IsPartialPermBipartition(x) then 967 ErrorNoReturn("Semigroups: AsBlockBijection (for a bipartition):\n", 968 "the argument <x> must be a partial perm bipartition,"); 969 fi; 970 return AsBlockBijection(AsPartialPerm(x)); 971end); 972 973InstallMethod(NaturalLeqBlockBijection, "for a bipartition and bipartition", 974IsIdenticalObj, [IsBipartition, IsBipartition], 975function(x, y) 976 local xblocks, yblocks, n, lookup, i; 977 978 if not IsBlockBijection(x) or not IsBlockBijection(y) then 979 ErrorNoReturn("Semigroups: NaturalLeqBlockBijection: usage,\n", 980 "the arguments must be block bijections,"); 981 elif NrBlocks(x) > NrBlocks(y) then 982 return false; 983 fi; 984 985 xblocks := IntRepOfBipartition(x); 986 yblocks := IntRepOfBipartition(y); 987 n := DegreeOfBipartition(x); 988 989 lookup := []; 990 for i in [1 .. n] do 991 if IsBound(lookup[yblocks[i]]) and lookup[yblocks[i]] <> xblocks[i] then 992 return false; 993 else 994 lookup[yblocks[i]] := xblocks[i]; 995 fi; 996 od; 997 for i in [n + 1 .. 2 * n] do 998 if lookup[yblocks[i]] <> xblocks[i] then 999 return false; 1000 fi; 1001 od; 1002 return true; 1003end); 1004 1005InstallMethod(NaturalLeqPartialPermBipartition, 1006"for a bipartition and bipartition", 1007IsIdenticalObj, [IsBipartition, IsBipartition], 1008function(x, y) 1009 local n, xblocks, yblocks, val, i; 1010 1011 if not IsPartialPermBipartition(x) or not IsPartialPermBipartition(y) then 1012 ErrorNoReturn("Semigroups: NaturalLeqPartialPermBipartition: usage,\n", 1013 "the arguments must be partial perm bipartitions,"); 1014 fi; 1015 1016 n := DegreeOfBipartition(x); 1017 1018 xblocks := IntRepOfBipartition(x); 1019 yblocks := IntRepOfBipartition(y); 1020 1021 for i in [n + 1 .. 2 * n] do 1022 val := xblocks[i]; 1023 if val <= n and val <> yblocks[i] then 1024 return false; 1025 fi; 1026 od; 1027 return true; 1028end); 1029 1030InstallMethod(IsUniformBlockBijection, "for a bipartition", 1031[IsBipartition], 1032function(x) 1033 local blocks, n, sizesleft, sizesright, i; 1034 1035 if not IsBlockBijection(x) then 1036 return false; 1037 fi; 1038 1039 blocks := IntRepOfBipartition(x); 1040 n := DegreeOfBipartition(x); 1041 sizesleft := [1 .. NrBlocks(x)] * 0; 1042 sizesright := [1 .. NrBlocks(x)] * 0; 1043 1044 for i in [1 .. n] do 1045 sizesleft[blocks[i]] := sizesleft[blocks[i]] + 1; 1046 od; 1047 for i in [n + 1 .. 2 * n] do 1048 sizesright[blocks[i]] := sizesright[blocks[i]] + 1; 1049 od; 1050 for i in [1 .. NrBlocks(x)] do 1051 if sizesright[i] <> sizesleft[i] then 1052 return false; 1053 fi; 1054 od; 1055 1056 return true; 1057end); 1058 1059InstallMethod(IndexPeriodOfSemigroupElement, "for a bipartition", 1060[IsBipartition], 1061function(x) 1062 return SEMIGROUPS.IndexPeriodByRank(x, RankOfBipartition); 1063end); 1064