Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/pkg/resclasses/lib/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 24.8.2025 mit Größe 141 kB image not shown  

Quelle  resclass.gi   Sprache: unbekannt

 
#############################################################################
##
#W  resclass.gi             GAP4 Package `ResClasses'             Stefan Kohl
##
##  This file contains implementations of methods and functions for computing
##  with unions of residue classes +/- finite sets ('residue class unions').
##
#############################################################################

#############################################################################
##
#S  Implications between the categories of residue class unions /////////////
#S  and shorthands for commonly used filters. ///////////////////////////////
##
#############################################################################

InstallTrueMethod( IsResidueClassUnion,
                   IsResidueClassUnionOfZorZ_pi );
InstallTrueMethod( IsResidueClassUnionOfZorZ_pi,
                   IsResidueClassUnionOfZ );
InstallTrueMethod( IsResidueClassUnionOfZorZ_pi,
                   IsResidueClassUnionOfZ_pi );
InstallTrueMethod( IsResidueClassUnion,
                   IsResidueClassUnionOfZxZ );
InstallTrueMethod( IsResidueClassUnion,
                   IsResidueClassUnionOfGFqx );

BindGlobal( "IsResidueClassOfZ",
             IsResidueClassUnionOfZ and IsResidueClass );
BindGlobal( "IsResidueClassOfZxZ",
             IsResidueClassUnionOfZxZ and IsResidueClass );
BindGlobal( "IsResidueClassOfZ_pi",
             IsResidueClassUnionOfZ_pi and IsResidueClass );
BindGlobal( "IsResidueClassOfZorZ_pi",
             IsResidueClassUnionOfZorZ_pi and IsResidueClass );
BindGlobal( "IsResidueClassOfGFqx",
             IsResidueClassUnionOfGFqx and IsResidueClass );

BindGlobal( "IsResidueClassUnionInResidueListRep",
             IsResidueClassUnion and IsResidueClassUnionResidueListRep );
BindGlobal( "IsResidueClassUnionInClassListRep",
             IsResidueClassUnion and IsResidueClassUnionClassListRep );
BindGlobal( "IsResidueClassUnionOfZInClassListRep",
             IsResidueClassUnionOfZ and IsResidueClassUnionClassListRep );

#############################################################################
##
#S  The families of residue class unions. ///////////////////////////////////
##
#############################################################################

# Internal variables for caching the families of residue class unions
# used in the current GAP session.

BindGlobal( "Z_RESIDUE_CLASS_UNIONS_FAMILIES", [] );
BindGlobal( "Z_PI_RESIDUE_CLASS_UNIONS_FAMILIES", [] );
BindGlobal( "GF_Q_X_RESIDUE_CLASS_UNIONS_FAMILIES", [] );

#############################################################################
##
#F  ZResidueClassUnionsFamily( <fixedreps> )
##
InstallGlobalFunction( ZResidueClassUnionsFamily,

  function ( fixedreps )

    local  fam, pos;

    if not fixedreps then pos := 1; else pos := 2; fi;
    if   IsBound( Z_RESIDUE_CLASS_UNIONS_FAMILIES[ pos ] )
    then return   Z_RESIDUE_CLASS_UNIONS_FAMILIES[ pos ]; fi;
    if not fixedreps then
      fam := NewFamily( "ResidueClassUnionsFamily( Integers )",
                        IsResidueClassUnionOfZ,
                        CanEasilySortElements, CanEasilySortElements );
      SetUnderlyingRing( fam, Integers );
      SetElementsFamily( fam, FamilyObj( 1 ) );
    else
      fam := NewFamily( "ResidueClassUnionsFamily( Integers, true )",
                        IsUnionOfResidueClassesWithFixedRepresentatives,
                        CanEasilySortElements, CanEasilySortElements );
      SetUnderlyingRing( fam, Integers );
      SetElementsFamily( fam, fam );
    fi;
    MakeReadWriteGlobal( "Z_RESIDUE_CLASS_UNIONS_FAMILIES" );
    Z_RESIDUE_CLASS_UNIONS_FAMILIES[ pos ] := fam;
    MakeReadOnlyGlobal( "Z_RESIDUE_CLASS_UNIONS_FAMILIES" );
    return fam;
  end );

#############################################################################
##
#V  ZxZResidueClassUnionsFamily . . family of all residue class unions of Z^2
##
##  GAP does not view Z^2 as a ring, but rather as a row module.
##  Anyway it is viewed as the underlying ring of the family, since it
##  mathematically is a ring and since this avoids a case distinction
##  in many places in the code.
##
BindGlobal( "ZxZResidueClassUnionsFamily",
            NewFamily( "ResidueClassUnionsFamily( Integers^2 )",
                       IsResidueClassUnionOfZxZ,
                       CanEasilySortElements, CanEasilySortElements ) );
SetUnderlyingRing( ZxZResidueClassUnionsFamily, Integers^2 );
SetElementsFamily( ZxZResidueClassUnionsFamily, FamilyObj( [ 0, 0 ] ) );

#############################################################################
##
#F  Z_piResidueClassUnionsFamily( <R> , <fixedreps> )
##
InstallGlobalFunction( Z_piResidueClassUnionsFamily,

  function ( R, fixedreps )

    local  fam, cat, name;

    fam := First( Z_PI_RESIDUE_CLASS_UNIONS_FAMILIES,
                  fam ->     UnderlyingRing( fam ) = R
                         and PositionSublist( fam!.NAME,
                                              String(fixedreps) ) <> fail );
    if fam <> fail then return fam; fi;
    if   not fixedreps
    then cat := IsResidueClassUnionOfZ_pi;
    else cat := IsUnionOfResidueClassesOfZ_piWithFixedRepresentatives; fi;
    name := Concatenation( "ResidueClassUnionsFamily( ",
                           String( R ),", ",String(fixedreps)," )" );
    fam := NewFamily( name, cat,
                      CanEasilySortElements, CanEasilySortElements );
    SetUnderlyingRing( fam, R );
    if not fixedreps then SetElementsFamily( fam, FamilyObj( 1 ) );
                     else SetElementsFamily( fam, fam ); fi;
    MakeReadWriteGlobal( "Z_PI_RESIDUE_CLASS_UNIONS_FAMILIES" );
    Add( Z_PI_RESIDUE_CLASS_UNIONS_FAMILIES, fam );
    MakeReadOnlyGlobal( "Z_PI_RESIDUE_CLASS_UNIONS_FAMILIES" );

    return fam;
  end );

#############################################################################
##
#F  GFqxResidueClassUnionsFamily( <R>, <fixedreps> )
##
InstallGlobalFunction( GFqxResidueClassUnionsFamily,

  function ( R, fixedreps )

    local  fam, cat, name, x;

    x := IndeterminatesOfPolynomialRing( R )[ 1 ];
    fam := First( GF_Q_X_RESIDUE_CLASS_UNIONS_FAMILIES,
                  fam -> UnderlyingRing( fam ) = R
                         and PositionSublist( fam!.NAME,
                                              String(fixedreps) ) <> fail );
    if fam <> fail then return fam; fi;
    if   not fixedreps
    then cat := IsResidueClassUnionOfGFqx;
    else cat := IsUnionOfResidueClassesOfGFqxWithFixedRepresentatives; fi;
    name := Concatenation( "ResidueClassUnionsFamily( ",
                           ViewString( R ),", ",String(fixedreps)," )" );
    fam := NewFamily( name, cat,
                      CanEasilySortElements, CanEasilySortElements );
    SetUnderlyingIndeterminate( fam, x );
    SetUnderlyingRing( fam, R );
    if not fixedreps then SetElementsFamily( fam, FamilyObj( x ) );
                     else SetElementsFamily( fam, fam ); fi;
    MakeReadWriteGlobal( "GF_Q_X_RESIDUE_CLASS_UNIONS_FAMILIES" );
    Add( GF_Q_X_RESIDUE_CLASS_UNIONS_FAMILIES, fam );
    MakeReadOnlyGlobal( "GF_Q_X_RESIDUE_CLASS_UNIONS_FAMILIES" );

    return fam;
  end );

