1#############################################################################
2##
3##  HomalgRing.gi               MatricesForHomalg package    Mohamed Barakat
4##
5##  Copyright 2007-2009 Mohamed Barakat, RWTH Aachen
6##
7##  Implementation stuff for homalg rings.
8##
9#############################################################################
10
11####################################
12#
13# representations:
14#
15####################################
16
17##  <#GAPDoc Label="IsHomalgInternalRingRep">
18##  <ManSection>
19##    <Filt Type="Representation" Arg="R" Name="IsHomalgInternalRingRep"/>
20##    <Returns><C>true</C> or <C>false</C></Returns>
21##    <Description>
22##      The internal representation of &homalg; rings. <P/>
23##      (It is a representation of the &GAP; category <C>IsHomalgRing</C>.)
24##    </Description>
25##  </ManSection>
26##  <#/GAPDoc>
27##
28DeclareRepresentation( "IsHomalgInternalRingRep",
29        IsHomalgRing and IsHomalgRingOrFinitelyPresentedModuleRep,
30        [ "ring", "homalgTable" ] );
31
32##
33DeclareRepresentation( "IsContainerForWeakPointersOnIdentityMatricesRep",
34        IsContainerForWeakPointersRep,
35        [ "weak_pointers" ] );
36
37####################################
38#
39# families and types:
40#
41####################################
42
43# a new family:
44BindGlobal( "TheFamilyOfHomalgRingElements",
45        NewFamily( "TheFamilyOfHomalgRingElements" ) );
46
47# a new family:
48BindGlobal( "TheFamilyOfHomalgRings",
49        CollectionsFamily( TheFamilyOfHomalgRingElements ) );
50
51# a new type:
52BindGlobal( "TheTypeHomalgInternalRing",
53        NewType( TheFamilyOfHomalgRings,
54                IsHomalgInternalRingRep ) );
55
56# a new family:
57BindGlobal( "TheFamilyOfContainersForWeakPointersOfIdentityMatrices",
58        NewFamily( "TheFamilyOfContainersForWeakPointersOfIdentityMatrices" ) );
59
60# a new type:
61BindGlobal( "TheTypeContainerForWeakPointersOnIdentityMatrices",
62        NewType( TheFamilyOfContainersForWeakPointersOfIdentityMatrices,
63                IsContainerForWeakPointersOnIdentityMatricesRep ) );
64
65####################################
66#
67# global variables:
68#
69####################################
70
71##
72InstallValue( CommonHomalgTableForRings,
73        rec(
74            RingName :=
75              function( R )
76                local minimal_polynomial, var, brackets, r;
77
78                if IsBound( R!.MinimalPolynomialOfPrimitiveElement ) then
79                    minimal_polynomial := R!.MinimalPolynomialOfPrimitiveElement;
80                fi;
81
82                ## the Weyl algebra (relative version):
83                if HasRelativeIndeterminateDerivationsOfRingOfDerivations( R ) then
84
85                    var := RelativeIndeterminateDerivationsOfRingOfDerivations( R );
86
87                    brackets := [ "<", ">" ];
88
89                ## the Weyl algebra:
90                elif HasIndeterminateDerivationsOfRingOfDerivations( R ) then
91
92                    var := IndeterminateDerivationsOfRingOfDerivations( R );
93
94                    brackets := [ "<", ">" ];
95
96                ## the exterior algebra (relative version):
97                elif HasRelativeIndeterminateAntiCommutingVariablesOfExteriorRing( R ) then
98
99                    var := RelativeIndeterminateAntiCommutingVariablesOfExteriorRing( R );
100
101                    brackets := [ "{", "}" ];
102
103                ## the exterior algebra:
104                elif HasIndeterminateAntiCommutingVariablesOfExteriorRing( R ) then
105
106                    var := IndeterminateAntiCommutingVariablesOfExteriorRing( R );
107
108                    brackets := [ "{", "}" ];
109
110                ## the (free) polynomial ring (relative version):
111                elif HasBaseRing( R ) and HasRelativeIndeterminatesOfPolynomialRing( R ) and
112                  not IsIdenticalObj( R, BaseRing( R ) ) then
113
114                    var := RelativeIndeterminatesOfPolynomialRing( R );
115
116                    brackets := [ "[", "]" ];
117
118                ## the (free) polynomial ring:
119                elif HasIndeterminatesOfPolynomialRing( R ) then
120
121                    var := IndeterminatesOfPolynomialRing( R );
122
123                    brackets := [ "[", "]" ];
124
125                elif HasRationalParameters( R ) then
126
127                    var := RationalParameters( R );
128
129                    if IsBound( minimal_polynomial ) then
130                        brackets := [ "[", "]" ];
131                    else
132                        brackets := [ "(", ")" ];
133                    fi;
134
135                fi;
136
137                if not IsBound( var ) then
138                    return fail;
139                fi;
140
141                var := JoinStringsWithSeparator( List( var, String ) );
142
143                var := Concatenation( brackets[1], var, brackets[2] );
144
145                if HasBaseRing( R ) and HasCoefficientsRing( R ) and
146                   not IsIdenticalObj( BaseRing( R ), CoefficientsRing( R ) ) then
147                    r := RingName( BaseRing( R ) );
148                elif HasCoefficientsRing( R ) then
149                    r := CoefficientsRing( R );
150                    if IsBound( r!.MinimalPolynomialOfPrimitiveElement ) and IsSubset( RingName( r ), "/" ) then
151                        r := Concatenation( "(", RingName( r ), ")" );
152                    else
153                        r := RingName( r );
154                    fi;
155                else
156                    r := "(some ring)";
157                fi;
158
159                r := Concatenation( r, var );
160
161                if IsBound( minimal_polynomial ) then
162                    r := Concatenation( r, "/(", minimal_polynomial, ")" );
163                fi;
164
165                return String( r );
166
167            end,
168
169         )
170);
171
172####################################
173#
174# methods for attributes:
175#
176####################################
177
178##
179InstallMethod( Zero,
180        "for homalg rings",
181        [ IsHomalgInternalRingRep ], 10001,
182
183  function( R )
184
185    return Zero( R!.ring );
186
187end );
188
189##
190InstallMethod( Zero,
191        "for homalg rings",
192        [ IsHomalgInternalRingRep ], 10001,
193
194  function( R )
195    local RP;
196
197    RP := homalgTable( R );
198
199    if IsBound( RP!.Zero ) then
200        return RP!.Zero;
201    fi;
202
203    TryNextMethod( );
204
205end );
206
207##
208InstallMethod( One,
209        "for homalg rings",
210        [ IsHomalgInternalRingRep ], 1001,
211
212  function( R )
213
214    return One( R!.ring );
215
216end );
217
218##
219InstallMethod( One,
220        "for homalg rings",
221        [ IsHomalgInternalRingRep ], 1001,
222
223  function( R )
224    local RP;
225
226    RP := homalgTable( R );
227
228    if IsBound( RP!.One ) then
229        return RP!.One;
230    fi;
231
232    TryNextMethod( );
233
234end );
235
236##
237InstallMethod( MinusOne,
238        "for homalg rings",
239        [ IsHomalgInternalRingRep ],
240
241  function( R )
242
243    return -One( R );
244
245end );
246
247##
248InstallMethod( MinusOne,
249        "for homalg rings",
250        [ IsHomalgInternalRingRep ],
251
252  function( R )
253    local RP;
254
255    RP := homalgTable( R );
256
257    if IsBound( RP!.MinusOne ) then
258        return RP!.MinusOne;
259    fi;
260
261    TryNextMethod( );
262
263end );
264
265##
266InstallMethod( ZeroMutable,
267        "for homalg ring elements",
268        [ IsHomalgRingElement ],
269
270  function( r )
271
272    return Zero( HomalgRing( r ) );
273
274end );
275
276##
277InstallMethod( OneMutable,
278        "for homalg ring elements",
279        [ IsHomalgRingElement ],
280
281  function( r )
282
283    return One( HomalgRing( r ) );
284
285end );
286
287##
288InstallMethod( Inverse,
289        "for homalg ring elements",
290        [ IsHomalgRingElement ],
291
292  function( r )
293
294    return One( r ) / r;
295
296end );
297
298##
299InstallMethod( MinusOneMutable,
300        "for homalg ring elements",
301        [ IsHomalgRingElement ],
302
303  function( r )
304
305    return MinusOne( HomalgRing( r ) );
306
307end );
308
309##
310InstallMethod( Characteristic,
311        "for homalg ring elements",
312        [ IsHomalgRingElement ],
313
314  function( r )
315
316    return Characteristic( HomalgRing( r ) );
317
318end );
319
320## for the computeralgebra course
321InstallOtherMethod( IndeterminateOfLaurentPolynomial,
322        "for homalg ring elements",
323        [ IsHomalgRingElement ],
324
325  function( r )
326    local R, indets;
327
328    R := HomalgRing( r );
329
330    indets := IndeterminatesOfPolynomialRing( R );
331
332    return indets[Length( indets )];
333
334end );
335
336## for the computeralgebra course
337InstallOtherMethod( CoefficientsRing,
338        "for ring elements",
339        [ IsRingElement ],
340
341  function( r )
342    local R;
343
344    if IsHomalgRingElement( r ) then
345        R := HomalgRing( r );
346    else
347        R := DefaultRing( r );
348    fi;
349
350    return CoefficientsRing( R );
351
352end );
353
354##
355InstallMethod( AssociatedPolynomialRing,
356        "for homalg fields",
357        [ IsHomalgRing and IsFieldForHomalg ],
358
359  function( R )
360    local a, r;
361
362    if not HasRationalParameters( R ) then
363        Error( "the field has no rational parameters" );
364    elif not HasCoefficientsRing( R ) then
365        Error( "the field has no subfield of coefficients" );
366    fi;
367
368    r := CoefficientsRing( R );
369
370    a := RationalParameters( R );
371
372    return r * List( a, String );
373
374end );
375
376##
377InstallMethod( PolynomialRingWithProductOrdering,
378        "for homalg rings",
379        [ IsHomalgRing ],
380
381  function( R )
382    local B, C;
383
384    if not IsIdenticalObj( BaseRing( R ), CoefficientsRing( R ) ) then
385        TryNextMethod( );
386    fi;
387
388    return R;
389
390end );
391
392##
393InstallMethod( BaseRing,
394        "for homalg rings",
395        [ IsHomalgRing and HasCoefficientsRing ],
396
397  CoefficientsRing );
398
399####################################
400#
401# methods for operations:
402#
403####################################
404
405##
406InstallMethod( HomalgRing,
407        "for homalg rings",
408        [ IsHomalgRing ],
409
410  function( R )
411
412    return R;
413
414end );
415
416##
417InstallMethod( \=,
418        "for two homalg rings",
419        [ IsHomalgRing, IsHomalgRing ], 10001,
420
421  IsIdenticalObj );
422
423##
424InstallMethod( HomalgRing,
425        "for homalg ring elements",
426        [ IsHomalgRingElement ],
427
428  function( r )
429
430    return r!.ring;
431
432end );
433
434##
435InstallMethod( LT,
436        "for homalg ring elements",
437        [ IsHomalgRingElement, IsHomalgRingElement ],
438
439  function( a, b )
440
441    return LT( String( a ), String( b ) );
442
443end );
444
445##
446InstallMethod( INV,
447        "for homalg ring elements",
448        [ IsHomalgRingElement ],
449
450  function( r )
451
452    return Inverse( r );
453
454end );
455
456##
457InstallMethod( \*,
458        "for homalg ring elements",
459        [ IS_RAT, IsHomalgRingElement ],
460
461  function( a, b )
462
463    if IS_INT( a ) then
464        TryNextMethod( );
465    fi;
466
467    return ( NUMERATOR_RAT( a ) * b ) / ( DENOMINATOR_RAT( a ) * One( b ) );
468
469end );
470
471##
472InstallMethod( \*,
473        "for homalg ring elements",
474        [ IsHomalgRingElement, IS_RAT ],
475
476  function( a, b )
477
478    if IS_INT( b ) then
479        TryNextMethod( );
480    fi;
481
482    return ( NUMERATOR_RAT( b ) * a ) / ( DENOMINATOR_RAT( b ) * One( a ) );
483
484end );
485
486##
487InstallMethod( \+,
488        "for homalg ring elements",
489        [ IS_RAT, IsHomalgRingElement ],
490
491  function( a, b )
492
493    return a * One( b ) + b;
494
495end );
496
497##
498InstallMethod( \+,
499        "for homalg ring elements",
500        [ IsHomalgRingElement, IS_RAT ],
501
502  function( a, b )
503
504    return a + b * One( a );
505
506end );
507
508##
509InstallMethod( Indeterminates,
510        "for homalg rings",
511        [ IsHomalgRing and HasIndeterminatesOfPolynomialRing ],
512
513  function( R )
514
515    return IndeterminatesOfPolynomialRing( R );
516
517end );
518
519##
520InstallMethod( Indeterminates,
521        "for homalg rings",
522        [ IsHomalgRing and HasIndeterminatesOfExteriorRing ],
523
524  function( R )
525
526    return IndeterminatesOfExteriorRing( R );
527
528end );
529
530##
531InstallMethod( Indeterminates,
532        "for homalg rings",
533        [ IsHomalgRing and HasIndeterminateCoordinatesOfRingOfDerivations ],
534
535  function( R )
536
537    return
538      Concatenation(
539              IndeterminateCoordinatesOfRingOfDerivations( R ),
540              IndeterminateDerivationsOfRingOfDerivations( R )
541              );
542
543end );
544
545##
546InstallMethod( Indeterminates,
547        "for homalg fields",
548        [ IsHomalgRing and IsFieldForHomalg ],
549
550  function( R )
551
552    return [ ];
553
554end );
555
556##
557InstallMethod( Indeterminates,
558        "for homalg ring of integers",
559        [ IsHomalgRing and IsIntegersForHomalg ],
560
561  function( R )
562
563    return [ ];
564
565end );
566
567## Fallback method
568InstallMethod( RelativeIndeterminatesOfPolynomialRing,
569        "for homalg rings",
570        [ IsHomalgRing and HasCoefficientsRing ],
571
572  IndeterminatesOfPolynomialRing );
573
574##
575InstallMethod( AssignGeneratorVariables,
576        "for homalg rings",
577        [ IsHomalgRing ],
578
579  function( R )
580    local indets;
581
582    indets := Indeterminates( R );
583
584    DoAssignGenVars( indets );
585
586    return;
587
588end );
589
590##
591InstallMethod( ExportIndeterminates,
592        "for homalg rings",
593        [ IsHomalgRing ],
594
595  function( R )
596    local indets, x_name, x;
597
598    indets := Indeterminates( R );
599
600    for x in indets do
601        x_name := String( x );
602        if IsBoundGlobal( x_name ) then
603            if not IsHomalgRingElement( ValueGlobal( x_name ) ) then
604                Error( "the name ", x_name, " is not bound to a homalg ring element\n" );
605            elif IsReadOnlyGlobal( x_name ) then
606                MakeReadWriteGlobal( x_name );
607            fi;
608            UnbindGlobal( x_name );
609        fi;
610        BindGlobal( x_name, x );
611    od;
612
613    return indets;
614
615end );
616
617##
618InstallMethod( ExportRationalParameters,
619        "for homalg rings",
620        [ IsHomalgRing and HasRationalParameters ],
621
622  function( R )
623    local params, x_name, x;
624
625    params := RationalParameters( R );
626
627    for x in params do
628        x_name := String( x );
629        if IsBoundGlobal( x_name ) then
630            if not IsHomalgRingElement( ValueGlobal( x_name ) ) then
631                Error( "the name ", x_name, " is not bound to a homalg ring element\n" );
632            elif IsReadOnlyGlobal( x_name ) then
633                MakeReadWriteGlobal( x_name );
634            fi;
635            UnbindGlobal( x_name );
636        fi;
637        BindGlobal( x_name, x );
638    od;
639
640    return params;
641
642end );
643
644##
645InstallMethod( ExportVariables,
646        "for homalg rings",
647        [ IsHomalgRing ],
648
649  function( R )
650
651    return ExportIndeterminates( R );
652
653end );
654
655##
656InstallMethod( ExportVariables,
657        "for homalg rings",
658        [ IsHomalgRing and HasRationalParameters ],
659
660  function( R )
661
662    return Concatenation(
663                   ExportIndeterminates( R ),
664                   ExportRationalParameters( R ) );
665
666end );
667
668##
669InstallMethod( Indeterminate,
670        "for homalg rings",
671        [ IsHomalgRing, IsPosInt ],
672
673  function( R, i )
674
675    return Indeterminates( R )[i];
676
677end );
678
679##
680InstallMethod( ProductOfIndeterminates,
681        "for homalg rings",
682        [ IsHomalgRing ],
683
684  function( R )
685
686    return Product( Indeterminates( R ) );
687
688end );
689
690##
691InstallMethod( ProductOfIndeterminatesOverBaseRing,
692        "for homalg rings",
693        [ IsHomalgRing and HasIndeterminatesOfPolynomialRing ],
694
695  function( R )
696
697    return Product( IndeterminatesOfPolynomialRing( R ) );
698
699end );
700
701##
702InstallMethod( ProductOfIndeterminatesOverBaseRing,
703        "for homalg rings",
704        [ IsHomalgRing and HasRelativeIndeterminatesOfPolynomialRing ], 100, ## otherwise the above method is triggered :(
705
706  function( R )
707
708    return Product( RelativeIndeterminatesOfPolynomialRing( R ) );
709
710end );
711
712## provided to avoid branching in the code and always returns fail
713InstallMethod( PositionOfTheDefaultPresentation,
714        "for ring elements",
715        [ IsRingElement ],
716
717  function( r )
718
719    return fail;
720
721end );
722
723##
724InstallMethod( \=,
725        "for two homalg ring elements",
726        [ IsHomalgRingElement, IsHomalgRingElement ],
727
728  function( r1, r2 )
729
730    if IsIdenticalObj( HomalgRing( r1 ), HomalgRing( r2 ) ) then
731        return IsZero( r1 - r2 );
732    fi;
733
734    return false;
735
736end );
737
738##
739InstallMethod( \=,
740        "for a rational and a homalg ring element",
741        [ IS_RAT, IsHomalgRingElement ],
742
743  function( r1, r2 )
744
745    return r1 / HomalgRing( r2 ) = r2;
746
747end );
748
749##
750InstallMethod( \=,
751        "for a homalg ring element and a rational",
752        [ IsHomalgRingElement, IS_RAT ],
753
754  function( r1, r2 )
755
756    return r1 = r2 / HomalgRing( r1 );
757
758end );
759
760##
761InstallMethod( StandardBasisRowVectors,
762        "for homalg rings",
763        [ IsInt, IsHomalgRing ],
764
765  function( n, R )
766    local id;
767
768    id := HomalgIdentityMatrix( n, R );
769
770    return List( [ 1 .. n ], r -> CertainRows( id, [ r ] ) );
771
772end );
773
774##
775InstallMethod( StandardBasisColumnVectors,
776        "for homalg rings",
777        [ IsInt, IsHomalgRing ],
778
779  function( n, R )
780    local id;
781
782    id := HomalgIdentityMatrix( n, R );
783
784    return List( [ 1 .. n ], c -> CertainColumns( id, [ c ] ) );
785
786end );
787
788##
789InstallMethod( RingName,
790        "for homalg rings",
791        [ IsHomalgRing ],
792
793  function( R )
794    local RP, var, r, c;
795
796    if HasName( R ) then
797        return Name( R );
798    fi;
799
800    ## ask the ring table
801    RP := homalgTable( R );
802
803    if IsBound(RP!.RingName) then
804
805        if IsFunction( RP!.RingName ) then
806            r := RP!.RingName( R );
807        else
808            r := RP!.RingName;
809        fi;
810
811        if r <> fail then
812            return r;
813        fi;
814
815    fi;
816
817    ## residue class rings/fields of the integers
818    if HasIsResidueClassRingOfTheIntegers( R ) and
819       IsResidueClassRingOfTheIntegers( R ) and
820       HasCharacteristic( R ) then
821
822        c := Characteristic( R );
823
824        if c = 0 then
825            return "Z";
826        elif IsPrime( c ) then
827            if HasDegreeOverPrimeField( R ) and DegreeOverPrimeField( R ) > 1 then
828                r := [ "GF(", String( c ), "^", String( DegreeOverPrimeField( R ) ), ")" ];
829            else
830                r := [ "GF(", String( c ), ")" ];
831            fi;
832        else
833            r := [ "Z/", String( c ), "Z" ];
834        fi;
835
836        return String( Concatenation( r ) );
837
838    fi;
839
840    ## the rationals
841    if HasIsRationalsForHomalg( R ) and IsRationalsForHomalg( R ) then
842        return "Q";
843    fi;
844
845    return "(homalg ring)";
846
847end );
848
849##
850InstallMethod( homalgRingStatistics,
851        "for homalg rings",
852        [ IsHomalgRing ],
853
854  function( R )
855
856    return R!.statistics;
857
858end );
859
860##
861InstallMethod( IncreaseRingStatistics,
862        "for homalg rings",
863        [ IsHomalgRing, IsString ],
864
865  function( R, s )
866
867    R!.statistics.(s) := R!.statistics.(s) + 1;
868
869end );
870
871##
872InstallMethod( DecreaseRingStatistics,
873        "for homalg rings",
874        [ IsHomalgRing, IsString ],
875
876  function( R, s )
877
878    R!.statistics.(s) := R!.statistics.(s) - 1;
879
880end );
881
882##
883InstallOtherMethod( AsList,
884        "for homalg internal rings",
885        [ IsHomalgInternalRingRep ],
886
887  function( r )
888
889    return AsList( r!.ring );
890
891end );
892
893##
894InstallMethod( homalgSetName,
895        "for homalg ring elements",
896        [ IsHomalgRingElement, IsString ],
897
898  SetName );
899
900##
901InstallMethod( IrreducibleFactors,
902        "for ring elements",
903        [ IsRingElement ],
904
905  PrimeDivisors );
906
907##
908InstallMethod( IrreducibleFactors,
909        "for homalg ring elements",
910        [ IsHomalgRingElement ],
911
912  function( r )
913    local R, factors;
914
915    R := HomalgRing( r );
916
917    if IsHomalgInternalRingRep( R ) then
918        if not IsBound( r!.IrreducibleFactors ) then
919            r!.IrreducibleFactors := PrimeDivisors( EvalString( String( r ) ) );
920        fi;
921    fi;
922
923    factors := RadicalDecompositionOp( HomalgMatrix( [ r ], 1, 1, R ) );
924
925    r!.Factors := List( factors, a -> a[ 1, 1 ] );
926
927    return r!.Factors;
928
929end );
930
931##
932InstallMethod( Factors,
933        "for homalg ring elements",
934        [ IsHomalgRingElement ],
935
936  function( r )
937    local R, factors, primary, prime, one, divide;
938
939    R := HomalgRing( r );
940
941    if IsHomalgInternalRingRep( R ) then
942        if not IsBound( r!.Factors ) then
943            r!.Factors := Factors( EvalString( String( r ) ) );
944        fi;
945    fi;
946
947    factors := PrimaryDecompositionOp( HomalgMatrix( [ r ], 1, 1, R ) );
948
949    primary := List( factors, a -> a[1][ 1, 1 ] );
950    prime := List( factors, a -> a[2][ 1, 1 ] );
951
952    one := One( R );
953
954    divide :=
955      function( q, p )
956        local list;
957
958        list := [ ];
959
960        repeat
961            q := q / p;
962            Add( list, p );
963        until IsZero( DecideZero( one, q ) );
964
965        return list;
966
967    end;
968
969    factors := List( [ 1 .. Length( factors ) ], i -> divide( primary[i], prime[i] ) );
970
971    factors := Concatenation( factors );
972
973    factors[1] := ( r / Product( factors ) ) * factors[1];
974
975    r!.Factors := factors;
976
977    return r!.Factors;
978
979end );
980
981##
982InstallMethod( Roots,
983        "for homalg ring elements",
984        [ IsHomalgRingElement ],
985
986  function( r )
987    local R, roots;
988
989    R := HomalgRing( r );
990
991    if not IsHomalgInternalRingRep( R ) then
992        TryNextMethod( );
993    fi;
994
995    if not IsBound( r!.Roots ) then
996        roots := RootsOfUPol( EvalString( String( r ) ) );
997        Sort( roots );
998        r!.Roots := roots;
999    fi;
1000
1001    return r!.Roots;
1002
1003end );
1004
1005##
1006InstallMethod( DecideZero,
1007        "for homalg ring elements",
1008        [ IsHomalgRingElement ],
1009
1010  function( r )
1011
1012    IsZero( r );
1013
1014    return r;
1015
1016end );
1017
1018##
1019InstallMethod( SetRingProperties,
1020        "for homalg rings",
1021        [ IsHomalgRing and IsFreePolynomialRing, IsHomalgRing, IsList ],
1022
1023  function( S, R, var )
1024    local param, paramS, d;
1025
1026    d := Length( var );
1027
1028    if d > 0 then
1029        SetIsFinite( S, false );
1030    fi;
1031
1032    SetCoefficientsRing( S, R );
1033
1034    if HasRationalParameters( R ) then
1035        param := RationalParameters( R );
1036        paramS := List( param, a -> a / S );
1037        Perform( [ 1 .. Length( param ) ], function( i ) SetName( paramS[i], Name( param[i] ) ); end );
1038        SetRationalParameters( S, paramS );
1039    fi;
1040
1041    if HasCharacteristic( R ) then
1042        SetCharacteristic( S, Characteristic( R ) );
1043    fi;
1044
1045    SetIsCommutative( S, true );
1046
1047    SetIndeterminatesOfPolynomialRing( S, var );
1048
1049    if HasContainsAField( R ) and ContainsAField( R ) then
1050        SetContainsAField( S, true );
1051    fi;
1052
1053    if d > 0 then
1054        SetIsLeftArtinian( S, false );
1055        SetIsRightArtinian( S, false );
1056    fi;
1057
1058    if HasGlobalDimension( R ) then
1059        SetGlobalDimension( S, d + GlobalDimension( R ) );
1060    fi;
1061
1062    if HasKrullDimension( R ) then
1063        SetKrullDimension( S, d + KrullDimension( R ) );
1064    fi;
1065
1066    SetGeneralLinearRank( S, 1 );	## Quillen-Suslin Theorem (see [McCRob, 11.5.5]
1067
1068    if d = 1 then			## [McCRob, 11.5.7]
1069        SetElementaryRank( S, 1 );
1070    elif d > 2 then
1071        SetElementaryRank( S, 2 );
1072    fi;
1073
1074    SetIsIntegralDomain( S, true );
1075
1076    SetBasisAlgorithmRespectsPrincipalIdeals( S, true );
1077
1078end );
1079
1080##
1081InstallMethod( SetRingProperties,
1082        "for homalg rings",
1083        [ IsHomalgRing and IsWeylRing, IsHomalgRing and IsFreePolynomialRing, IsList ],
1084
1085  function( S, R, der )
1086    local r, b, param, paramS, var, d;
1087
1088    r := CoefficientsRing( R );
1089
1090    if HasBaseRing( R ) then
1091        b := BaseRing( R );
1092    else
1093        b := r;
1094    fi;
1095
1096    var := IndeterminatesOfPolynomialRing( R );
1097    var := List( var, a -> a / S );
1098
1099    d := Length( var );
1100
1101    if d > 0 then
1102        SetIsFinite( S, false );
1103    fi;
1104
1105    SetCoefficientsRing( S, r );
1106
1107    if HasRationalParameters( r ) then
1108        param := RationalParameters( r );
1109        paramS := List( param, a -> a / S );
1110        Perform( [ 1 .. Length( param ) ], function( i ) SetName( paramS[i], Name( param[i] ) ); end );
1111        SetRationalParameters( S, paramS );
1112    fi;
1113
1114    SetCharacteristic( S, Characteristic( R ) );
1115
1116    SetIsCommutative( S, der = [ ] );
1117
1118    SetCenter( S, Center( b ) );
1119
1120    SetIndeterminateCoordinatesOfRingOfDerivations( S, var );
1121
1122    if HasRelativeIndeterminatesOfPolynomialRing( R ) then
1123        SetRelativeIndeterminateCoordinatesOfRingOfDerivations(
1124                S, RelativeIndeterminatesOfPolynomialRing( R ) );
1125    fi;
1126
1127    SetIndeterminateDerivationsOfRingOfDerivations( S, der );
1128
1129    if d > 0 then
1130        SetIsLeftArtinian( S, false );
1131        SetIsRightArtinian( S, false );
1132    fi;
1133
1134    SetIsLeftNoetherian( S, true );
1135    SetIsRightNoetherian( S, true );
1136
1137    if HasGlobalDimension( r ) then
1138        SetGlobalDimension( S, d + GlobalDimension( r ) );
1139    fi;
1140
1141    if HasIsFieldForHomalg( b ) and IsFieldForHomalg( b ) and Characteristic( S ) = 0 then
1142        SetGeneralLinearRank( S, 2 );	## [Stafford78], [McCRob, 11.2.15(i)]
1143        SetIsSimpleRing( S, true );	## [Coutinho, Thm 2.2.1]
1144    fi;
1145
1146    if HasIsIntegralDomain( r ) and IsIntegralDomain( r ) then
1147        SetIsIntegralDomain( S, true );
1148    fi;
1149
1150    if d > 0 then
1151        SetIsLeftPrincipalIdealRing( S, false );
1152        SetIsRightPrincipalIdealRing( S, false );
1153        SetIsPrincipalIdealRing( S, false );
1154    fi;
1155
1156    SetBasisAlgorithmRespectsPrincipalIdeals( S, true );
1157
1158    SetAreUnitsCentral( S, true );
1159
1160end );
1161
1162##
1163InstallMethod( SetRingProperties,
1164        "for homalg rings",
1165        [ IsHomalgRing and IsLocalizedWeylRing, IsString ],
1166
1167  function( S, _var )
1168    local var, d;
1169
1170    var := SplitString( _var, ",", "[]" );
1171    var := List( var, a -> a / S );
1172
1173    SetIndeterminateCoordinatesOfRingOfDerivations( S, var );
1174
1175    d := Length( var );
1176
1177    ## SetCoefficientsRing( S, r );
1178
1179    SetCharacteristic( S, 0 );
1180
1181    SetIsCommutative( S, false );
1182
1183    ## SetCenter( S, r );
1184
1185    SetIndeterminateCoordinatesOfRingOfDerivations( S, var );
1186
1187    ## SetIndeterminateDerivationsOfRingOfDerivations( S, der );
1188
1189    if d > 0 then
1190        SetIsLeftArtinian( S, false );
1191        SetIsRightArtinian( S, false );
1192    fi;
1193
1194    SetIsLeftNoetherian( S, true );
1195    SetIsRightNoetherian( S, true );
1196
1197    SetGlobalDimension( S, d + 0 );	## Janet only knows Q as the coefficient ring
1198
1199    ## SetGeneralLinearRank( S, 2 );	## [Stafford78], [McCRob, 11.2.15(i)]
1200    SetIsSimpleRing( S, true );		## [Coutinho, Thm 2.2.1]
1201
1202    if d > 0 then
1203        SetIsPrincipalIdealRing( S, false );
1204    fi;
1205
1206    if d = 1 then
1207        SetIsLeftPrincipalIdealRing( S, true );
1208        SetIsRightPrincipalIdealRing( S, true );
1209    elif d > 0 then
1210        SetIsLeftPrincipalIdealRing( S, false );
1211        SetIsRightPrincipalIdealRing( S, false );
1212    fi;
1213
1214    SetIsIntegralDomain( S, true );
1215
1216    SetBasisAlgorithmRespectsPrincipalIdeals( S, true );
1217
1218    SetAreUnitsCentral( S, false );
1219
1220end );
1221
1222##
1223InstallMethod( SetRingProperties,
1224        "for homalg rings",
1225        [ IsHomalgRing and IsExteriorRing, IsHomalgRing and IsFreePolynomialRing, IsList ],
1226
1227  function( A, S, anti )
1228    local r, d, param, paramA, comm, T;
1229
1230    r := CoefficientsRing( S );
1231
1232    d := Length( anti );
1233
1234    SetCoefficientsRing( A, r );
1235
1236    if HasRationalParameters( r ) then
1237        param := RationalParameters( r );
1238        paramA := List( param, a -> a / A );
1239        Perform( [ 1 .. Length( param ) ], function( i ) SetName( paramA[i], Name( param[i] ) ); end );
1240        SetRationalParameters( A, paramA );
1241    fi;
1242
1243    SetCharacteristic( A, Characteristic( S ) );
1244
1245    if d <= 1 or Characteristic( A ) = 2 then
1246
1247        ## the Center is then automatically set to S
1248        SetIsCommutative( A, true );
1249
1250    else
1251
1252        ## the center is the even part, which is
1253        ## bigger than the coefficients ring r
1254        SetIsCommutative( A, false );
1255
1256    fi;
1257
1258    SetIsSuperCommutative( A, true );
1259
1260    SetIsIntegralDomain( A, d = 0 );
1261
1262    comm := [ ];
1263
1264    if HasBaseRing( S ) then
1265        T := BaseRing( S );
1266        if HasIndeterminatesOfPolynomialRing( T ) then
1267            comm := IndeterminatesOfPolynomialRing( T );
1268        fi;
1269    fi;
1270
1271    SetIndeterminateAntiCommutingVariablesOfExteriorRing( A, anti );
1272
1273    SetIndeterminatesOfExteriorRing( A, Concatenation( comm, anti ) );
1274
1275    SetBasisAlgorithmRespectsPrincipalIdeals( A, true );
1276
1277    SetAreUnitsCentral( S, true );
1278
1279end );
1280
1281##
1282InstallMethod( SetRingProperties,
1283        "for homalg rings",
1284        [ IsHomalgRing and IsPrincipalIdealRing and IsCommutative, IsInt ],
1285
1286  function( R, c )
1287    local RP, powers;
1288
1289    SetCharacteristic( R, c );
1290
1291    if HasIsFieldForHomalg( R ) and IsFieldForHomalg( R ) then
1292        TryNextMethod( );
1293    elif HasIsResidueClassRingOfTheIntegers( R ) and
1294      IsResidueClassRingOfTheIntegers( R ) then
1295        TryNextMethod( );
1296    fi;
1297
1298    if c = 0 then
1299        SetContainsAField( R, false );
1300        SetIsIntegralDomain( R, true );
1301        SetIsArtinian( R, false );
1302        SetKrullDimension( R, 1 );	## FIXME: it is not set automatically although an immediate method is installed
1303    elif not IsPrime( c ) then
1304        SetIsSemiLocalRing( R, true );
1305        SetIsIntegralDomain( R, false );
1306        powers := List( Collected( FactorsInt( c ) ), a -> a[2] );
1307        if Set( powers ) = [ 1 ] then
1308            SetIsSemiSimpleRing( R, true );
1309        else
1310            SetIsRegular( R, false );
1311            if Length( powers ) = 1 then
1312                SetIsLocal( R, true );
1313            fi;
1314        fi;
1315        SetKrullDimension( R, 0 );
1316    fi;
1317
1318    RP := homalgTable( R );
1319
1320    if HasIsIntegralDomain( R ) and IsIntegralDomain( R ) then
1321        if IsBound( RP!.RowRankOfMatrixOverDomain ) then
1322            RP!.RowRankOfMatrix := RP!.RowRankOfMatrixOverDomain;
1323        fi;
1324
1325        if IsBound( RP!.ColumnRankOfMatrixOverDomain ) then
1326            RP!.ColumnRankOfMatrix := RP!.ColumnRankOfMatrixOverDomain;
1327        fi;
1328    fi;
1329
1330    SetBasisAlgorithmRespectsPrincipalIdeals( R, true );
1331
1332end );
1333
1334##
1335InstallMethod( SetRingProperties,
1336        "for homalg rings",
1337        [ IsHomalgRing and IsResidueClassRingOfTheIntegers, IsInt ],
1338
1339  function( R, c )
1340    local RP, powers;
1341
1342    SetCharacteristic( R, c );
1343
1344    SetIsRationalsForHomalg( R, false );
1345
1346    if c = 0 then
1347        SetIsIntegersForHomalg( R, true );
1348        SetContainsAField( R, false );
1349        SetIsArtinian( R, false );
1350        SetKrullDimension( R, 1 );	## FIXME: it is not set automatically although an immediate method is installed
1351    elif IsPrime( c ) then
1352        SetIsFieldForHomalg( R, true );
1353        SetRingProperties( R, c );
1354    else
1355        SetIsSemiLocalRing( R, true );
1356        SetIsIntegralDomain( R, false );
1357        powers := List( Collected( FactorsInt( c ) ), a -> a[2] );
1358        if Set( powers ) = [ 1 ] then
1359            SetIsSemiSimpleRing( R, true );
1360        else
1361            SetIsRegular( R, false );
1362            if Length( powers ) = 1 then
1363                SetIsLocal( R, true );
1364            fi;
1365        fi;
1366        SetKrullDimension( R, 0 );
1367    fi;
1368
1369    RP := homalgTable( R );
1370
1371    if HasIsIntegralDomain( R ) and IsIntegralDomain( R ) then
1372        if IsBound( RP!.RowRankOfMatrixOverDomain ) then
1373            RP!.RowRankOfMatrix := RP!.RowRankOfMatrixOverDomain;
1374        fi;
1375
1376        if IsBound( RP!.ColumnRankOfMatrixOverDomain ) then
1377            RP!.ColumnRankOfMatrix := RP!.ColumnRankOfMatrixOverDomain;
1378        fi;
1379    fi;
1380
1381    SetBasisAlgorithmRespectsPrincipalIdeals( R, true );
1382
1383end );
1384
1385##
1386InstallMethod( SetRingProperties,
1387        "for homalg rings",
1388        [ IsHomalgRing and IsFieldForHomalg, IsInt ],
1389
1390  function( R, c )
1391    local RP;
1392
1393    SetCharacteristic( R, c );
1394
1395    if HasRationalParameters( R ) and Length( RationalParameters( R ) ) > 0 then
1396        SetIsRationalsForHomalg( R, false );
1397        SetIsResidueClassRingOfTheIntegers( R, false );
1398    else
1399        SetDegreeOverPrimeField( R, 1 );
1400    fi;
1401
1402    RP := homalgTable( R );
1403
1404    if IsBound( RP!.RowRankOfMatrixOverDomain ) then
1405        RP!.RowRankOfMatrix := RP!.RowRankOfMatrixOverDomain;
1406    fi;
1407
1408    if IsBound( RP!.ColumnRankOfMatrixOverDomain ) then
1409        RP!.ColumnRankOfMatrix := RP!.ColumnRankOfMatrixOverDomain;
1410    fi;
1411
1412    SetFilterObj( R, IsField );
1413    SetLeftActingDomain( R, R );
1414
1415    SetBasisAlgorithmRespectsPrincipalIdeals( R, true );
1416
1417end );
1418
1419##
1420InstallMethod( SetRingProperties,
1421        "for homalg rings",
1422        [ IsHomalgRing and IsFieldForHomalg, IsInt, IsInt ],
1423
1424  function( R, c, d )
1425    local RP;
1426
1427    SetCharacteristic( R, c );
1428    SetDegreeOverPrimeField( R, d );
1429
1430    if HasRationalParameters( R ) and Length( RationalParameters( R ) ) > 0 then
1431        SetIsRationalsForHomalg( R, false );
1432        SetIsResidueClassRingOfTheIntegers( R, false );
1433    fi;
1434
1435    RP := homalgTable( R );
1436
1437    if IsBound( RP!.RowRankOfMatrixOverDomain ) then
1438        RP!.RowRankOfMatrix := RP!.RowRankOfMatrixOverDomain;
1439    fi;
1440
1441    if IsBound( RP!.ColumnRankOfMatrixOverDomain ) then
1442        RP!.ColumnRankOfMatrix := RP!.ColumnRankOfMatrixOverDomain;
1443    fi;
1444
1445    SetFilterObj( R, IsField );
1446    SetLeftActingDomain( R, R );
1447
1448    SetBasisAlgorithmRespectsPrincipalIdeals( R, true );
1449
1450end );
1451
1452##
1453InstallMethod( UnusedVariableName,
1454        "for a homalg ring and a string",
1455        [ IsHomalgRing, IsString ],
1456
1457  function( R, t )
1458    local var;
1459
1460    var := [ ];
1461
1462    if HasRationalParameters( R ) then
1463        Append( var, List( RationalParameters( R ), Name ) );
1464    fi;
1465
1466    if HasIndeterminatesOfPolynomialRing( R ) then
1467        Append( var, List( IndeterminatesOfPolynomialRing( R ), Name ) );
1468    fi;
1469
1470    while true do
1471
1472        if not t in var then
1473            return t;
1474        fi;
1475
1476        t := Concatenation( t, "_" );
1477    od;
1478
1479end );
1480
1481##
1482InstallMethod( EuclideanQuotient,
1483        "for a homalg ring and two homalg ring elements",
1484        [ IsHomalgInternalRingRep and IsPrincipalIdealRing and IsCommutative, IsRingElement, IsRingElement ],
1485
1486  function( R, a, b )
1487
1488    return EuclideanQuotient( R!.ring, a, b );
1489
1490end );
1491
1492##
1493InstallMethod( EuclideanRemainder,
1494        "for a homalg ring and two homalg ring elements",
1495        [ IsHomalgInternalRingRep and IsPrincipalIdealRing and IsCommutative, IsRingElement, IsRingElement ],
1496
1497  function( R, a, b )
1498
1499    return EuclideanRemainder( R!.ring, a, b );
1500
1501end );
1502
1503##
1504InstallMethod( QuotientRemainder,
1505        "for a homalg ring and two homalg ring elements",
1506        [ IsHomalgInternalRingRep and IsPrincipalIdealRing and IsCommutative, IsRingElement, IsRingElement ],
1507
1508  function( R, a, b )
1509
1510    return QuotientRemainder( R!.ring, a, b );
1511
1512end );
1513
1514####################################
1515#
1516# constructor functions and methods:
1517#
1518####################################
1519
1520##
1521InstallGlobalFunction( CreateHomalgRing,
1522  function( arg )
1523    local nargs, r, IdentityMatrices, statistics, asserts,
1524          homalg_ring, table, properties, ar, type, matrix_type,
1525          ring_element_constructor, finalizers, c, el;
1526
1527    nargs := Length( arg );
1528
1529    if nargs = 0 then
1530        Error( "expecting a ring as the first argument\n" );
1531    fi;
1532
1533    r := arg[1];
1534
1535    IdentityMatrices := ContainerForWeakPointers( TheTypeContainerForWeakPointersOnIdentityMatrices );
1536    Unbind( IdentityMatrices!.active );
1537    Unbind( IdentityMatrices!.deleted );
1538    Unbind( IdentityMatrices!.accessed );
1539    Unbind( IdentityMatrices!.cache_misses );
1540
1541    statistics := rec(
1542                      BasisOfRowModule := 0,
1543                      BasisOfColumnModule := 0,
1544                      BasisOfRowsCoeff := 0,
1545                      BasisOfColumnsCoeff := 0,
1546                      DecideZeroRows := 0,
1547                      DecideZeroColumns := 0,
1548                      DecideZeroRowsEffectively := 0,
1549                      DecideZeroColumnsEffectively := 0,
1550                      SyzygiesGeneratorsOfRows := 0,
1551                      SyzygiesGeneratorsOfColumns := 0,
1552                      RelativeSyzygiesGeneratorsOfRows := 0,
1553                      RelativeSyzygiesGeneratorsOfColumns := 0,
1554                      PartiallyReducedBasisOfRowModule := 0,
1555                      PartiallyReducedBasisOfColumnModule := 0,
1556                      ReducedBasisOfRowModule := 0,
1557                      ReducedBasisOfColumnModule := 0,
1558                      ReducedSyzygiesGeneratorsOfRows := 0,
1559                      ReducedSyzygiesGeneratorsOfColumns := 0
1560                      );
1561
1562
1563    ##  <#GAPDoc Label="asserts">
1564    ##   Below you can find the record of the available level-4 assertions,
1565    ##   which is a &GAP;-component of every &homalg; ring. Each assertion can
1566    ##   thus be overwritten by package developers or even ordinary users.
1567    ##      <Listing Type="Code"><![CDATA[
1568    asserts :=
1569      rec(
1570          BasisOfRowModule :=
1571            function( B ) return ( NrRows( B ) = 0 ) = IsZero( B ); end,
1572
1573          BasisOfColumnModule :=
1574            function( B ) return ( NrColumns( B ) = 0 ) = IsZero( B ); end,
1575
1576          BasisOfRowsCoeff :=
1577            function( B, T, M ) return B = T * M; end,
1578
1579          BasisOfColumnsCoeff :=
1580            function( B, M, T ) return B = M * T; end,
1581
1582          DecideZeroRows_Effectively :=
1583            function( M, A, B ) return M = DecideZeroRows( A, B ); end,
1584
1585          DecideZeroColumns_Effectively :=
1586            function( M, A, B ) return M = DecideZeroColumns( A, B ); end,
1587
1588          DecideZeroRowsEffectively :=
1589            function( M, A, T, B ) return M = A + T * B; end,
1590
1591          DecideZeroColumnsEffectively :=
1592            function( M, A, B, T ) return M = A + B * T; end,
1593
1594          DecideZeroRowsWRTNonBasis :=
1595            function( B )
1596              local R;
1597              R := HomalgRing( B );
1598              if not ( HasIsBasisOfRowsMatrix( B ) and
1599                       IsBasisOfRowsMatrix( B ) ) and
1600                 IsBound( R!.DecideZeroWRTNonBasis ) then
1601                  if R!.DecideZeroWRTNonBasis = "warn" then
1602                      Info( InfoWarning, 1,
1603                            "about to reduce with respect to a matrix",
1604                            "with IsBasisOfRowsMatrix not set to true" );
1605                  elif R!.DecideZeroWRTNonBasis = "error" then
1606                      Error( "about to reduce with respect to a matrix",
1607                             "with IsBasisOfRowsMatrix not set to true\n" );
1608                  fi;
1609              fi;
1610            end,
1611
1612          DecideZeroColumnsWRTNonBasis :=
1613            function( B )
1614              local R;
1615              R := HomalgRing( B );
1616              if not ( HasIsBasisOfColumnsMatrix( B ) and
1617                       IsBasisOfColumnsMatrix( B ) ) and
1618                 IsBound( R!.DecideZeroWRTNonBasis ) then
1619                  if R!.DecideZeroWRTNonBasis = "warn" then
1620                      Info( InfoWarning, 1,
1621                            "about to reduce with respect to a matrix",
1622                            "with IsBasisOfColumnsMatrix not set to true" );
1623                  elif R!.DecideZeroWRTNonBasis = "error" then
1624                      Error( "about to reduce with respect to a matrix",
1625                             "with IsBasisOfColumnsMatrix not set to true\n" );
1626                  fi;
1627              fi;
1628            end,
1629
1630          ReducedBasisOfRowModule :=
1631            function( M, B )
1632              return GenerateSameRowModule( B, BasisOfRowModule( M ) );
1633            end,
1634
1635          ReducedBasisOfColumnModule :=
1636            function( M, B )
1637              return GenerateSameColumnModule( B, BasisOfColumnModule( M ) );
1638            end,
1639
1640          ReducedSyzygiesGeneratorsOfRows :=
1641            function( M, S )
1642              return GenerateSameRowModule( S, SyzygiesGeneratorsOfRows( M ) );
1643            end,
1644
1645          ReducedSyzygiesGeneratorsOfColumns :=
1646            function( M, S )
1647              return GenerateSameColumnModule( S, SyzygiesGeneratorsOfColumns( M ) );
1648            end,
1649
1650         );
1651    ##  ]]></Listing>
1652    ##  <#/GAPDoc>
1653
1654    homalg_ring := rec(
1655                       ring := r,
1656                       IdentityMatrices := IdentityMatrices,
1657                       statistics := statistics,
1658                       asserts := asserts,
1659                       DecideZeroWRTNonBasis := "warn/error"
1660                       );
1661
1662    if nargs > 1 and IshomalgTable( arg[nargs] ) then
1663        table := arg[nargs];
1664    else
1665        table := CreateHomalgTable( r );
1666    fi;
1667
1668    if not IsBound( table!.InitialMatrix ) and IsBound( table!.ZeroMatrix ) then
1669        table!.InitialMatrix := table!.ZeroMatrix;
1670    fi;
1671
1672    if not IsBound( table!.InitialIdentityMatrix ) and IsBound( table!.IdentityMatrix ) then
1673        table!.InitialIdentityMatrix := table!.IdentityMatrix;
1674    fi;
1675
1676    properties := [ ];
1677
1678    for ar in arg{[ 2 .. nargs ]} do
1679        if IsFilter( ar ) then
1680            Add( properties, ar );
1681        elif not IsBound( type ) and IsList( ar ) and Length( ar ) = 2 and ForAll( ar, IsType ) then
1682            type := ar;
1683        elif not IsBound( ring_element_constructor ) and IsFunction( ar ) then
1684            ring_element_constructor := ar;
1685        elif not IsBound( finalizers ) and IsList( ar ) and ForAll( ar, IsFunction ) then
1686            finalizers := ar;
1687        fi;
1688    od;
1689
1690    if IsBound( type ) then
1691        matrix_type := type[2];
1692        type := type[1];
1693    elif IsSemiringWithOneAndZero( r ) then
1694        matrix_type := ValueGlobal( "TheTypeHomalgInternalMatrix" ); ## will be defined later in HomalgMatrix.gi
1695        type := TheTypeHomalgInternalRing;
1696    else
1697        Error( "the types of the ring and matrices were not specified\n" );
1698    fi;
1699
1700    ## Objectify:
1701    ObjectifyWithAttributes(
1702            homalg_ring, type,
1703            homalgTable, table );
1704
1705    if IsBound( matrix_type ) then
1706        SetTypeOfHomalgMatrix( homalg_ring, matrix_type );
1707    fi;
1708
1709    if properties <> [ ] then
1710        for ar in properties do
1711            Setter( ar )( homalg_ring, true );
1712        od;
1713    fi;
1714
1715    if IsBound( HOMALG_MATRICES.RingCounter ) then
1716        HOMALG_MATRICES.RingCounter := HOMALG_MATRICES.RingCounter + 1;
1717    else
1718        HOMALG_MATRICES.RingCounter := 1;
1719    fi;
1720
1721    ## this has to be done before we call
1722    ## ring_element_constructor below
1723    homalg_ring!.creation_number := HOMALG_MATRICES.RingCounter;
1724
1725    ## do not invoke SetRingProperties here, since I might be
1726    ## the first step of creating a residue class ring!
1727
1728    ## this has to be invoked before we set the distinguished ring elements below;
1729    ## these functions are used to finalize the construction of the ring
1730    if IsBound( finalizers ) then
1731        Perform( finalizers, function( f ) f( homalg_ring ); end );
1732    fi;
1733
1734    ## add distinguished ring elements like 0 and 1
1735    ## (sometimes also -1) to the homalg table:
1736    if IsBound( ring_element_constructor ) then
1737
1738        for c in NamesOfComponents( table ) do
1739            if IsRingElement( table!.(c) ) then
1740                table!.(c) := ring_element_constructor( table!.(c), homalg_ring );
1741            fi;
1742        od;
1743
1744        ## set the attribute
1745        SetRingElementConstructor( homalg_ring, ring_element_constructor );
1746
1747    fi;
1748
1749    if IsBound( HOMALG_MATRICES.ByASmallerPresentation ) and HOMALG_MATRICES.ByASmallerPresentation = true then
1750        homalg_ring!.ByASmallerPresentation := true;
1751    fi;
1752
1753    ## e.g. needed to construct residue class rings
1754    homalg_ring!.ConstructorArguments := arg;
1755
1756    homalg_ring!.interpret_rationals_func :=
1757      function( r )
1758        local d;
1759        d := DenominatorRat( r ) / homalg_ring;
1760        if IsZero( d ) or not IsUnit( homalg_ring, d ) then
1761            return fail;
1762        fi;
1763        return r / homalg_ring;
1764    end;
1765
1766    return homalg_ring;
1767
1768end );
1769
1770##  <#GAPDoc Label="HomalgRingOfIntegers">
1771##  <ManSection>
1772##    <Func Arg="" Name="HomalgRingOfIntegers" Label="constructor for the integers"/>
1773##    <Returns>a &homalg; ring</Returns>
1774##    <Func Arg="c" Name="HomalgRingOfIntegers" Label="constructor for the residue class rings of the integers"/>
1775##    <Returns>a &homalg; ring</Returns>
1776##    <Description>
1777##      The no-argument form returns the ring of integers <M>&ZZ;</M> for &homalg;. <P/>
1778##      The one-argument form accepts an integer <A>c</A> and returns
1779##      the ring <M>&ZZ; / c </M> for &homalg;:
1780##      <List>
1781##        <Item><A>c</A><M> = 0</M> defaults to <M>&ZZ;</M></Item>
1782##        <Item>if <A>c</A> is a prime power then the package &GaussForHomalg; is loaded (if it fails to load an error is issued)</Item>
1783##        <Item>otherwise, the residue class ring constructor <C>/</C>
1784##          (&see; <Ref Oper="\/" Label="constructor for residue class rings" Style="Number"/>) is invoked</Item>
1785##      </List>
1786##      The operation <C>SetRingProperties</C> is automatically invoked to set the ring properties. <P/>
1787##      If for some reason you don't want to use the &GaussForHomalg; package (maybe because you didn't install it), then use<P/>
1788##      <C>HomalgRingOfIntegers</C>( ) <C>/</C> <A>c</A>; <P/>
1789##      but note that the computations will then be considerably slower.
1790##    </Description>
1791##  </ManSection>
1792##  <#/GAPDoc>
1793##
1794InstallGlobalFunction( HomalgRingOfIntegers,
1795  function( arg )
1796    local nargs, R, c, d, rel;
1797
1798    nargs := Length( arg );
1799
1800    if nargs = 0 or arg[1] = 0 then
1801        c := 0;
1802        R := CreateHomalgRing( Integers );
1803    elif IsInt( arg[1] ) then
1804        c := arg[1];
1805        if Length( Collected( FactorsInt( c ) ) ) = 1 and IsPackageMarkedForLoading( "GaussForHomalg", ">= 2018.09.20") then
1806            R := HOMALG_RING_OF_INTEGERS_PRIME_POWER_HELPER( arg, c );
1807        else
1808            R := HomalgRingOfIntegers( );
1809            rel := HomalgRingRelationsAsGeneratorsOfLeftIdeal( [ c ], R );
1810            return R / rel;
1811        fi;
1812    else
1813        Error( "the first argument must be an integer\n" );
1814    fi;
1815
1816    SetIsResidueClassRingOfTheIntegers( R, true );
1817
1818    SetRingProperties( R, c );
1819
1820    return R;
1821
1822end );
1823
1824##
1825InstallMethod( HomalgRingOfIntegersInUnderlyingCAS,
1826        "for an integer and homalg internal ring",
1827        [ IsInt, IsHomalgInternalRingRep ],
1828
1829  HomalgRingOfIntegers );
1830
1831##
1832InstallOtherMethod( \in,
1833        "for an integer and a homalg internal ring",
1834        [ IsObject, IsHomalgInternalRingRep ], 100001,
1835
1836  function( z, R )
1837
1838    if not IsInt( Zero( R ) ) then
1839        TryNextMethod( );
1840    fi;
1841
1842    if IsInt( z ) then
1843        return true;
1844    fi;
1845
1846    if not ( HasIsFieldForHomalg( R ) and IsFieldForHomalg( R ) ) then
1847        TryNextMethod( );
1848    fi;
1849
1850    if IsRat( z ) then
1851        return true;
1852    fi;
1853
1854    TryNextMethod( );
1855
1856end );
1857
1858##
1859InstallMethod( ParseListOfIndeterminates,
1860        "for lists",
1861        [ IsList ],
1862
1863  function( _indets )
1864    local err, l, indets, i, v, l1, l2, p1, p2, c;
1865
1866    if _indets = [ ] then
1867        return [ ];
1868    fi;
1869
1870    err := function( ) Error( "a list of variable strings or range strings is expected\n" ); end;
1871
1872    if ForAll( _indets, IsRingElement and HasName ) then
1873        return ParseListOfIndeterminates( List( _indets, Name ) );
1874    fi;
1875
1876    if not ForAll( _indets, e -> IsStringRep( e ) or ( IsList( e ) and ForAll( e, IsInt ) ) ) then
1877        TryNextMethod( );
1878    fi;
1879
1880    l := Length( _indets );
1881
1882    indets := [ ];
1883
1884    for i in [ 1 .. l ] do
1885        v := _indets[i];
1886        if Position( v, ',' ) <> fail then
1887            err( );
1888        elif ForAll( v, IsInt ) then
1889            ## do nothing
1890        elif Position( v, '.' ) = fail then
1891            if i < l and ForAll( _indets[ i + 1 ], IsInt ) then
1892                Append( indets, List( _indets[ i + 1 ], i -> Concatenation( v, String( i ) ) ) );
1893            else
1894                Add( indets, v );
1895            fi;
1896        elif PositionSublist( v, ".." ) = fail then
1897            err( );
1898        else
1899            v := SplitString( v, "." );
1900            v := Filtered( v, s -> not IsEmpty( s ) );
1901            if Length( v ) <> 2 then
1902                err( );
1903            fi;
1904#             p1 := PositionProperty( v[1], c -> Position( "0123456789", c ) <> fail );
1905#             p2 := PositionProperty( v[2], c -> Position( "0123456789", c ) <> fail );
1906            l1 := Flat( List( "0123456789", c -> Positions( v[1], c ) ) );
1907            Sort( l1 );
1908            l2 := Flat( List( "0123456789", c -> Positions( v[2], c ) ) );
1909            Sort( l2 );
1910            if l1 = [] or l2 = [] then
1911                err( );
1912            fi;
1913            p1 := l1[1];
1914            p2 := l2[1];
1915            for i in [ 2 .. Length( l1 ) ] do
1916                if l1[i-1] + 1 <> l1[i] then
1917                    p1 := l1[i];
1918                fi;
1919            od;
1920            for i in [ 2 .. Length( l2 ) ] do
1921                if l2[i-1] + 1 <> l2[i] then
1922                    p2 := l2[i];
1923                fi;
1924            od;
1925            if p1 = 1 then
1926                err( );
1927            fi;
1928            c := v[1]{[ 1 .. p1 - 1 ]};
1929            if p1 = p2 and c <> v[2]{[ 1 .. p2 - 1 ]} then
1930                err( );
1931            fi;
1932            p1 := EvalString( v[1]{[ p1 .. Length( v[1] ) ]} );
1933            p2 := EvalString( v[2]{[ p2 .. Length( v[2] ) ]} );
1934            Append( indets, List( [ p1 .. p2 ], i -> Concatenation( c, String( i ) ) ) );
1935        fi;
1936    od;
1937
1938    return indets;
1939
1940end );
1941
1942##
1943InstallGlobalFunction( _PrepareInputForPolynomialRing,
1944  function( R, indets )
1945    local var, nr_var, properties, r, var_of_base_ring, param;
1946
1947    if HasRingRelations( R ) then
1948        Error( "polynomial rings over homalg residue class rings are not supported yet\nUse the generic residue class ring constructor '/' provided by homalg after defining the ambient ring\nfor help type: ?homalg: constructor for residue class rings\n" );
1949    fi;
1950
1951    ## get the new indeterminates for the ring and save them in var
1952    if IsString( indets ) and indets <> "" then
1953        var := SplitString( indets, "," );
1954    elif indets <> [ ] and ForAll( indets, i -> IsString( i ) and i <> "" ) then
1955        var := indets;
1956    else
1957        Error( "either a non-empty list of indeterminates or a comma separated string of them must be provided as the second argument\n" );
1958    fi;
1959
1960    if not IsDuplicateFree( var ) then
1961        Error( "your list of indeterminates is not duplicate free: ", var, "\n" );
1962    fi;
1963
1964    nr_var := Length( var );
1965
1966    properties := [ IsCommutative ];
1967
1968    ## K[x] is a principal ideal ring for a field K
1969    if Length( var ) = 1 and HasIsFieldForHomalg( R ) and IsFieldForHomalg( R ) then
1970        Add( properties, IsPrincipalIdealRing );
1971    fi;
1972
1973    ## r is set to the ring of coefficients
1974    ## further a check is done, whether the old indeterminates (if exist) and the new
1975    ## ones are disjoint
1976    if HasIndeterminatesOfPolynomialRing( R ) then
1977        r := CoefficientsRing( R );
1978        var_of_base_ring := IndeterminatesOfPolynomialRing( R );
1979        var_of_base_ring := List( var_of_base_ring, Name );
1980        if Intersection2( var_of_base_ring, var ) <> [ ] then
1981            Error( "the following indeterminates are already elements of the base ring: ", Intersection2( var_of_base_ring, var ), "\n" );
1982        fi;
1983    else
1984        r := R;
1985        var_of_base_ring := [ ];
1986    fi;
1987
1988    var := Concatenation( var_of_base_ring, var );
1989
1990    if HasRationalParameters( r ) then
1991        param := Concatenation( ",", JoinStringsWithSeparator( RationalParameters( r ) ) );
1992    else
1993        param := "";
1994    fi;
1995
1996    return [ r, var, nr_var, properties, param ];
1997
1998end );
1999
2000##
2001InstallMethod( PolynomialRing,
2002        "for homalg internal rings",
2003        [ IsHomalgInternalRingRep, IsList ],
2004
2005  function( R, indets )
2006    local ar, r, var, nr_var, properties, S, l;
2007
2008    ar := _PrepareInputForPolynomialRing( R, indets );
2009
2010    r := ar[1];
2011    var := ar[2];	## all indeterminates, relative and base
2012    nr_var := ar[3];	## the number of relative indeterminates
2013    properties := ar[4];
2014
2015    ## create the new ring
2016    S := PolynomialRing( r!.ring, var );
2017
2018    var := IndeterminatesOfPolynomialRing( S );
2019
2020    S := CallFuncList( CreateHomalgRing, Concatenation( [ S ], properties ) );
2021
2022    SetIsFreePolynomialRing( S, true );
2023
2024    if HasIndeterminatesOfPolynomialRing( R ) and IndeterminatesOfPolynomialRing( R ) <> [ ] then
2025        SetBaseRing( S, R );
2026        l := Length( var );
2027        SetRelativeIndeterminatesOfPolynomialRing( S, var{[ l - nr_var + 1 .. l ]} );
2028    fi;
2029
2030    SetRingProperties( S, r, var );
2031
2032    S!.pre_matrix_constructor := a -> One( S ) * a;
2033
2034    return S;
2035
2036end );
2037
2038##
2039InstallMethod( \*,
2040        "for homalg rings",
2041        [ IsHomalgRing, IsList ], 1001,	## a high rank is necessary to overwrite the default behaviour of applying R to each list element
2042
2043  function( R, indets )
2044
2045    return PolynomialRing( R, ParseListOfIndeterminates( indets ) );
2046
2047end );
2048
2049##
2050InstallMethod( \*,
2051        "for homalg rings",
2052        [ IsHomalgRing, IsString ], 1001, ## for this method to be triggered first it has to have at least the same rank as the above method
2053
2054  function( R, indets )
2055
2056    if indets = "" then
2057        return R;
2058    else
2059        return R * SplitString( indets, "," );
2060    fi;
2061
2062end );
2063
2064##
2065InstallOtherMethod( \[\],
2066        "for homalg rings",
2067        [ IsHomalgRing, IsString ], 1001, ## for this method to be triggered first it has to have at least the same rank as the above method
2068
2069  function( R, indets )
2070
2071    return R * indets;
2072
2073end );
2074
2075##
2076InstallMethod( \*,
2077        "for homalg rings",
2078        [ IsHomalgRing and IsFreePolynomialRing and HasCoefficientsRing,
2079          IsHomalgRing and IsFreePolynomialRing and HasCoefficientsRing ],
2080
2081  function( R1, R2 )
2082    local r, var2;
2083
2084    r := CoefficientsRing( R1 );
2085
2086    if not IsIdenticalObj( r, CoefficientsRing( R2 ) ) then
2087        TryNextMethod( );
2088    fi;
2089
2090    var2 := IndeterminatesOfPolynomialRing( R2 );
2091    var2 := List( var2, Name );
2092    var2 := JoinStringsWithSeparator( var2 );
2093
2094    return PolynomialRing( R1, var2 );
2095
2096end );
2097
2098##
2099InstallMethod( PolynomialRing,
2100        "for homalg rings",
2101        [ IsHomalgRing, IsString ], 1001,
2102
2103  function( R, _var )
2104    local var;
2105
2106    if _var = "" then
2107        return R;
2108    fi;
2109
2110    var := ParseListOfIndeterminates( SplitString( _var, "," ) );
2111
2112    return PolynomialRing( R, var );
2113
2114end );
2115
2116##
2117InstallMethod( PolynomialRingWithLexicographicOrdering,
2118        "for homalg rings",
2119        [ IsHomalgRing and HasIndeterminatesOfPolynomialRing ],
2120
2121  function( R )
2122    local indets;
2123
2124    indets := IndeterminatesOfPolynomialRing( R );
2125
2126    indets := List( indets, String );
2127
2128    return PolynomialRing( CoefficientsRing( R ), indets : order := "lex" );
2129
2130end );
2131
2132##
2133InstallMethod( RingOfDerivations,
2134        "for homalg rings",
2135        [ IsHomalgRing and IsCommutative, IsString ], 1001,
2136
2137  function( S, _der )
2138    local der, A;
2139
2140    der := ParseListOfIndeterminates( SplitString( _der, "," ) );
2141
2142    A := RingOfDerivations( S, der );
2143
2144    S!.RingOfDerivations := A;
2145
2146    return A;
2147
2148end );
2149
2150##
2151InstallMethod( RingOfDerivations,
2152        "for homalg rings",
2153        [ IsHomalgRing ],
2154
2155  function( R )
2156    local var, A;
2157
2158    if IsBound(R!.RingOfDerivations) then
2159        return R!.RingOfDerivations;
2160    fi;
2161
2162    if HasRelativeIndeterminatesOfPolynomialRing( R ) then
2163        var := RelativeIndeterminatesOfPolynomialRing( R );
2164    else
2165        var := IndeterminatesOfPolynomialRing( R );
2166    fi;
2167
2168    var := List( var, x -> Concatenation( "D", Name( x ) ) );
2169
2170    A := RingOfDerivations( R, var );
2171
2172    R!.RingOfDerivations := A;
2173
2174    return A;
2175
2176end );
2177
2178##
2179InstallMethod( ExteriorRing,
2180        "for homalg rings",
2181        [ IsHomalgRing and IsFreePolynomialRing, IsList ],
2182
2183  function( S, _anti )
2184    local anti, Base, A;
2185
2186    if IsString( _anti ) then
2187        return ExteriorRing( S, SplitString( _anti, "," ) );
2188    else
2189        anti := ParseListOfIndeterminates( _anti );
2190    fi;
2191
2192    if HasBaseRing( S ) then
2193        Base := BaseRing( S );
2194    else
2195        Base := CoefficientsRing( S );
2196    fi;
2197    A := ExteriorRing( S, CoefficientsRing( S ), Base, anti );
2198
2199    SetRingProperties( A, S, anti );
2200
2201    return A;
2202
2203end );
2204
2205##
2206InstallMethod( KoszulDualRing,
2207        "for homalg rings",
2208        [ IsHomalgRing and IsFreePolynomialRing, IsList ],
2209
2210  function( S, anti )
2211    local A;
2212
2213    if IsBound(S!.KoszulDualRing) then
2214        return S!.KoszulDualRing;
2215    fi;
2216
2217    A := ExteriorRing( S, anti );
2218
2219    ## thanks GAP4
2220    A!.KoszulDualRing := S;
2221    S!.KoszulDualRing := A;
2222
2223    return A;
2224
2225end );
2226
2227##
2228InstallMethod( KoszulDualRing,
2229        "for homalg rings",
2230        [ IsHomalgRing ], 10000,
2231
2232  function( S )
2233
2234    if IsBound(S!.KoszulDualRing) then
2235        return S!.KoszulDualRing;
2236    fi;
2237
2238    TryNextMethod( );
2239
2240end );
2241
2242##
2243InstallMethod( KoszulDualRing,
2244        "for homalg rings",
2245        [ IsHomalgRing and IsFreePolynomialRing ],
2246
2247  function( S )
2248    local l, Base, l_base, s1, s2, i;
2249
2250    l := IndeterminatesOfPolynomialRing( S );
2251
2252    if HasBaseRing( S ) then
2253        Base := BaseRing( S );
2254    else
2255        Base := CoefficientsRing( S );
2256    fi;
2257
2258    if HasIsFreePolynomialRing( Base ) and IsFreePolynomialRing( Base ) then
2259        l_base := List( Indeterminates( Base ), a -> a / S );
2260    else
2261        l_base := [];
2262    fi;
2263
2264    l := Difference( l, l_base );
2265
2266    s1 := List( l, String );
2267
2268    l := Length( l );
2269
2270    s2 := List( [ 0 .. l - 1 ], a -> Concatenation( "e", String( a ) ) );
2271
2272    for i in s1 do
2273        if not ( Position( s2, i ) = fail ) then
2274            Info( InfoWarning, 1,
2275                  "KoszulDualRing: Variable name ", i, " already in use"
2276                  );
2277        fi;
2278    od;
2279
2280    return KoszulDualRing( S, s2 );
2281
2282end );
2283
2284##
2285InstallGlobalFunction( HomalgRingElement,
2286  function( arg )
2287    local nargs, R;
2288
2289    nargs := Length( arg );
2290
2291    R := arg[nargs];
2292
2293    if HasRingElementConstructor( R ) then
2294        return CallFuncList( RingElementConstructor( R ), arg );
2295    elif not IsHomalgInternalRingRep( R ) then
2296        Error( "the non-internal homalg ring must contain a ring element constructor as the attribute RingElementConstructor\n" );
2297    elif IsString( arg[1] ) then
2298        return One( R ) * EvalString( arg[1] );
2299    fi;
2300
2301    return One( R ) * arg[1];
2302
2303end );
2304
2305##
2306InstallMethod( \/,
2307        "for ring elements",
2308        [ IsRingElement, IsHomalgRing ],
2309
2310  function( r, R )
2311
2312    return HomalgRingElement( String( r ), R );
2313
2314end );
2315
2316##
2317InstallMethod( \/,
2318        "for strings",
2319        [ IsStringRep and IsString, IsHomalgRing ],
2320
2321  function( r, R )
2322
2323    return HomalgRingElement( r, R );
2324
2325end );
2326
2327##
2328InstallMethod( \/,
2329        "for strings",
2330        [ IsString, IsHomalgRing ],
2331
2332  function( r, R )
2333
2334    # IsStringRep( r ) is false since otherwise the method above would have been chosen
2335    r := CopyToStringRep( r );
2336
2337    return HomalgRingElement( r, R );
2338
2339end );
2340
2341##
2342InstallMethod( \/,
2343        "for homalg ring elements",
2344        [ IsHomalgRingElement, IsHomalgRing ],
2345
2346  function( r, R )
2347
2348    if IsIdenticalObj( HomalgRing( r ), R ) then
2349        return r;
2350    fi;
2351
2352    return HomalgRingElement( String( r ), R );
2353
2354end );
2355
2356##
2357InstallGlobalFunction( StringToElementStringList,
2358  function( arg )
2359
2360    return SplitString( arg[1], ",", "[ ]\n" );
2361
2362end );
2363
2364##
2365InstallGlobalFunction( _CreateHomalgRingToTestProperties,
2366  function( arg )
2367    local homalg_ring, type;
2368
2369    homalg_ring := rec( );
2370
2371    type := TheTypeHomalgInternalRing;
2372
2373    ## Objectify:
2374    CallFuncList( ObjectifyWithAttributes, Concatenation([ homalg_ring, type ], arg ) );
2375
2376    return homalg_ring;
2377
2378end );
2379
2380##
2381InstallMethod( UnivariatePolynomial,
2382        "for a list and a string",
2383        [ IsList, IsString ],
2384
2385  function( coeffs, r )
2386    local pol;
2387
2388    pol := List( Reversed( [ 1 .. Length( coeffs ) ] ),
2389                 i -> Concatenation( "(", String( coeffs[i] ), ")*", r, "^", String( i - 1 ) )
2390                 );
2391
2392    return JoinStringsWithSeparator( pol, "+" );
2393
2394end );
2395
2396##
2397InstallMethod( Homogenization,
2398        "for a homalg ring element and a homalg ring",
2399        [ IsHomalgRingElement, IsHomalgRing ],
2400
2401  function( r, S )
2402    local R, d, indetsR, indetsS, indR, indS, z, coeffs, monoms, diff;
2403
2404    if IsZero( r ) then
2405        return Zero( S );
2406    fi;
2407
2408    R := HomalgRing( r );
2409
2410    if not HasIsFreePolynomialRing( R ) and IsFreePolynomialRing( R ) and
2411       not HasIsFreePolynomialRing( S ) and IsFreePolynomialRing( S ) then
2412        TryNextMethod( );
2413    fi;
2414
2415    d := Degree( r );
2416
2417    if d = 0 then
2418        return r / S;
2419    fi;
2420
2421    indetsR := Indeterminates( R );
2422    indetsS := Indeterminates( S );
2423
2424    indS := List( indetsS, String );
2425    indR := List( indetsR, String );
2426
2427
2428    if not IsSubset( indS, indR ) then
2429        Error( "the indeterminates of the second argument do not contain the indeterminates of the ring underlying the given ring element\n" );
2430    fi;
2431
2432    z := Difference( indS, indR );
2433
2434    if Length( z ) <> 1 then
2435        Error( "the indeterminates of the second argument are not exactly one more than the indeterminates of the ring underlying the given ring element\n" );
2436    fi;
2437
2438    z := Filtered( indetsS, a -> String( a ) = z[1] )[1];
2439
2440    coeffs := Coefficients( r );
2441    monoms := coeffs!.monomials;
2442
2443    coeffs := List( EntriesOfHomalgMatrix( coeffs ), c -> c / S );
2444    monoms := List( monoms, m -> ( m / S ) * z^( d - Degree( m ) ) );
2445
2446    return Sum( ListN( coeffs, monoms, \* ) );
2447
2448end );
2449
2450##
2451InstallMethod( \*,
2452        "for an FFE and a homalg ring element",
2453        [ IsFFE, IsHomalgRingElement ],
2454
2455  function( f, r )
2456    local R, e;
2457
2458    R := HomalgRing( r );
2459
2460    e := LogFFE( f, Z( Characteristic( R ), DegreeOverPrimeField( R ) ) );
2461
2462    return PrimitiveElement( R )^e * r;
2463
2464end );
2465
2466##
2467InstallMethod( \*,
2468        "for a homalg ring element and an FFE",
2469        [ IsHomalgRingElement, IsFFE ],
2470
2471  function( r, f )
2472
2473    return f * r;
2474
2475end );
2476
2477## the second argument is there for method selection
2478InstallMethod( LcmOp,
2479        "for homalg objects",
2480        [ IsList, IsHomalgRingElement ],
2481
2482  function( L, r )
2483
2484    return Iterated( L, LcmOp );
2485
2486end );
2487
2488##
2489InstallMethod( LcmOp,
2490        "for homalg ring elements",
2491        [ IsHomalgRingElement, IsHomalgRingElement ],
2492
2493  function( p, q )
2494    local R, pp, qq;
2495
2496    if IsZero( p ) or IsZero( q ) then
2497        return Zero( p );
2498    fi;
2499
2500    R := HomalgRing( p );
2501
2502    pp := HomalgMatrix( [ p ], 1, 1, R );
2503    qq := HomalgMatrix( [ q ], 1, 1, R );
2504
2505    ## this can be expressed categorically
2506    return p * SyzygiesOfRows( pp, qq )[ 1, 1 ];
2507
2508end );
2509
2510##
2511InstallOtherMethod( GcdOp,
2512        "for homalg ring elements",
2513        [ IsHomalgRingElement, IsHomalgRingElement ],
2514
2515  function( p, q )
2516    local R, pp, qq;
2517
2518    if IsZero( p ) or IsZero( q ) then
2519        return Zero( p );
2520    fi;
2521
2522    R := HomalgRing( p );
2523
2524    pp := HomalgMatrix( [ p ], 1, 1, R );
2525    qq := HomalgMatrix( [ q ], 1, 1, R );
2526
2527    ## this can be expressed categorically
2528    return q / SyzygiesOfRows( pp, qq )[ 1, 1 ];
2529
2530end );
2531
2532##
2533InstallMethod( CoefficientsRing,
2534        "for homalg ring elements",
2535        [ IsHomalgRingElement ],
2536
2537  function( r )
2538
2539    return CoefficientsRing( HomalgRing( r ) );
2540
2541end );
2542
2543##
2544InstallMethod( CoefficientsRing,
2545        "for homalg fields",
2546        [ IsHomalgRing and IsFieldForHomalg ],
2547
2548  IdFunc );
2549
2550##
2551InstallMethod( CoefficientsRing,
2552        "for homalg ring of integers",
2553        [ IsHomalgRing and IsIntegersForHomalg ],
2554
2555  IdFunc );
2556
2557##
2558InstallMethod( BaseRing,
2559        "for homalg fields",
2560        [ IsHomalgRing and IsFieldForHomalg ],
2561
2562  IdFunc );
2563
2564##
2565InstallMethod( BaseRing,
2566        "for homalg ring of integers",
2567        [ IsHomalgRing and IsIntegersForHomalg ],
2568
2569  IdFunc );
2570
2571##
2572InstallMethod( Size,
2573        "for a homalg ring",
2574        [ IsHomalgRing ],
2575
2576  function( R )
2577    local p, d;
2578
2579    p := Characteristic( R );
2580
2581    if p = 0 then
2582        return infinity;
2583    fi;
2584
2585    if not HasDegreeOverPrimeField( R ) then
2586        TryNextMethod( );
2587    fi;
2588
2589    return p^DegreeOverPrimeField( R );
2590
2591end );
2592
2593####################################
2594#
2595# View, Print, and Display methods:
2596#
2597####################################
2598
2599##
2600InstallMethod( String,
2601        "for homalg rings",
2602        [ IsHomalgRing ],
2603
2604  RingName );
2605
2606##
2607InstallMethod( ViewObj,
2608        "for homalg rings",
2609        [ IsHomalgRing ], 100,
2610
2611  function( o )
2612
2613    Print( RingName( o ) );
2614
2615end );
2616
2617##
2618InstallMethod( Display,
2619        "for homalg rings",
2620        [ IsHomalgRing ],
2621
2622  function( o )
2623
2624    Print( "<A" );
2625
2626    if HasIsZero( o ) and IsZero( o ) then
2627        Print( " zero" );
2628    fi;
2629
2630    if IsBound( o!.description ) then
2631        Print( o!.description );
2632    elif IsHomalgInternalRingRep( o ) then
2633        Print( "n internal" );
2634    fi;
2635
2636    if IsPreHomalgRing( o ) then
2637        Print( " pre-homalg" );
2638    fi;
2639
2640    Print( " ring>", "\n" );
2641
2642end );
2643
2644##
2645InstallMethod( DisplayRing,
2646        "for homalg rings",
2647        [ IsHomalgRing ],
2648
2649  function( o )
2650
2651    Display( o );
2652
2653end );
2654
2655##
2656InstallMethod( ViewObj,
2657        "for homalg ring elements",
2658        [ IsHomalgRingElement ],
2659
2660  function( o )
2661
2662    Print( Name( o ) );	## this sets the attribute Name and the view method is never triggered again (as long as Name is set)
2663
2664end );
2665
2666##
2667InstallMethod( Display,
2668        "for homalg ring elements",
2669        [ IsHomalgRingElement ],
2670
2671  function( o )
2672
2673    Print( Name( o ), "\n" );	## this sets the attribute Name and the display method is never triggered again (as long as Name is set)
2674
2675end );
2676
2677##
2678InstallMethod( Display,
2679        "for weak pointer containers of identity matrices",
2680        [ IsContainerForWeakPointersOnIdentityMatricesRep ],
2681
2682  function( o )
2683    local weak_pointers;
2684
2685    weak_pointers := o!.weak_pointers;
2686
2687    Print( Filtered( [ 1 .. LengthWPObj( weak_pointers ) ], i -> IsBoundElmWPObj( weak_pointers, i ) ), "\n" );
2688
2689end );
2690