#############################################################################
##
#F  ResidueClassUnionsFamily( <R> [ , <fixedreps> ]  )
##
InstallGlobalFunction( ResidueClassUnionsFamily,

  function ( arg )

    local  R, fixedreps;

    if   not Length(arg) in [1,2]
    or   Length(arg) = 2 and not arg[2] in [true,false]
    then Error("Usage: ResidueClassUnionsFamily( <R> [ , <fixedreps> ] )\n");
    fi;
    R := arg[1];
    if Length(arg) = 2 then fixedreps := arg[2]; else fixedreps := false; fi;
    if   IsIntegers( R )
    then return ZResidueClassUnionsFamily( fixedreps );
    elif IsZxZ( R ) then return ZxZResidueClassUnionsFamily;
    elif IsZ_pi( R )
    then return Z_piResidueClassUnionsFamily( R, fixedreps );
    elif IsUnivariatePolynomialRing( R ) and IsFiniteFieldPolynomialRing( R )
    then return GFqxResidueClassUnionsFamily( R, fixedreps );
    else Error("Sorry, residue class unions of ",R,
               " are not yet implemented.\n");
    fi;
  end );

#############################################################################
##
#M  IsZxZ( <R> ) . . . . . . . . . . . . . . . . . . Z^2 = Z x Z = Integers^2
##
InstallMethod( IsZxZ, "general method (ResClasses)", true,
               [ IsObject ], 0, R -> R = Integers^2 );

#############################################################################
##
#S  Residues / residue classes (mod m). /////////////////////////////////////
##
#############################################################################

# Buffer for storing already computed polynomial residue systems.

BindGlobal( "POLYNOMIAL_RESIDUE_CACHE", [] );

BindGlobal( "AllGFqPolynomialsModDegree",

  function ( q, d, x )

    local  erg, mon, gflist;

    if   d = 0
    then return [ Zero( x ) ];
    elif     IsBound( POLYNOMIAL_RESIDUE_CACHE[ q ] )
         and IsBound( POLYNOMIAL_RESIDUE_CACHE[ q ][ d ] )
    then return ShallowCopy( POLYNOMIAL_RESIDUE_CACHE[ q ][ d ] );
    else gflist := AsList( GF( q ) );
         mon := List( gflist, el -> List( [ 0 .. d - 1 ], i -> el * x^i ) );
         erg := List( Tuples( GF( q ), d ),
                      t -> Sum( List( [ 1 .. d ],
                                      i -> mon[ Position( gflist, t[ i ] ) ]
                                              [ d - i + 1 ] ) ) );
         MakeReadWriteGlobal( "POLYNOMIAL_RESIDUE_CACHE" );
         if not IsBound( POLYNOMIAL_RESIDUE_CACHE[ q ] )
         then POLYNOMIAL_RESIDUE_CACHE[ q ] := [ ]; fi;
         POLYNOMIAL_RESIDUE_CACHE[ q ][ d ] := Immutable( erg );
         MakeReadOnlyGlobal( "POLYNOMIAL_RESIDUE_CACHE" );
         return erg;
    fi;
  end );

# Difference r1(m1) \ r2(m2) of two residue classes;
# the residue classes r1(m1) and r2(m2) are to be given as pairs
# [r1,m1] and [r2,m2] of integers, and the output is a list of
# residue classes represented in the same way.

BindGlobal( "DIFFERENCE_OF_RESIDUE_CLASSES",

  function ( cl1, cl2 )

    local  cls, r1, m1, r2, m2, r3, m3, divs, d, p, r, inc, i;

    r1 := cl1[1]; m1 := cl1[2];
    r2 := cl2[1]; m2 := cl2[2];

    if (r1-r2) mod Gcd(m1,m2) <> 0 then return [cl1]; fi; # disjoint
    m3 := Lcm(m1,m2);
    if m3 = m1 then return []; fi; # second cl. is a superset of first cl.
    r3 := ChineseRem([m1,m2],[r1,r2]);

    divs := []; d := 1;
    for p in Factors(m3/m1) do 
      d := d * p;
      Add(divs,d);
    od;
    cls := [];
    for i in [1..Length(divs)] do
      d := divs[i];
      if i > 1 then inc := divs[i-1]; else inc := 1; fi;
      for r in [inc,2*inc..d-inc] do
        Add(cls,[r,d]);
      od;
    od;
    for i in [1..Length(cls)] do # get moduli and residues right
      cls[i][2] := cls[i][2] * m1;
      cls[i][1] := (cls[i][1] * m1 + r3) mod cls[i][2];
    od;
    SortParallel( List( cls, Reversed ), cls );

    return cls;
  end );

#############################################################################
##
#M  AllResidues( <R>, <m> ) . . . . . . . . . . . .  for Z, Z_pi and GF(q)[x]
##
InstallMethod( AllResidues,
               "for Z, Z_pi and GF(q)[x] (ResClasses)", ReturnTrue,
               [ IsRing, IsRingElement ], 0,

  function ( R, m )

    local  q, d, x;

    if   IsIntegers(R) or IsZ_pi(R)
    then return [0..StandardAssociate(R,m)-1]; fi;
    if IsUnivariatePolynomialRing(R) and Characteristic(R) <> 0 then
      q := Size(CoefficientsRing(R));
      d := DegreeOfLaurentPolynomial(m);
      x := IndeterminatesOfPolynomialRing(R)[1];
      return AllGFqPolynomialsModDegree(q,d,x);
    fi;
    TryNextMethod();
  end );

#############################################################################
##
#M  AllResidues( Integers^2, <L> ) . . . . . . . . . . . . for lattice in Z^2
##
InstallOtherMethod( AllResidues,
                    "for lattice in Z^2 (ResClasses)", true,
                    [ IsRowModule, IsMatrix ], 0,

  function ( ZxZ, L )
    if not IsZxZ(ZxZ) or not IsSubset(ZxZ,L) then TryNextMethod(); fi;
    L := HermiteNormalFormIntegerMat(L);
    return Cartesian([0..L[1][1]-1],[0..L[2][2]-1]);
  end );

#############################################################################
##
#M  NumberOfResidues( <R>, <m> ) . . . . . . . . . . for Z, Z_pi and GF(q)[x]
##
InstallMethod( NumberOfResidues,
               "for Z, Z_pi and GF(q)[x] (ResClasses)", ReturnTrue,
               [ IsRing, IsRingElement ], 0,

  function ( R, m )

    local  q, d, x;

    if IsIntegers(R) or IsZ_pi(R) then return StandardAssociate(R,m); fi;
    if IsUnivariatePolynomialRing(R) and Characteristic(R) <> 0 then
      q := Size(CoefficientsRing(R));
      d := DegreeOfLaurentPolynomial(m);
      return q^d;
    fi;
    TryNextMethod();
  end );

#############################################################################
##
#M  NumberOfResidues( Integers^2, <L> ) . . . . . . . . .  for lattice in Z^2
##
InstallOtherMethod( NumberOfResidues,
                    "for lattice in Z^2 (ResClasses)", ReturnTrue,
                    [ IsRowModule, IsMatrix ], 0,

  function ( ZxZ, L )
    if not IsZxZ(ZxZ) or not IsSubset(ZxZ,L) then TryNextMethod(); fi;
    return AbsInt(DeterminantMat(L));
  end );

#############################################################################
##
#F  AllResidueClassesModulo( [ <R>, ] <m> ) . . the residue classes (mod <m>)
##
InstallGlobalFunction( AllResidueClassesModulo,

  function ( arg )

    local  R, m;

    if   Length(arg) = 2
    then R := arg[1]; m := arg[2];
    else m := arg[1]; R := DefaultRing(m); fi;
    if IsRing(R) and (IsZero(m) or not m in R) then return fail; fi;
    return List(AllResidues(R,m),r->ResidueClass(R,m,r));
  end );

#############################################################################
##
#F  All2x2IntegerMatricesInHNFWithDeterminantUpTo( <maxdet> )
##
InstallGlobalFunction( All2x2IntegerMatricesInHNFWithDeterminantUpTo,

  function ( maxdet )

    local  mods, det, diags, diag;

    mods := [];
    for det in [1..maxdet] do 
      diags := List(DivisorsInt(det),d->[d,det/d]);
      for diag in diags do
        Append(mods,List([0..diag[2]-1],k->[[diag[1],k],[0,diag[2]]]));
      od;
    od;
    return mods;
  end );

#############################################################################
##
#M  SizeOfSmallestResidueClassRing( <R> ) . . . . .  for Z, Z_pi and GF(q)[x]
##
InstallMethod( SizeOfSmallestResidueClassRing,
               "for Z, Z_pi and GF(q)[x] (ResClasses)", true, [ IsRing ], 0,

  function ( R )
    if   IsIntegers(R) then return 2;
    elif IsZ_pi(R) then return Minimum(NoninvertiblePrimes(R));
    elif IsFiniteFieldPolynomialRing(R) then return Characteristic(R);
    else TryNextMethod(); fi;
  end );

#############################################################################
##
#M  SizeOfSmallestResidueClassRing( Integers^2 ) . . . . . . . . . .  for Z^2
##
InstallOtherMethod( SizeOfSmallestResidueClassRing,
                    "for Z^2 (ResClasses)", true, [ IsRowModule ], 0,

  function ( ZxZ )
    if IsZxZ(ZxZ) then return 2; else TryNextMethod(); fi;
  end );

#############################################################################
##
#S  Basic functionality for lattices in Z^n. ////////////////////////////////
##
#############################################################################

#############################################################################
##
#M  StandardAssociate( <R>, <mat> ) . . . . . . . HNF of n x n integer matrix
##
InstallOtherMethod( StandardAssociate,
                    "HNF of n x n integer matrix (ResClasses)", IsCollsElms,
                    [ IsRing and IsFullMatrixModule, IsMatrix ], 0,

  function ( R, mat )
    if   not IsIntegers(LeftActingDomain(R))
      or Length(Set(DimensionOfVectors(R))) <> 1 or not mat in R
    then TryNextMethod(); fi;
    return HermiteNormalFormIntegerMat(mat);
  end );

#############################################################################
##
#M  \mod . . . . . . . . . . . . . . . . . . . . . for a vector and a lattice
##
if   not IsReadOnlyGlobal( "VectorModLattice" ) # not protected in polycyclic
then MakeReadOnlyGlobal( "VectorModLattice" ); fi;

InstallMethod( \mod, "for a vector and a lattice (ResClasses)", IsElmsColls,
               [ IsRowVector, IsMatrix ], 0,
               function ( v, L ) return VectorModLattice( v, L ); end );

#############################################################################
##
#M  LcmOp( <R>, <mat1>, <mat2> ) . . . . . . . .  lattice intersection in Z^n
##
InstallOtherMethod( LcmOp, "lattice intersection in Z^n (ResClasses)",
                    IsCollsElmsElms,
                    [ IsRing and IsFullMatrixModule, IsMatrix, IsMatrix ], 0,

  function ( R, mat1, mat2 )

    local  n;

    if   not IsIntegers(LeftActingDomain(R)) 
      or Length(Set(DimensionOfVectors(R))) <> 1
      or not mat1 in R or not mat2 in R 
    then TryNextMethod(); fi;

    n := DimensionOfVectors(R)[1];

    if n = 2 then # Check whether matrices are already in HNF.
      if   mat1[2][1] <> 0 or ForAny(Flat(mat1),n->n<0)
        or mat1[1][2] >= mat1[2][2]
      then mat1 := HermiteNormalFormIntegerMat(mat1); fi;
      if   mat2[2][1] <> 0 or ForAny(Flat(mat2),n->n<0)
        or mat2[1][2] >= mat2[2][2]
      then mat2 := HermiteNormalFormIntegerMat(mat2); fi;
    else
      mat1 := HermiteNormalFormIntegerMat(mat1);
      mat2 := HermiteNormalFormIntegerMat(mat2);
    fi;

    return LatticeIntersection( mat1, mat2 );

  end );

#############################################################################
##
#M  IsSublattice( <L1>, <L2> ) . . . . . . . . . . . . .  for lattices in Z^n
##
InstallMethod( IsSublattice,
               "for lattices in Z^n (ResClasses)", IsIdenticalObj,
               [ IsMatrix, IsMatrix ], 0,

  function ( L1, L2 )
    return ForAll( Flat( L2 / L1 ), IsInt );
  end );

#############################################################################
##
#M  Superlattices( <L> ) . . . . . . . . . . . . . . . . for a lattice in Z^2
##
SetupCache( "RESCLASSES_SUPERLATTICES_CACHE", 100 );

InstallMethod( Superlattices,
               "for a lattice in Z^2 (ResClasses)", true, [ IsMatrix ], 0,

  function ( L )

    local  lattices, sup, divx, divy, x, y, dx;

    if   Set(DimensionsMat(L)) <> [2] or not ForAll(Flat(L),IsInt)
      or DeterminantMat(L) = 0
    then TryNextMethod(); fi;

    if IsOne(L) then return [[[1,0],[0,1]]]; fi;

    lattices := FetchFromCache( "RESCLASSES_SUPERLATTICES_CACHE", L );
    if lattices <> fail then return lattices; fi;

    divx := DivisorsInt(L[2][2]); divy := DivisorsInt(L[1][1]);
    lattices := [];
    for x in divx do for y in divy do for dx in [0..x-1] do
      sup := [[y,dx],[0,x]];
      if ForAll(Flat(L/sup),IsInt) then Add(lattices,sup); fi;
    od; od; od;
    lattices := Set(lattices,HermiteNormalFormIntegerMat);
    SortParallel(List(lattices,Li->[DeterminantMat(Li),Li]),lattices);
    
    PutIntoCache( "RESCLASSES_SUPERLATTICES_CACHE", L, lattices );
    return lattices;
  end );

#############################################################################
##
#F  ModulusAsFormattedString( <m> ) . format lattice etc. for output purposes
##
BindGlobal( "ModulusAsFormattedString",
  function ( m )
    if not IsMatrix(m) then return ViewString(m); fi;
    return Filtered(Concatenation(List(["(",m[1][1],",",m[1][2],")Z+(",
                                            m[2][1],",",m[2][2],")Z"],
                                       String)),ch->ch<>' ');
  end );

#############################################################################
##
#S  Construction of residue class unions. ///////////////////////////////////
##
#############################################################################

#############################################################################
##
#M  ResidueClassUnionCons( <filter>, <R>, <m>, <r>, <included>, <excluded> )
##
InstallMethod( ResidueClassUnionCons,
               "residue list rep., for Z, Z_pi and GF(q)[x] (ResClasses)",
               ReturnTrue, [ IsResidueClassUnion, IsRing, IsRingElement,
                             IsList, IsList, IsList ], 0,

  function ( filter, R, m, r, included, excluded )

    local  ReduceResidueClassUnion, result, both, fam, type, rep, pos;

    ReduceResidueClassUnion := function ( U )

      local  R, m, r, mRed, mRedBuf, rRed, rRedBuf, valid, fact, p;

      R := UnderlyingRing(FamilyObj(U));
      m := StandardAssociate(R,U!.m);  mRed := m;
      r := Set( U!.r, n -> n mod m ); rRed := r;
      fact := Set(Factors(R,m));
      for p in fact do
        repeat
          mRedBuf := mRed; rRedBuf := ShallowCopy(rRed);
          mRed := mRed/p;
          rRed := Set(rRedBuf,n->n mod mRed);
          if   IsIntegers(R) or IsZ_pi(R)
          then valid := Length(rRed) = Length(rRedBuf)/p;
          else valid := Length(rRed) = Length(rRedBuf)/
                      Size(CoefficientsRing(R))^DegreeOfLaurentPolynomial(p);
          fi;
        until not valid or not IsZero(mRed mod p) or IsOne(mRed);
        if not valid then mRed := mRedBuf; rRed := rRedBuf; fi;
      od;
      U!.m := mRed; U!.r := Immutable(rRed);
      U!.included := Immutable(Set(Filtered(U!.included,
                                            n -> not (n mod mRed in rRed))));
      U!.excluded := Immutable(Set(Filtered(U!.excluded,
                                            n -> n mod mRed in rRed)));
      if rRed = [] then U := Difference(U!.included,U!.excluded); fi;
    end;

    if not ( IsIntegers( R ) or IsZ_pi( R )
             or (     IsFiniteFieldPolynomialRing( R )
                  and IsUnivariatePolynomialRing( R ) ) )
    then TryNextMethod( ); fi;
    m := StandardAssociate( R, m );
    r := Set( r, n -> n mod m );
    both := Intersection( included, excluded );
    included := Difference( included, both );
    excluded := Difference( excluded, both );
    if r = [] then return Difference(included,excluded); fi;
    fam := ResidueClassUnionsFamily( R );
    if   IsIntegers( R )       then type := IsResidueClassUnionOfZ;
    elif IsZ_pi( R )           then type := IsResidueClassUnionOfZ_pi;
    elif IsPolynomialRing( R ) then type := IsResidueClassUnionOfGFqx;
    fi;
    result := Objectify( NewType( fam, type and
                                  IsResidueClassUnionResidueListRep ),
                         rec( m := m, r := r,
                              included := included, excluded := excluded ) );
    SetSize( result, infinity ); SetIsFinite( result, false );
    SetIsEmpty( result, false );
    rep := r[1]; pos := 1;
    while rep in excluded do
      pos := pos + 1;
      rep := r[pos mod Length(r) + 1] + Int(pos/Length(r)) * m;
    od;
    if   included <> [ ] and rep > Minimum( included ) 
    then rep := Minimum( included ); fi;
    SetRepresentative( result, rep );
    ReduceResidueClassUnion( result );
    if Length( result!.r ) = 1 then SetIsResidueClass( result, true ); fi;
    if IsOne( result!.m ) and result!.r = [ Zero( R ) ]
      and [ result!.included, result!.excluded ] = [ [ ], [ ] ]
    then return R; else return result; fi;
  end );

#############################################################################
##
#M  ResidueClassUnionCons( <filter>, <R>, <cls>, <included>, <excluded> )
##
InstallMethod( ResidueClassUnionCons,
               "class list rep., for Z (ResClasses)",
               ReturnTrue, [ IsResidueClassUnionOfZInClassListRep,
                             IsIntegers, IsList, IsList, IsList ], 0,

  function ( filter, R, cls, included, excluded )

    local  ReduceResidueClassUnion, result, m, both, rep, pos;

    ReduceResidueClassUnion := function ( U )

      local  R, cls, clsRed, m, ndpair, d1, d2, density, divs, d, i,
             partdens, cl, int, res, r, both;

      cls := U!.cls;
      cls := Set( cls, c -> [ c[1] mod c[2], AbsInt( c[2] ) ] );
      SortParallel( List( cls, Reversed ), cls );
      repeat
        ndpair := First(Combinations(cls,2),
                        c->(c[1][1]-c[2][1]) mod Gcd(c[1][2],c[2][2]) = 0);
        if ndpair <> fail then
          cls := Difference(cls,ndpair);
          d1 := DIFFERENCE_OF_RESIDUE_CLASSES(ndpair[1],ndpair[2]);
          d2 := DIFFERENCE_OF_RESIDUE_CLASSES(ndpair[2],ndpair[1]);
          if Length(d1) <= Length(d2) then
            Append(cls,d1); Add(cls,ndpair[2]);
          else
            Append(cls,d2); Add(cls,ndpair[1]);
          fi;
          cls := Filtered(cls,cl->cl<>[]);
        fi;
      until ndpair = fail;
      SortParallel( List( cls, Reversed ), cls );

      clsRed := [];
      m := U!.m;
      divs := DivisorsInt(m);
      density := Sum(List(cls,cl->1/cl[2]));
      for d in divs do
        if 1/d > density then continue; fi;
        res := Set(cls,cl->cl[1] mod d);
        for r in res do
          partdens := 0;
          for cl in cls do
            if (r - cl[1]) mod Gcd(d,cl[2]) = 0
            then partdens := partdens + 1/Lcm(d,cl[2]); fi;
          od;
          if partdens = 1/d then
            Add(clsRed,[r,d]);
            cls := List(cls,cl->DIFFERENCE_OF_RESIDUE_CLASSES(cl,[r,d]));
            cls := Filtered(Concatenation(cls),cl->cl<>[]);
            if cls = [] then break; fi;
            SortParallel( List( cls, Reversed ), cls );
            density := Sum(List(cls,cl->1/cl[2]));
          elif partdens > 1/d then Error("internal error"); fi;
        od;
        if cls = [] then break; fi;
      od;

      m := Lcm(List(clsRed,c->c[2]));
      SortParallel( List( clsRed, Reversed ), clsRed );
      U!.cls := Immutable(clsRed); U!.m := m;
      both := Intersection( U!.included, U!.excluded );
      U!.included := Difference( U!.included, both );
      U!.excluded := Difference( U!.excluded, both );
      U!.included := Immutable(Set(Filtered(U!.included,
                       n -> not ForAny(clsRed,c -> n mod c[2] = c[1]))));
      U!.excluded := Immutable(Set(Filtered(U!.excluded,
                       n -> ForAny(clsRed,c -> n mod c[2] = c[1]))));
      if clsRed = [] then U := U!.included; fi;
    end;

    if not IsIntegers(R) then TryNextMethod(); fi;
    if cls = [] then return Difference(included,excluded); fi;

    result := Objectify( NewType( ResidueClassUnionsFamily( Integers ),
                                  IsResidueClassUnionOfZ and
                                  IsResidueClassUnionClassListRep ),
                         rec( cls := cls, m := Lcm(List(cls,c->c[2])),
                              included := included, excluded := excluded ) );
    SetSize( result, infinity ); SetIsFinite( result, false );
    SetIsEmpty( result, false );

    if ValueOption("RCU_AlreadyReduced") <> true then
      ReduceResidueClassUnion( result );
      cls := result!.cls; m := result!.m;
      included := result!.included; excluded := result!.excluded;
    fi;

    rep := cls[1][1]; pos := 1;
    while rep in excluded do
      pos := pos + 1;
      rep := cls[pos mod Length(cls) + 1][1]
           + Int(pos/Length(cls)) * cls[pos mod Length(cls) + 1][2];
    od;
    if   included <> [ ] and rep > Minimum( included ) 
    then rep := Minimum( included ); fi;
    SetRepresentative( result, rep );

    if Length(result!.cls) = 1 then SetIsResidueClass(result,true); fi;
    if result!.m = 1 and result!.cls = [[0,1]]
      and [result!.included,result!.excluded] = [[],[]]
    then return Integers; else return result; fi;
  end );

#############################################################################
##
#M  ResidueClassUnionCons( <filter>, Integers^2,
##                         <L>, <r>, <included>, <excluded> )
##
InstallMethod( ResidueClassUnionCons,
               "residue list representation, for Z^2 (ResClasses)",
               ReturnTrue, [ IsResidueClassUnion, IsRowModule,
                             IsMatrix, IsList, IsList, IsList ], 0,

  function ( filter, ZxZ, L, r, included, excluded )

    local  ReduceResidueClassUnion, result, both, rep, pos;

    ReduceResidueClassUnion := function ( U )

      local  L, r, LRed, rRed, divs, d;

      L := HermiteNormalFormIntegerMat(U!.m);  LRed := L;
      r := List(U!.r,v->v mod L); rRed := r;
      divs := Superlattices(L);
      for d in divs do
        if DeterminantMat(L)/DeterminantMat(d) > Length(r) then continue; fi;
        rRed := Set(r,v->v mod d);
        if   Length(rRed) = Length(r)*DeterminantMat(d)/DeterminantMat(L)
        then LRed := d; break; fi;
      od;
      U!.m := LRed; U!.r := Immutable(rRed);
      U!.included := Immutable(Set(Filtered(U!.included,
                                            v->not v mod LRed in rRed)));
      U!.excluded := Immutable(Set(Filtered(U!.excluded,
                                            v->v mod LRed in rRed)));
    end;

    if not IsZxZ( ZxZ ) then TryNextMethod( ); fi;
    L := HermiteNormalFormIntegerMat( L );
    r := Set( r, v -> v mod L );
    both := Intersection( included, excluded );
    included := Difference( included, both );
    excluded := Difference( excluded, both );
    if r = [] then L := [[1,0],[0,1]]; excluded := []; fi;
    result := Objectify( NewType( ResidueClassUnionsFamily( ZxZ ),
                                  IsResidueClassUnionOfZxZ and
                                  IsResidueClassUnionResidueListRep ),
                         rec( m := L, r := r,
                              included := included, excluded := excluded ) );
    if r <> [] then
      SetSize( result, infinity ); SetIsFinite( result, false );
      SetIsEmpty( result, false );
    else
      SetSize( result, Length( included ) );
      SetIsEmpty( result, IsEmpty( included ) );
    fi;
    if not IsEmpty( result ) then
      if included <> [ ] then rep := included[ 1 ]; else
        rep := r[1]; pos := 1;
        while rep in excluded do
          pos := pos + 1;
          rep := r[pos mod Length(r) + 1] + Int(pos/Length(r)) * L[1];
        od;
      fi;
      SetRepresentative( result, rep );
    fi;
    if r <> [] then ReduceResidueClassUnion( result ); else
      MakeImmutable( result!.included ); MakeImmutable( result!.excluded );
    fi;
    if Length( result!.r ) = 1 then SetIsResidueClass( result, true ); fi;
    if AbsInt( DeterminantMat( result!.m ) ) = 1
      and result!.r = [ [ 0, 0 ] ]
      and [ result!.included, result!.excluded ] = [ [ ], [ ] ]
    then return ZxZ; else return result; fi;
  end );

#############################################################################
##
#M  ResidueClassUnionCons( <filter>, Integers^2,      ("modulus L as vector")
##                         <L>, <r>, <included>, <excluded> )
##
InstallOtherMethod( ResidueClassUnionCons,
                    "residue list rep, mod. as vector, for Z^2 (ResClasses)",
                    ReturnTrue, [ IsResidueClassUnion, IsRowModule,
                                  IsRowVector, IsList, IsList, IsList ], 0,

  function ( filter, ZxZ, L, r, included, excluded )
    return ResidueClassUnionCons( filter, ZxZ,
                                  DiagonalMat(L), r, included, excluded );
  end );

#############################################################################
##
#F  ResidueClassUnion( <R>, <m>, <r> ) . . . . . . . union of residue classes
#F  ResidueClassUnion( <R>, <m>, <r>, <included>, <excluded> )
#F  ResidueClassUnion( <R>, <cls> )
#F  ResidueClassUnion( <R>, <cls>, <included>, <excluded> )
##
InstallGlobalFunction( ResidueClassUnion,

  function ( arg )

    if    not (     Length(arg) in [3,5]
                and (    IsRing(arg[1]) and arg[2] in arg[1]
                      or     IsRowModule(arg[1]) and IsMatrix(arg[2])
                         and IsSubset(arg[1],arg[2])
                         and not IsZero(DeterminantMat(arg[2])) )
                and IsList(arg[3]) and IsSubset(arg[1],arg[3])
                and (    Length(arg) = 3 or IsList(arg[4]) and IsList(arg[5])
                     and IsSubset(arg[1],arg[4])
                     and IsSubset(arg[1],arg[5])) )
      and not (     Length(arg) in [2,4]
                and (IsRing(arg[1]) and IsList(arg[2])
                     and ForAll(arg[2],l->IsList(l) and Length(l) = 2
                                and IsSubset(arg[1],l) and not IsZero(l[2])))
                and (    Length(arg) = 2 or IsList(arg[3]) and IsList(arg[4])
                     and IsSubset(arg[1],arg[3])
                     and IsSubset(arg[1],arg[4])) )
    then Error("usage: ResidueClassUnion( <R>, <m>, <r> [, <included>",
               ", <excluded> ] )\nor ResidueClassUnion( <R>, <cls> ",
               "[, <included>, <excluded> ] ), for details see manual.\n");
         return fail;
    fi;
    return CallFuncList( ResidueClassUnionNC, arg );
  end );

#############################################################################
##
#F  ResidueClassUnionNC( <R>, <m>, <r> ) . . . . . . union of residue classes
#F  ResidueClassUnionNC( <R>, <m>, <r>, <included>, <excluded> )
#F  ResidueClassUnionNC( <R>, <cls> )
#F  ResidueClassUnionNC( <R>, <cls>, <included>, <excluded> )
##
InstallGlobalFunction( ResidueClassUnionNC,

  function ( arg )

    local  R, m, r, cls, included, excluded;

    if Length(arg) in [2,4] then
      R := arg[1]; cls := arg[2];
      if   Length(arg) = 4
      then included := Set(arg[3]); excluded := Set(arg[4]);
      else included := [];          excluded := []; fi;
      return ResidueClassUnionCons( IsResidueClassUnionOfZInClassListRep,
                                    R, cls, included, excluded );
    elif Length(arg) in [3,5] then
      R := arg[1]; m := arg[2]; r := Set(arg[3]);
      if   Length(arg) = 5
      then included := Set(arg[4]); excluded := Set(arg[5]);
      else included := [];          excluded := []; fi;
      return ResidueClassUnionCons( IsResidueClassUnion, R, m, r,
                                    included, excluded );
    fi;
  end );

#############################################################################
##
#F  ResidueClass( <R>, <m>, <r> ) . . . . . . . . . . .  residue class of <R>
#F  ResidueClass( <m>, <r> )  . residue class of the default ring of <m>, <r>
#F  ResidueClass( <r>, <m> )  . . . . . . . . . . . . . . . . . . .  ( dito )
##
InstallGlobalFunction( ResidueClass,

  function ( arg )

    local  R, m, r, d, cl, usage;

    usage := "usage: see ?ResidueClass\n";
    if   Length( arg ) = 3 then
      R := arg[1]; m := arg[2]; r := arg[3];
      if   not (    IsRing(R) and m in R and r in R and not IsZero(m)
                 or IsRowModule(R) and IsMatrix(m) and IsSubset(R,m)
                    and not IsZero(DeterminantMat(m)) )
      then Error( usage ); return fail; fi;
    elif Length( arg ) = 2 then
      if ForAll( arg, IsRingElement ) then
        if   IsPolynomial(arg[1])
        then R := DefaultRing(arg[1]); arg[2] := arg[2] * One(R);
        elif IsPolynomial(arg[2])
        then R := DefaultRing(arg[2]); arg[1] := arg[1] * One(R);
        else R := DefaultRing(arg); fi;
        m := Maximum( arg ); r := Minimum( arg );
        if IsZero( m ) then Error( usage ); return fail; fi;
      else
        if IsMatrix( arg[1] ) then m := arg[1]; r := arg[2];
                              else m := arg[2]; r := arg[1]; fi;
        if   not ( IsMatrix(m) and IsVector(r) )
        then Error( usage ); return fail; fi;
        d := Length(r);
        R := DefaultRing(r)^d;
        if not (     DimensionsMat(m) = [d,d] and IsSubset(R,m)
                 and RankMat(m) = d and r in R )
        then Error( usage ); return fail; fi;
      fi;
    elif Length( arg ) = 1 then
      if   IsList( arg[1] )
      then return CallFuncList( ResidueClass, arg[1] );
      elif IsResidueClass( arg[1] )
      then return arg[1];
      else Error( usage ); return fail; fi;
    else
      Error( usage ); return fail;
    fi;
    cl := ResidueClassUnionNC( R, m, [ r ] );
    SetIsResidueClass( cl, true );
    return cl;
  end );

#############################################################################
##
#F  ResidueClassNC( <R>, <m>, <r> ) . . . . . . . . . .  residue class of <R>
#F  ResidueClassNC( <m>, <r> )  residue class of the default ring of <m>, <r>
#F  ResidueClassNC( <r>, <m> )  . . . . . . . . . . . . . . . . . .  ( dito )
##
InstallGlobalFunction( ResidueClassNC,

  function ( arg )

    local  R, m, r, d, cl;

    if   Length( arg ) = 3 then
      R := arg[1]; m := arg[2]; r := arg[3];
    elif Length( arg ) = 2 then
      if ForAll(arg,IsRingElement) then
        R := DefaultRing( arg ); 
        m := Maximum( arg ); r := Minimum( arg );
      else
        if IsMatrix(arg[1]) then m := arg[1]; r := arg[2];
                            else m := arg[2]; r := arg[1]; fi;
        d := Length(r);
        R := DefaultRing(r)^d;
      fi;
    elif Length( arg ) = 1 then return CallFuncList(ResidueClassNC,arg[1]);
    else return fail; fi;
    cl := ResidueClassUnionNC( R, m, [ r ] );
    SetIsResidueClass( cl, true );
    return cl;
  end );

#############################################################################
##
#M  IsResidueClass( <obj> ) . . . . . . . . . . . . . . . . .  general method
##
InstallMethod( IsResidueClass,
               "general method (ResClasses)", true, [ IsObject ], 0,

  function ( obj )
    if IsRing(obj) then return true; fi;
    if    IsResidueClassUnionInResidueListRep(obj)
      and Length(obj!.r) = 1 and obj!.included = [] and obj!.excluded = []
    then return true; fi;
    if    IsResidueClassUnionInClassListRep(obj)
      and Length(obj!.cls) = 1 and obj!.included = [] and obj!.excluded = []
    then return true; fi;
    return false;
  end );

#############################################################################
##
#S  ExtRepOfObj / ObjByExtRep for residue class unions. /////////////////////
##
#############################################################################

#############################################################################
##
#M  ExtRepOfObj( <U> ) . . . . . . . . . . . . . . . for residue class unions
##
InstallMethod( ExtRepOfObj,
               "for residue class unions (ResClasses)",
               true, [ IsResidueClassUnion ], 0,
               U -> [ Modulus( U ), ShallowCopy( Residues( U ) ),
                      ShallowCopy( IncludedElements( U ) ),
                      ShallowCopy( ExcludedElements( U ) ) ] );

#############################################################################
##
#M  ExtRepOfObj( <U> ) . . . . . . . . . . . . . . . for residue class unions
##
InstallMethod( ExtRepOfObj,
               "for residue class unions in standard rep. (ResClasses)",
               true, [ IsResidueClassUnionInResidueListRep ], 0,
               U -> [U!.m, ShallowCopy( U!.r ),
                     ShallowCopy(U!.included), ShallowCopy(U!.excluded)] );

#############################################################################
##
#M  ObjByExtRep( <fam>, <l> ) . . . . . . . reconstruct a residue class union
##
InstallMethod( ObjByExtRep,
               "reconstruct a residue class union (ResClasses)",
               ReturnTrue, [ IsFamily, IsList ], 0,

  function ( fam, l )

    local  R;

    if not HasUnderlyingRing(fam) or Length(l) <> 4 then TryNextMethod(); fi;
    R := UnderlyingRing(fam);
    if fam <> ResidueClassUnionsFamily(R) then TryNextMethod(); fi;
    return ResidueClassUnion(R,l[1],l[2],l[3],l[4]);
  end );

#############################################################################
##
#S  Accessing the components of a residue class union object. ///////////////
##
#############################################################################

#############################################################################
##
#M  Modulus( <U> ) . . . . . . . . . . . . . . . . . for residue class unions
#M  Modulus( <R> ) . . . . . . . . . . . . . . .  for the base ring / -module
#M  Modulus( <l> ) . . . . . . . . . . . . . . . . . . . . .  for finite sets
##
##  Since the empty list carries no information about the objects it does
##  not contain, the method for that case silently assumes that these are
##  supposed to be integers, and returns 0.
##
InstallMethod( Modulus,
               "for residue class unions, standard rep. (ResClasses)", true,
               [ IsResidueClassUnionInResidueListRep ], 0, U -> U!.m );
InstallMethod( Modulus,
               "for residue class unions, sparse rep. (ResClasses)", true,
               [ IsResidueClassUnionInClassListRep ], 0, U -> U!.m );
InstallOtherMethod( Modulus, "for the base ring (ResClasses)", true,
                    [ IsRing ], 0, One );
InstallOtherMethod( Modulus, "for the base module (ResClasses)", true,
                    [ IsRowModule ], 0, R -> AsList( Basis( R ) ) );
InstallOtherMethod( Modulus, "for finite sets (ResClasses)", true,
                    [ IsList ], 0, l -> Zero( l[ 1 ] ) );
InstallOtherMethod( Modulus, "for the empty set (ResClasses)", true,
                    [ IsList and IsEmpty ], 0, empty -> 0 );

#############################################################################
##
#M  Residue( <cl> ) . . . . . . . . . . . . . . . . . . . for residue classes
#M  Residue( <R> ) . . . . . . . . . . . . . . .  for the base ring / -module
##
InstallMethod( Residue, "for residue classes (ResClasses)", true,
               [ IsResidueClass ], 0, cl -> Residues(cl)[1] );
InstallOtherMethod( Residue, "for the base ring (ResClasses)", true,
                    [ IsRing ], 0, Zero );
InstallOtherMethod( Residue, "for the base module (ResClasses)", true,
                    [ IsRowModule ], 0, Zero );

#############################################################################
##
#M  Residues( <U> ) . . . . . . . . . . . . . . . .  for residue class unions
#M  Residues( <R> ) . . . . . . . . . . . . . . . for the base ring / -module
#M  Residues( <l> ) . . . . . . . . . . . . . . . . . . . . . for finite sets
##
InstallMethod( Residues,
               "for residue class unions of Z in sparse rep (ResClasses)",
               true, [ IsResidueClassUnionOfZInClassListRep ], 0,

  function ( U )

    local  res, cls, m, cl, i;

    cls := U!.cls; m := U!.m; res := [];
    for cl in cls do
      for i in [0..m/cl[2]-1] do
        Add(res,i*cl[2]+cl[1]);
      od;
    od;
    res := Set(res);
    return res;
  end );

InstallMethod( Residues, "for residue class unions (ResClasses)", true,
               [ IsResidueClassUnionInResidueListRep ], 0, U -> U!.r );
InstallOtherMethod( Residues, "for the base ring (ResClasses)", true,
                    [ IsRing ], 0, R -> [ Zero( R ) ] );
InstallOtherMethod( Residues, "for the base module (ResClasses)", true,
                    [ IsRowModule ], 0, R -> [ Zero( R ) ] );
InstallOtherMethod( Residues, "for finite sets (ResClasses)", true,
                    [ IsList ], 0, l -> [  ] );

#############################################################################
##
#M  Classes( <U> ) . . . . . . . . . . . . . . . . . for residue class unions
##
InstallMethod( Classes, "for residue class unions, sparse rep. (ResClasses)",
               true, [ IsResidueClassUnionInClassListRep ], 0, U -> U!.cls );
InstallMethod( Classes, "for residue class unions, std. rep. (ResClasses)",
               true, [ IsResidueClassUnionInResidueListRep ], 0,
               U -> List(AsUnionOfFewClasses(U),
                         cl->[Residue(cl),Modulus(cl)]) );
InstallOtherMethod( Classes, "for the base ring (ResClasses)",
                    true, [ IsRing ], 0, R -> [ [ Zero(R), One(R) ] ] );
InstallOtherMethod( Classes, "for finite sets (ResClasses)",
                    true, [ IsList ], 0, R -> [  ] );

#############################################################################
##
#M  IncludedElements( <U> ) . . . . . . . . . . . .  for residue class unions
#M  IncludedElements( <R> ) . . . . . . . . . . . for the base ring / -module
#M  IncludedElements( <l> ) . . . . . . . . . . . . . . . . . for finite sets
##
InstallMethod( IncludedElements, "for residue class unions (ResClasses)",
               true, [ IsResidueClassUnionInResidueListRep ], 0,
               U -> U!.included );
InstallMethod( IncludedElements, "for residue class unions (ResClasses)",
               true, [ IsResidueClassUnionInClassListRep ], 0,
               U -> U!.included );
InstallOtherMethod( IncludedElements, "for the base ring (ResClasses)",
                    true, [ IsRing ], 0, R -> [ ] );
InstallOtherMethod( IncludedElements, "for the base module (ResClasses)",
                    true, [ IsRowModule ], 0, R -> [ ] );
InstallOtherMethod( IncludedElements, "for finite sets (ResClasses)",
                    true, [ IsList ], 0, l -> l );

#############################################################################
##
#M  ExcludedElements( <U> ) . . . . . . . . . . . .  for residue class unions
#M  ExcludedElements( <R> ) . . . . . . . . . . . for the base ring / -module
#M  ExcludedElements( <l> ) . . . . . . . . . . . . . . . . . for finite sets
##
InstallMethod( ExcludedElements, "for residue class unions (ResClasses)",
               true, [ IsResidueClassUnionInResidueListRep ], 0,
               U -> U!.excluded );
InstallMethod( ExcludedElements, "for residue class unions (ResClasses)",
               true, [ IsResidueClassUnionInClassListRep ], 0,
               U -> U!.excluded );
InstallOtherMethod( ExcludedElements, "for the base ring (ResClasses)",
                    true, [ IsRing ], 0, R -> [ ] );
InstallOtherMethod( ExcludedElements, "for the base module (ResClasses)",
                    true, [ IsRowModule ], 0, R -> [ ] );
InstallOtherMethod( ExcludedElements, "for finite sets (ResClasses)",
                    true, [ IsList ], 0, l -> [ ] );

#############################################################################
##
#M  SparseRep( <U> ) . . . conversion to class list ("sparse") representation
##
InstallMethod( SparseRep,
               "for residue class unions in standard rep. (ResClasses)",
               true, [ IsResidueClassUnionInResidueListRep ], 0,
               U -> ResidueClassUnionNC(UnderlyingRing(FamilyObj(U)),
                                        List(AsUnionOfFewClasses(U),
                                             cl->[Residue(cl),Modulus(cl)]),
                                        U!.included,U!.excluded) );
InstallMethod( SparseRep,
               "for residue class unions in sparse rep (ResClasses)",
               true, [ IsResidueClassUnionInClassListRep ], 0, U -> U );
InstallMethod( SparseRep,
               "for finite sets (ResClasses)",
               true, [ IsList ], 0, l -> l );
InstallMethod( SparseRep,
               "for the base ring (ResClasses)",
               true, [ IsRing ], 0, R -> R );
InstallMethod( SparseRep,
               "for the base module (ResClasses)",
               true, [ IsRowModule ], 0, R -> R );

#############################################################################
##
#M  StandardRep( <U> ) . . . . . conversion to residue list ("standard") rep.
##
InstallMethod( StandardRep,
               "for residue class unions in sparse rep. (ResClasses)",
               true, [ IsResidueClassUnionInClassListRep ], 0,
               U -> ResidueClassUnionNC(UnderlyingRing(FamilyObj(U)),
                                        Modulus(U),Residues(U),
                                        U!.included,U!.excluded) );
InstallMethod( StandardRep,
               "for residue class unions in standard rep. (ResClasses)",
               true, [ IsResidueClassUnionInResidueListRep ], 0, U -> U );
InstallMethod( StandardRep,
               "for finite sets (ResClasses)",
               true, [ IsList ], 0, l -> l );
InstallMethod( StandardRep,
               "for the base ring (ResClasses)",
               true, [ IsRing ], 0, R -> R );
InstallMethod( StandardRep,
               "for the base module (ResClasses)",
               true, [ IsRowModule ], 0, R -> R );

#############################################################################
##
#S  Testing residue class unions for equality. //////////////////////////////
##
#############################################################################

#############################################################################
##
#M  \=( <U1>, <U2> ) . . . . . . . . . . . . . . . . for residue class unions
##
InstallMethod( \=,
               "for two residue class unions in standard rep. (ResClasses)",
               IsIdenticalObj,
               [ IsResidueClassUnionInResidueListRep,
                 IsResidueClassUnionInResidueListRep ], 0,

  function ( U1, U2 )
    return U1!.m = U2!.m and U1!.r = U2!.r
           and U1!.included = U2!.included and U1!.excluded = U2!.excluded;
  end );

InstallMethod( \=,
               "for two residue class unions in sparse rep. (ResClasses)",
               IsIdenticalObj,
               [ IsResidueClassUnionInClassListRep,
                 IsResidueClassUnionInClassListRep ], 0,

  function ( U1, U2 )
    return U1!.m = U2!.m and U1!.cls = U2!.cls
           and U1!.included = U2!.included and U1!.excluded = U2!.excluded;
  end );

InstallMethod( \=,
               "for two residue class unions in different rep. (ResClasses)",
               IsIdenticalObj,
               [ IsResidueClassUnionInResidueListRep,
                 IsResidueClassUnionInClassListRep ], 0,
               function ( U1, U2 ) return SparseRep(U1) = U2; end );

InstallMethod( \=,
               "for two residue class unions in different rep. (ResClasses)",
               IsIdenticalObj,
               [ IsResidueClassUnionInClassListRep,
                 IsResidueClassUnionInResidueListRep ], 0,
               function ( U1, U2 ) return U1 = SparseRep(U2); end );


#############################################################################
##
#M  \=( <U>, <l> ) . . . . . . . . . . . for a residue class union and a list
#M  \=( <l>, <U> ) . . . . . . . . . . . for a list and a residue class union
##
InstallMethod( \=, "for a residue class union and a list (ResClasses)",
               ReturnTrue, [ IsResidueClassUnionInResidueListRep, IsList ],
               SUM_FLAGS,
               function ( U, l )
                 return IsOne(U!.m) and U!.r = [] and U!.included = l;
               end );

InstallMethod( \=, "for a list and a residue class union (ResClasses)",
               ReturnTrue, [ IsList, IsResidueClassUnionInResidueListRep ],
               SUM_FLAGS, function ( l, U ) return U = l; end );

#############################################################################
##
#M  \=( <D>, <l> ) . . . . . .  for an infinite domain and a list of elements
#M  \=( <l>, <D> ) . . . . . .  for a list of elements and an infinite domain
##
InstallMethod( \=,
               "for an infinite domain and a list of elements (ResClasses)", 
               IsIdenticalObj, [ IsDomain, IsList and IsFinite ], 0,
               function ( D, l )
                 if   not IsFinite( D ) then return false;
                 else TryNextMethod(  ); fi;
               end );
InstallMethod( \=,
               "for a list of elements and an infinite domain (ResClasses)", 
               IsIdenticalObj, [ IsList and IsFinite, IsDomain ], 0,
               function ( l, D ) return D = l; end );

#############################################################################
##
#M  \<( <U1>, <U2> ) . . . . . . . . . . . . . . . . for residue class unions
##
##  A total ordering of residue class unions - we want to be able to form
##  sorted lists and sets of these objects.
##
InstallMethod( \<,
               "for two residue class unions in standard rep. (ResClasses)",
               IsIdenticalObj,
               [ IsResidueClassUnionInResidueListRep,
                 IsResidueClassUnionInResidueListRep ], 0,

  function ( U1, U2 )
    if   U1!.r = []  and U2!.r <> [] then return false;
    elif U1!.r <> [] and U2!.r = []  then return true;
    elif U1!.m <> U2!.m then return U1!.m < U2!.m;
    elif U1!.r <> U2!.r then return U1!.r < U2!.r;
    elif U1!.included <> U2!.included
    then return U1!.included < U2!.included;
    else return U1!.excluded < U2!.excluded; fi;
  end );

InstallMethod( \<,
               "for two residue class unions in sparse rep. (ResClasses)",
               IsIdenticalObj,
               [ IsResidueClassUnionInClassListRep,
                 IsResidueClassUnionInClassListRep ], 0,

  function ( U1, U2 )
    if   U1!.m <> U2!.m then return U1!.m < U2!.m;
    elif List(U1!.cls,cl->cl[2]) <> List(U2!.cls,cl->cl[2])
    then return List(U1!.cls,cl->cl[2]) < List(U2!.cls,cl->cl[2]);
    elif U1!.cls <> U2!.cls then return U1!.cls < U2!.cls;
    elif U1!.included <> U2!.included
    then return U1!.included < U2!.included;
    else return U1!.excluded < U2!.excluded; fi;
  end );

InstallMethod( \<,
               "for two residue class unions, mixed rep. (ResClasses)",
               IsIdenticalObj,
               [ IsResidueClassUnionInResidueListRep,
                 IsResidueClassUnionInClassListRep ], 0,

  function ( U1, U2 )
    Error("residue class unions in different representations ",
          "cannot be sorted\n-- convert to same representation first");
    return fail;
  end );

InstallMethod( \<,
               "for two residue class unions, mixed rep. (ResClasses)",
               IsIdenticalObj,
               [ IsResidueClassUnionInClassListRep,
                 IsResidueClassUnionInResidueListRep ], 0,

  function ( U1, U2 )
    Error("residue class unions in different representations ",
          "cannot be sorted\n-- convert to same representation first");
    return fail;
  end );

#############################################################################
##
#M  \<( <U>, <R> ) . . . . . .  for a residue class union and a ring / module
#M  \<( <R>, <U> ) . . . . . .  for a ring / module and a residue class union
#M  \<( <l>, <R> ) . . . .  for a finite list of elements and a ring / module
#M  \<( <R>, <l> ) . . . .  for a ring / module and a finite list of elements
#M  \<( <l>, <U> ) .  for a finite list of elements and a residue class union
#M  \<( <U>, <l> ) .  for a residue class union and a finite list of elements
##
InstallMethod( \<, "for a residue class union and a ring (ResClasses)",
               ReturnTrue, [ IsResidueClassUnion, IsRing ], 0, ReturnFalse );
InstallMethod( \<, "for a residue class union and a module (ResClasses)",
               ReturnTrue, [ IsResidueClassUnion, IsRowModule ], 0,
               ReturnFalse );
InstallMethod( \<, "for a ring and a residue class union (ResClasses)",
               ReturnTrue, [ IsRing, IsResidueClassUnion ], 0, ReturnTrue );
InstallMethod( \<, "for a module and a residue class union (ResClasses)",
               ReturnTrue, [ IsRowModule, IsResidueClassUnion ], 0,
               ReturnTrue );
InstallMethod( \<, "for a list of elements and a ring (ResClasses)",
               IsIdenticalObj, [ IsList, IsRing ], 0,
  function ( list, R )
    if not IsIntegers(R) and not IsZ_pi(R)
       and not (     IsUnivariatePolynomialRing(R)
                 and IsFiniteFieldPolynomialRing(R))
    then TryNextMethod(); fi;
    return false;
   end );

InstallMethod( \<, "for a list of elements and a module (ResClasses)",
               IsIdenticalObj, [ IsList, IsRowModule ], 0, ReturnFalse );
InstallMethod( \<, "for a ring and a list of elements (ResClasses)",
               IsIdenticalObj, [ IsRing, IsList ], 0,
  function ( R, list )
    if not IsIntegers(R) and not IsZ_pi(R)
       and not (     IsUnivariatePolynomialRing(R)
                 and IsFiniteFieldPolynomialRing(R))
    then TryNextMethod(); fi;
    return true;
   end );

InstallMethod( \<, "for a module and a list of elements (ResClasses)",
               IsIdenticalObj, [ IsRowModule, IsList ], 0, ReturnTrue );
InstallMethod( \<, "for a list and a residue class union (ResClasses)",
               ReturnTrue, [ IsList, IsResidueClassUnion ], 0, ReturnFalse );
InstallMethod( \<, "for a residue class union and a list (ResClasses)",
               ReturnTrue, [ IsResidueClassUnion, IsList ], 0,
               function ( U, l )
                 if   IsFinite(U) then return AsList(U) < l;
                 else return true; fi;
               end );

#############################################################################
##
#S  Testing for membership in a residue class union. ////////////////////////
##
#############################################################################

#############################################################################
##
#M  \in( <n>, <U> ) . . . . . .  for a ring element and a residue class union
##
InstallMethod( \in,
               Concatenation("for a ring element and a residue class union ",
                             "in standard rep. (ResClasses)"),
               ReturnTrue,
               [ IsObject, IsResidueClassUnionInResidueListRep ], 0,

  function ( n, U )
    if not n in UnderlyingRing(FamilyObj(U)) then return false; fi;
    if   n in U!.included then return true;
    elif n in U!.excluded then return false;
    else return n mod U!.m in U!.r; fi;
  end );

InstallMethod( \in,
               Concatenation("for a ring element and a residue class union ",
                             "in sparse rep. (ResClasses)"),
               ReturnTrue,
               [ IsObject, IsResidueClassUnionInClassListRep ], 0,

  function ( n, U )
    if not n in UnderlyingRing(FamilyObj(U)) then return false; fi;
    if   n in U!.included then return true;
    elif n in U!.excluded then return false;
    else return ForAny(U!.cls,cl->n mod cl[2] = cl[1]); fi;
  end );

#############################################################################
##
#S  Density and subset relations. ///////////////////////////////////////////
##
#############################################################################

#############################################################################
##
#M  Density( <U> ) . . . . . . . . . . . . . . . . . for residue class unions
#M  Density( <R> ) . . . . . . . . . . . .  for the whole base ring / -module
#M  Density( <l> ) . . . . . . . . . . . . . . . . . . . . .  for finite sets
##
InstallMethod( Density,
               "for residue class unions in standard rep. (ResClasses)",
               true, [ IsResidueClassUnionInResidueListRep ], 0,
               U -> Length(Residues(U))/
                    NumberOfResidues(UnderlyingRing(FamilyObj(U)),
                                     Modulus(U)) );
InstallMethod( Density,
               "for residue class unions in sparse rep. (ResClasses)",
               true, [ IsResidueClassUnionOfZInClassListRep ], 0,
               U -> Sum(List(U!.cls,cl->1/cl[2])) );

InstallOtherMethod( Density, "for the whole base ring (ResClasses)", true,
                    [ IsRing ], 0, R -> 1 );
InstallOtherMethod( Density, "for the whole base module (ResClasses)", true,
                    [ IsRowModule ], 0, R -> 1 );
InstallOtherMethod( Density, "for finite sets (ResClasses)", true,
                    [ IsList and IsCollection ], 0,
                    function ( l )
                      if   not IsFinite(DefaultRing(l[1]))
                      then return 0; else TryNextMethod(); fi;
                    end );
InstallOtherMethod( Density, "for the empty set (ResClasses)", true,
                    [ IsList and IsEmpty ], 0, l -> 0 );

#############################################################################
##
#M  IsSubset( <U>, <l> ) . . .  for a residue class union and an element list
##
InstallMethod( IsSubset,
               "for residue class union and element list (ResClasses)",
               ReturnTrue, [ IsResidueClassUnion, IsList ], 0,

  function ( U, l )
    return ForAll( Set( l ), n -> n in U );
  end );

#############################################################################
##
#M  IsSubset( <U1>, <U2> ) . .  for two residue class unions in standard rep.
##
InstallMethod( IsSubset,
               "for two residue class unions in standard rep. (ResClasses)",
               IsIdenticalObj,
               [ IsResidueClassUnionInResidueListRep,
                 IsResidueClassUnionInResidueListRep ], 0,

  function ( U1, U2 )

    local  R, m1, m2, m, r1, r2, r, allres1, allres2, allres;

    R := UnderlyingRing(FamilyObj(U1));
    m1 := U1!.m; m2 := U2!.m;
    r1 := U1!.r; r2 := U2!.r;
    if   not IsSubset(U1,U2!.included) or Intersection(U1!.excluded,U2) <> []
    then return false; fi;
    if   IsRing(R)      then m := Lcm(R,m1,m2);
    elif IsRowModule(R) then m := LatticeIntersection(m1,m2); fi;
    allres  := AllResidues(R,m);
    allres1 := Filtered(allres,n->n mod m1 in r1);
    allres2 := Filtered(allres,n->n mod m2 in r2);
    return IsSubset(allres1,allres2);
  end );

#############################################################################
##
#M  IsSubset( <U1>, <U2> ) . . .  for two residue class unions in sparse rep.
##
InstallMethod( IsSubset,
               "for two residue class unions in sparse rep. (ResClasses)",
               IsIdenticalObj,
               [ IsResidueClassUnionInClassListRep,
                 IsResidueClassUnionInClassListRep ], 0,

  function ( U1, U2 )

    if Density(U2) > Density(U1) then return false; fi; 
    if   not IsSubset(U1,U2!.included) or Intersection(U1!.excluded,U2) <> []
    then return false; fi;

    return Difference(U2,U1) = [];
  end );

#############################################################################
##
#M  IsSubset( <U1>, <U2> ) . . for two residue class unions in different rep.
##
InstallMethod( IsSubset,
               "for two residue class unions in different rep. (ResClasses)",
               IsIdenticalObj,
               [ IsResidueClassUnionInResidueListRep,
                 IsResidueClassUnionInClassListRep ], 0,
               function ( U1, U2 ) return IsSubset(SparseRep(U1),U2); end );
InstallMethod( IsSubset,
               "for two residue class unions in different rep. (ResClasses)",
               IsIdenticalObj,
               [ IsResidueClassUnionInClassListRep,
                 IsResidueClassUnionInResidueListRep ], 0,
               function ( U1, U2 ) return IsSubset(U1,SparseRep(U2)); end );

#############################################################################
##
#M  IsSubset( <R>, <U> ) . . . .  for the base ring and a residue class union
#M  IsSubset( <U>, <R> ) . . . .  for a residue class union and the base ring
##
InstallMethod( IsSubset,
               "for the base ring and a residue class union (ResClasses)",
               ReturnTrue, [ IsDomain, IsResidueClassUnion ], 0,
               function ( R, U )
                 if   R = UnderlyingRing(FamilyObj(U))
                 then return true; else TryNextMethod(); fi;
               end );

InstallMethod( IsSubset,
               "for a residue class union and the base ring (ResClasses)",
               ReturnTrue, [ IsResidueClassUnion, IsDomain ], 0,
               function ( U, R )
                 if   R = UnderlyingRing(FamilyObj(U))
                 then return U = R; else TryNextMethod(); fi;
               end );

#############################################################################
##
#M  IsSubset( Z_pi( <pi> ), Rationals ) . . . . . . . . . . .  for Z_pi and Q
##
InstallMethod( IsSubset, "for Z_pi and Rationals (ResClasses)",
               ReturnTrue, [ IsZ_pi, IsRationals ], 0, ReturnFalse );

#############################################################################
##
#S  Computing unions, intersections and differences. ////////////////////////
##
#############################################################################

#############################################################################
##
#M  Union2( <U1>, <U2> ) . . . . .  for residue class unions in standard rep.
##
InstallMethod( Union2,
               "for two residue class unions in standard rep. (ResClasses)",
               IsIdenticalObj,
               [ IsResidueClassUnionInResidueListRep,
                 IsResidueClassUnionInResidueListRep ], 0,

  function ( U1, U2 )

    local  R, m1, m2, m, r1, r2, r, included, excluded,
           r1exp, r2exp, allres;

    R := UnderlyingRing(FamilyObj(U1));
    m1 := U1!.m; m2 := U2!.m;
    r1 := U1!.r; r2 := U2!.r;
    if   IsRing(R)      then m := Lcm(R,m1,m2);
    elif IsRowModule(R) then m := LatticeIntersection(m1,m2); fi;
    included := Union(U1!.included,U2!.included);
    excluded := Difference(Union(Difference(U1!.excluded,U2),
                                 Difference(U2!.excluded,U1)),included);
    if IsIntegers(R) then
      r1exp := Concatenation(List([0..m/m1-1],i->i*m1+r1));
      r2exp := Concatenation(List([0..m/m2-1],i->i*m2+r2));
      r     := Union(r1exp,r2exp);
    else
      allres := AllResidues(R,m);
      r := Filtered(allres,n->n mod m1 in r1 or n mod m2 in r2);
    fi;
    return ResidueClassUnionNC(R,m,r,included,excluded);
  end );

#############################################################################
##
#M  Union2( <U1>, <U2> ) . . . . . .  for residue class unions in sparse rep.
##
InstallMethod( Union2,
               "for two residue class unions in sparse rep. (ResClasses)",
               IsIdenticalObj,
--> --------------------

--> maximum size reached

--> --------------------

[ Dauer der Verarbeitung: 0.36 Sekunden  (vorverarbeitet)  ]