Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  algrep.gi   Sprache: unbekannt

 
Spracherkennung für: .gi vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

#############################################################################
##
##  This file is part of GAP, a system for computational discrete algebra.
##  This file's authors include Willem de Graaf.
##
##  Copyright of GAP belongs to its developers, whose names are too numerous
##  to list here. Please refer to the COPYRIGHT file for details.
##
##  SPDX-License-Identifier: GPL-2.0-or-later
##
##  This file contains the methods for general modules over algebras.
##


#############################################################################
##
#M  PrintObj( <obj> ) . . . . . . . . . . . . . . . . for an algebra module
#M  ViewObj( <obj> ) . . . . . . . . . . . . . . . .  for an algebra module
##
InstallMethod( PrintObj,
    "for algebra module",
    true, [ IsVectorSpace and IsAlgebraModule ], 0,
    function( V )

      if HasDimension( V ) then
         Print("<", Dimension(V), "-dimensional " );
      else
         Print( "<" );
      fi;
      if IsLeftAlgebraModuleElementCollection( V ) then
          if IsRightAlgebraModuleElementCollection( V ) then
              Print("bi-module over ");
              Print( LeftActingAlgebra( V ) );
              Print( " (left) and " );
              Print( RightActingAlgebra( V ) );
              Print( " (right)>" );
          else
              Print("left-module over ");
              Print( LeftActingAlgebra( V ) );
              Print(">");
          fi;
      else
          Print("right-module over ");
          Print( RightActingAlgebra( V ) );
          Print(">");
      fi;

  end );

  InstallMethod( ViewObj,
    "for algebra module",
    true, [ IsVectorSpace and IsAlgebraModule ], 0,
    function( V )

      if HasDimension( V ) then
         Print("<", Dimension(V), "-dimensional " );
      else
         Print( "<" );
      fi;
      if IsLeftAlgebraModuleElementCollection( V ) then
          if IsRightAlgebraModuleElementCollection( V ) then
              Print("bi-module over ");
              View( LeftActingAlgebra( V ) );
              Print( " (left) and " );
              View( RightActingAlgebra( V ) );
              Print( " (right)>" );
          else
              Print("left-module over ");
              View( LeftActingAlgebra( V ) );
              Print(">");
          fi;
      else
          Print("right-module over ");
          View( RightActingAlgebra( V ) );
          Print(">");
      fi;

end );

############################################################################
##
#M  ExtRepOfObj( <elm> )  . . . . . . . . . . . .  for algebra module elements
##
InstallMethod( ExtRepOfObj,
    "for algebra module element in packed element rep",
    true,
    [ IsAlgebraModuleElement and IsPackedElementDefaultRep ], 0,
        elm -> elm![1] );

#############################################################################
##
#M  ObjByExtRep( <Fam>, <descr> ) . . . . . . . .  for algebra module elements
##
##
InstallMethod( ObjByExtRep,
    "for algebra module elements family, object",
    true,
    [ IsAlgebraModuleElementFamily, IsObject ], 0,
        function( Fam, vec )

    if Fam!.underlyingModuleEltsFam <> FamilyObj( vec ) then
        TryNextMethod();
    fi;
    return Objectify( Fam!.packedType, [ vec ] );
    end );



#############################################################################
##
#F  BasisOfAlgebraModule( <V>, <vecs> )  for space of algebra module elements
##                           and a list of elements thereof
##
##  Note that the work is delegated to a basis of the module
##  generated by the <v>![1] vectors, for <v> in <vecs>. This basis
##  is stored in the basis of the algebra module as <B>!.delegateBasis.
##
BindGlobal( "BasisOfAlgebraModule",
    function( V, vectors )
    local B, delmod, vecs;

    B:= Objectify( NewType( FamilyObj( V ),
                            IsFiniteBasisDefault and
                            IsBasisOfAlgebraModuleElementSpace and
                            IsAttributeStoringRep ),
                   rec() );
    SetUnderlyingLeftModule( B, V );
    SetBasisVectors( B, vectors );
    if IsEmpty( vectors ) then
        delmod:= VectorSpace( LeftActingDomain(V), [ ],
                         ExtRepOfObj( Zero(V) ) );
        B!.delegateBasis:= Basis( delmod );
    else
        vecs:= List( vectors, ExtRepOfObj );
        delmod:= VectorSpace( LeftActingDomain(V), vecs, "basis" );
        B!.delegateBasis:= Basis( delmod, vecs );
    fi;
    return B;
    end );


#############################################################################
##
#M  CanonicalBasis( <V> ) . . . . . .  for a space of algebra module elements
##
InstallMethod( CanonicalBasis,
    "for algebra module",
    [ IsVectorSpace and IsAlgebraModuleElementCollection ],
    function( V )
    local B, fam, vecs;

    B:= CanonicalBasis( VectorSpace( LeftActingDomain( V ),
            List( GeneratorsOfLeftModule( V ), ExtRepOfObj ) ) );
    fam:= ElementsFamily( FamilyObj( V ) );
    vecs:= List( BasisVectors( B ), x -> ObjByExtRep( fam, x ) );
    return BasisOfAlgebraModule( V, vecs );
    end );


#############################################################################
##
#M  LeftAlgebraModuleByGenerators( <A>, <op>, <gens> )
#M  LeftAlgebraModuleByGenerators( <A>, <op>, <gens>, "basis" )
##
##  The elements of an algebra module lie in the representation
##  `IsPackedElementDefaultRep': if <v> is an element of an algebra
##  module, then v![1] is an element of a vector space on which there
##  is an action of the algebra defined.
##
InstallMethod( LeftAlgebraModuleByGenerators,
    "for algebra, function of 2 args, module generators",
    true, [ IsAlgebra, IS_FUNCTION, IsHomogeneousList], 0,
    function( A, op, gens )

      local F,V;

      F:= LeftActingDomain( A );
      V:= VectorSpace( F, gens );
      return LeftAlgebraModule( A, op, V );

  end );

InstallOtherMethod( LeftAlgebraModuleByGenerators,
    "for algebra, function of 2 args, generators, string",
    true, [ IsAlgebra, IS_FUNCTION, IsHomogeneousList, IsString], 0,
    function( A, op, gens, str )

      local F,V;

      if str<>"basis" then
         Error( "Usage: LeftAlgebraModuleByGenerators( <A>, <op>, <gens>, <str>) where the last argument is the string \"basis\"" );
      fi;

      F:= LeftActingDomain( A );
      V:= VectorSpace( F, gens, str );
      return LeftAlgebraModule( A, op, V );

end );


#############################################################################
##
#M  RightAlgebraModuleByGenerators( <A>, <op>, <gens> )
#M  RightAlgebraModuleByGenerators( <A>, <op>, <gens>, "basis" )
##
##  The elements of an algebra module lie in the representation
##  `IsPackedElementDefaultRep': if <v> is an element of an algebra
##  module, then v![1] is an element of a vector space on which there
##  is an action of the algebra defined.
##
InstallMethod( RightAlgebraModuleByGenerators,
    "for algebra, function of 2 args, module generators",
    true, [ IsAlgebra, IS_FUNCTION, IsHomogeneousList], 0,
    function( A, op, gens )

      local F,V;

      F:= LeftActingDomain( A );
      V:= VectorSpace( F, gens );
      return RightAlgebraModule( A, op, V );

end );


InstallOtherMethod( RightAlgebraModuleByGenerators,
    "for algebra, function of 2 args, generators, string",
    true, [ IsAlgebra, IS_FUNCTION, IsHomogeneousList, IsString], 0,
    function( A, op, gens, str )

      local F,V;

      if str<>"basis" then
         Error( "Usage: RightAlgebraModuleByGenerators( <A>, <op>, <gens>, <str>) where the last argument is the string \"basis\"" );
      fi;

      F:= LeftActingDomain( A );
      V:= VectorSpace( F, gens, str );
      return RightAlgebraModule( A, op, V );

  end );

#############################################################################
##
#M  BiAlgebraModuleByGenerators( <A>, <B>, <opl>, <opr>, <gens> )
#M  BiAlgebraModuleByGenerators( <A>, <B>, <opl>, <opr>, <gens>, "basis" )
##
##  The elements of an algebra module lie in the representation
##  `IsPackedElementDefaultRep': if <v> is an element of an algebra
##  module, then v![1] is an element of a vector space on which there
##  is an action of the algebra defined.
##
InstallMethod( BiAlgebraModuleByGenerators,
 "for 2 algebras, function of 2 args, function of 2 args, module generators",
     true,
     [ IsAlgebra, IsAlgebra, IS_FUNCTION, IS_FUNCTION, IsHomogeneousList], 0,
    function( A, B, opl, opr, gens )

      local F,V;

      F:= LeftActingDomain( A );
      V:= VectorSpace( F, gens );
      return BiAlgebraModule( A, B, opl, opr, V );

  end );


InstallOtherMethod( BiAlgebraModuleByGenerators,
"for 2 algebras, function of 2 args, function of 2 args, generators, string",
true,
[ IsAlgebra, IsAlgebra, IS_FUNCTION, IS_FUNCTION, IsHomogeneousList, IsString],
        0,
    function( A, B, opl, opr, gens, str )

      local F,V;

      if str<>"basis" then
         Error( "Usage: BiAlgebraModuleByGenerators( <A>, <B>, <opl>, <opr>, <gens>, <str>) where the last argument is the string \"basis\"" );
      fi;

      F:= LeftActingDomain( A );
      V:= VectorSpace( F, gens, str );
      return BiAlgebraModule( A, B, opl, opr, V );

end );

#############################################################################
##
#M  LeftAlgebraModule( <A>, <op>, <V> )
##
##  The elements of an algebra module lie in the representation
##  `IsPackedElementDefaultRep': if <v> is an element of an algebra
##  module, then v![1] is an element of a vector space on which there
##  is an action of the algebra defined.
##
InstallMethod( LeftAlgebraModule,
    "for algebra, function of 2 args, underlying space",
    true, [ IsAlgebra, IS_FUNCTION, IsVectorSpace ], 0,
    function( A, op, V )

      local F,type,g,W,gens,B;

      F:= LeftActingDomain( A );
      type:= NewType( NewFamily( "AlgModElementsFam",
                                    IsLeftAlgebraModuleElement ),
                     IsPackedElementDefaultRep );
      gens:= GeneratorsOfLeftModule( V );
      if gens <> [] then
          g:= List( GeneratorsOfLeftModule( V ),
                    x -> Objectify( type, [ x ] ) );
      else
          g:= [ Objectify( type, [ Zero(V) ] ) ];
      fi;

      W:= Objectify( NewType( FamilyObj( g ),
                            IsLeftModule and IsAttributeStoringRep ),
                   rec() );
      SetLeftActingDomain( W, F );
      SetGeneratorsOfAlgebraModule( W, g );
      ElementsFamily( FamilyObj( W ) )!.left_operation:= op;
      ElementsFamily( FamilyObj( W ) )!.packedType:= type;
      ElementsFamily( FamilyObj( W ) )!.underlyingModuleEltsFam:=
                                              FamilyObj( Zero(V) );
      SetZero( ElementsFamily( FamilyObj( W ) ), Zero( g[1] ) );
      FamilyObj( W )!.leftAlgebraElementsFam:= ElementsFamily( FamilyObj(A) );
      SetIsAlgebraModule( W, true );
      SetLeftActingAlgebra( W, A );
      SetUnderlyingLeftModule( W, V );

      if HasBasis( V ) then
          B:= Objectify( NewType( FamilyObj( W ),
                      IsFiniteBasisDefault and
                      IsBasisOfAlgebraModuleElementSpace and
                      IsAttributeStoringRep ),
                      rec() );
          SetUnderlyingLeftModule( B, W );
          SetBasisVectors( B, List( Basis(V), x -> Objectify( type, [ x ] ) ));
          B!.delegateBasis:= Basis( V );
          SetDimension( W, Dimension(V) );
          SetBasis( W, B );
      fi;

      return W;

end );


#############################################################################
##
#M  RightAlgebraModule( <A>, <op>, <V> )
##
##  The elements of an algebra module lie in the representation
##  `IsPackedElementDefaultRep': if <v> is an element of an algebra
##  module, then v![1] is an element of a vector space on which there
##  is an action of the algebra defined.
##
InstallMethod( RightAlgebraModule,
    "for algebra, function of 2 args, underlying space",
    true, [ IsAlgebra, IS_FUNCTION, IsVectorSpace ], 0,
    function( A, op, V )

      local F,type,g,W,gens,B;

      F:= LeftActingDomain( A );
      type:= NewType( NewFamily( "AlgModElementsFam",
                                    IsRightAlgebraModuleElement ),
                     IsPackedElementDefaultRep );
      gens:= GeneratorsOfLeftModule( V );
      if gens <> [] then
          g:= List( GeneratorsOfLeftModule( V ),
                    x -> Objectify( type, [ x ] ) );
      else
          g:= [ Objectify( type, [ Zero(V) ] ) ];
      fi;

      W:= Objectify( NewType( FamilyObj( g ),
                            IsLeftModule and IsAttributeStoringRep ),
                   rec() );
      SetLeftActingDomain( W, F );
      SetGeneratorsOfAlgebraModule( W, g );
      ElementsFamily( FamilyObj( W ) )!.right_operation:= op;
      ElementsFamily( FamilyObj( W ) )!.packedType:= type;
      ElementsFamily( FamilyObj( W ) )!.underlyingModuleEltsFam:=
                                              FamilyObj( Zero(V) );
      SetZero( ElementsFamily( FamilyObj( W ) ), Zero( g[1] ) );
      FamilyObj( W )!.rightAlgebraElementsFam:= ElementsFamily( FamilyObj(A) );
      SetIsAlgebraModule( W, true );
      SetRightActingAlgebra( W, A );
      SetUnderlyingLeftModule( W, V );

      if HasBasis( V ) then
          B:= Objectify( NewType( FamilyObj( W ),
                      IsFiniteBasisDefault and
                      IsBasisOfAlgebraModuleElementSpace and
                      IsAttributeStoringRep ),
                      rec() );
          SetUnderlyingLeftModule( B, W );
          SetBasisVectors( B, List( Basis(V), x -> Objectify( type, [ x ] ) ));
          B!.delegateBasis:= Basis( V );
          SetDimension( W, Dimension(V) );
          SetBasis( W, B );
      fi;

      return W;

end );


#############################################################################
##
#M  BiAlgebraModule( <A>, <B>, <opl>, <opr>, <V> )
##
##  The elements of an algebra module lie in the representation
##  `IsPackedElementDefaultRep': if <v> is an element of an algebra
##  module, then v![1] is an element of a vector space on which there
##  is an action of the algebra defined.
##
InstallMethod( BiAlgebraModule,
         "for 2 algebras, function of 2 args, function of 2 args, module generators",
     true,
     [ IsAlgebra, IsAlgebra, IS_FUNCTION, IS_FUNCTION, IsVectorSpace], 0,
    function( A, B, opl, opr, V )

      local   F,  type,  g,  W, Ba, gens;

      F:= LeftActingDomain( A );
      type:= NewType( NewFamily( "AlgModElementsFam",
                          IsLeftAlgebraModuleElement and
                          IsRightAlgebraModuleElement ),
                       IsPackedElementDefaultRep );
      gens:= GeneratorsOfLeftModule( V );
      if gens <> [] then
          g:= List( GeneratorsOfLeftModule( V ),
                    x -> Objectify( type, [ x ] ) );
      else
          g:= [ Objectify( type, [ Zero(V) ] ) ];
      fi;

      W:= Objectify( NewType( FamilyObj( g ),
                            IsLeftModule and IsAttributeStoringRep ),
                   rec() );
      SetLeftActingDomain( W, F );
      SetGeneratorsOfAlgebraModule( W, g );
      ElementsFamily( FamilyObj( W ) )!.left_operation:= opl;
      ElementsFamily( FamilyObj( W ) )!.right_operation:= opr;
      ElementsFamily( FamilyObj( W ) )!.packedType:= type;
      ElementsFamily( FamilyObj( W ) )!.underlyingModuleEltsFam:=
                                              FamilyObj( Zero(V) );
      FamilyObj( W )!.leftAlgebraElementsFam:= ElementsFamily( FamilyObj(A) );
      FamilyObj( W )!.rightAlgebraElementsFam:= ElementsFamily( FamilyObj(B) );
      SetIsAlgebraModule( W, true );
      SetLeftActingAlgebra( W, A );
      SetRightActingAlgebra( W, B );
      SetZero( ElementsFamily( FamilyObj( W ) ), Zero( g[1] ) );
      SetUnderlyingLeftModule( W, V );

      if HasBasis( V ) then
          Ba:= Objectify( NewType( FamilyObj( W ),
                      IsFiniteBasisDefault and
                      IsBasisOfAlgebraModuleElementSpace and
                      IsAttributeStoringRep ),
                      rec() );
          SetUnderlyingLeftModule( Ba, W );
          SetBasisVectors( Ba, List( Basis(V), x -> Objectify( type, [ x ])));
          Ba!.delegateBasis:= Basis( V );
          SetDimension( W, Dimension(V) );
          SetBasis( W, Ba );
      fi;

      return W;

end );


############################################################################
##
#R  IsMutableBasisViaUnderlyingMutableBasisRep( <B> )
##
DeclareRepresentation( "IsMutableBasisViaUnderlyingMutableBasisRep",
    IsComponentObjectRep,
        [ "moduleElementsFam", "underlyingMutableBasis" ] );

############################################################################
##
#M  MutableBasis( <R>, <vectors> )
#M  MutableBasis( <R>, <vectors>, <zero> )
##
##  Mutable bases of algebra modules delegate the work to corresponding
##  mutable bases of the underlying vector spaces.
##
InstallMethod( MutableBasis,
    "for ring and vectors",
    true,
    [ IsRing, IsAlgebraModuleElementCollection ], 0,
    function( R, vectors )
    local B;

    if ForAll( vectors, IsZero ) then
      return MutableBasis( R, [], vectors[1] );
    fi;

    B:= rec(
             moduleElementsFamily:= FamilyObj( vectors[1] ),
             underlyingMutableBasis:= MutableBasis( R,
                                        List( vectors, ExtRepOfObj ) )
            );

    return Objectify( NewType( FamilyObj( vectors ),
                                 IsMutableBasis
                             and IsMutable
                             and IsMutableBasisViaUnderlyingMutableBasisRep ),
                      B );
end );

InstallOtherMethod( MutableBasis,
    "for ring, list and zero",
    true,
    [ IsRing, IsList, IsAlgebraModuleElement ], 0,
    function( R, vectors, zero )
    local B;

    B:= rec(
             moduleElementsFamily:= FamilyObj( zero ),
             underlyingMutableBasis:= MutableBasis( R,
                                        List( vectors, ExtRepOfObj ),
                                        ExtRepOfObj( zero ) )
            );

    return Objectify( NewType( CollectionsFamily( FamilyObj( zero ) ),
                                   IsMutableBasis
                               and IsMutable
                               and IsMutableBasisViaUnderlyingMutableBasisRep ),
                      B );
end );

#############################################################################
##
#M  PrintObj( <MB> ) . . . . . . . . . . . . . . . . . .  view a mutable basis
##
InstallMethod( PrintObj,
    "for mutable basis with underlying mutable basis",
    true,
    [ IsMutableBasis and IsMutableBasisViaUnderlyingMutableBasisRep ], 0,
    function( MB )
    Print( "<mutable basis with " );
    Print( NrBasisVectors( MB ), " vectors>" );
    end );


############################################################################
##
#M  BasisVectors( <MB> )
#M  CloseMutableBasis( <MB>, <v> )
#M  IsContainedInSpan( <MB>, <v> )
##
InstallOtherMethod( BasisVectors,
    "for mutable basis with underlying mutable basis",
    true,
    [ IsMutableBasis and IsMutableBasisViaUnderlyingMutableBasisRep ], 0,
    function( MB )
    # return the basis vectors of the underlying mutable basis, wrapped up.
    return List( BasisVectors( MB!.underlyingMutableBasis ), x ->
       ObjByExtRep( MB!.moduleElementsFamily, x ));
end );

InstallMethod( CloseMutableBasis,
    "for mutable basis with underlying mutable basis, and vector",
    IsCollsElms,
    [ IsMutableBasis and IsMutable and
      IsMutableBasisViaUnderlyingMutableBasisRep, IsVector ], 0,
    function( MB, v )
    return CloseMutableBasis( MB!.underlyingMutableBasis, ExtRepOfObj( v ) );

end );

InstallMethod( IsContainedInSpan,
    "for mutable basis with underlying mutable basis, and vector",
    IsCollsElms,
    [ IsMutableBasis and IsMutable and
      IsMutableBasisViaUnderlyingMutableBasisRep, IsVector ], 0,
    function( MB, v )

       return IsContainedInSpan( MB!.underlyingMutableBasis,
                   ExtRepOfObj( v ) );
end );

#############################################################################
##
#M  ActingAlgebra( <V> ) . . . . . . . . . . . . for an algebra module
##
InstallMethod( ActingAlgebra,
        "for an algebra module",
        true, [ IsAlgebraModule ], 0,
        function( V )

    if IsLeftAlgebraModuleElementCollection( V ) then
        if IsRightAlgebraModuleElementCollection( V ) then
            Error("ActingAlgebra is not defined for bi-modules");
        else
            return LeftActingAlgebra( V );
        fi;
    else
        return RightActingAlgebra( V );
    fi;
end );


#############################################################################
##
#M  PrintObj( <obj> ) . . . . . . . . . . . . . . . for algebra module element
##
InstallMethod( PrintObj,
    "for algebra module element in packed representation",
    true, [ IsAlgebraModuleElement and IsPackedElementDefaultRep], 0,
    function( v ) Print( v![1] ); end );

#############################################################################
##
#M  \=( <u>, <v> ) . . . . . . . . . . . . . . . for algebra module elements
#M  \<( <u>, <v> ) . . . . . . . . . . . . . . . for algebra module elements
#M  \+( <u>, <v> ) . . . . . . . . . . . . . . . for algebra module elements
#M  AdditiveInverseOp( <u> ) . .. . . . . . . . . . . . . . . for an algebra module element
#M  \*( <u>, <scal> ) . . . . . . for an algebra module element and a scalar
#M  \*( <scal>, <u> ) . . . . . . for a scalar and an algebra module element
#M  ZeroOp( <u> ) . . . . . . . . . . . . . . . .for an algebra module element
##
##

InstallMethod(\=,
    "for two algebra module elements in packed representation",
    IsIdenticalObj, [ IsAlgebraModuleElement and IsPackedElementDefaultRep,
              IsAlgebraModuleElement and IsPackedElementDefaultRep ], 0,
    function( u, v ) return u![1] = v![1]; end );

InstallMethod(\<,
    "for two algebra module elements in packed representation",
    IsIdenticalObj, [ IsAlgebraModuleElement and IsPackedElementDefaultRep,
              IsAlgebraModuleElement and IsPackedElementDefaultRep ], 0,
    function( u, v ) return u![1] < v![1]; end );

InstallMethod(\+,
    "for two algebra module elements in packed representation",
    IsIdenticalObj, [ IsAlgebraModuleElement and IsPackedElementDefaultRep,
              IsAlgebraModuleElement and IsPackedElementDefaultRep ], 0,
    function( u, v ) return ObjByExtRep( FamilyObj( u ), u![1]+v![1] ); end );

InstallMethod(\+,
    "for an algebra module element in packed representation and a vector",
    true, [ IsAlgebraModuleElement and IsPackedElementDefaultRep,
              IsVector ], 0,
    function( u, v ) return ObjByExtRep( FamilyObj( u ), u![1]+v ); end );


InstallMethod(\+,
    "for a vector and an algebra module element in packed representation",
    true, [ IsVector,
            IsAlgebraModuleElement and IsPackedElementDefaultRep ], 0,
    function( u, v ) return ObjByExtRep( FamilyObj( v ), u+v![1] ); end );

InstallMethod( AdditiveInverseOp,
    "for an algebra module element in packed representation",
    true, [ IsAlgebraModuleElement and IsPackedElementDefaultRep ], 0,
    function( u ) return ObjByExtRep( FamilyObj(u),  -u![1] ); end );

InstallMethod( \*,
    "for an algebra module element in packed representation and a scalar",
    true, [ IsAlgebraModuleElement and IsPackedElementDefaultRep,
            IsScalar ], 0,
    function( u, scal ) return ObjByExtRep( FamilyObj(u), scal*u![1] );
    end );


InstallMethod( \*,
    "for a scalar and an algebra module element in packed representation",
    true, [ IsScalar, IsAlgebraModuleElement and IsPackedElementDefaultRep],0,
    function( scal, u ) return ObjByExtRep( FamilyObj(u), scal*u![1] );
    end );

InstallMethod( ZeroOp,
    "for an algebra module element in packed representation",
    true, [ IsAlgebraModuleElement and IsPackedElementDefaultRep ], 0,
    function( u ) return ObjByExtRep( FamilyObj(u), 0*u![1] ); end );


#############################################################################
##
#M  \*( <obj>, <vec> ) . . . . . . . . . . . for a Lie object and a row vector
#M  \*( <vec>, <obj> ) . . . . . . . . . . . for a row vector and a Lie object
##
##
InstallMethod( \*,
    "for Lie object and row vector",
    true, [ IsLieObject and IsPackedElementDefaultRep, IsRowVector ], 0,
    function( m, v )
      return m![1]*v;
    end );

InstallMethod( \*,
    "for row vector and Lie object",
    true, [ IsRowVector, IsLieObject and IsPackedElementDefaultRep ], 0,
    function( v, m )
      return v*m![1];
    end );

#############################################################################
##
#M  \^( <a>, <v> ) . . . . . . . . . . . . for algebra elt, and elt of module
##
##  The action of an algebra element <a> on an element <v> of a left module
##  is denoted by <a>^<v>.
##
InstallOtherMethod( \^,
    "for an algebra element and an element of an algebra module",
    function( F1, F2 )
         return CollectionsFamily( F2 )!.leftAlgebraElementsFam = F1;
    end,
    [ IsRingElement,
          IsLeftAlgebraModuleElement and IsPackedElementDefaultRep ], 0,
    function( x, u  )
        return ObjByExtRep( FamilyObj( u ),
                        FamilyObj( u )!.left_operation(x,u![1]));
end );

#############################################################################
##
#M  \^( <a>, <v> ) . . . . . . . . . . . . for algebra elt, and elt of module
##
##  The action of an algebra element <a> on an element <v> of a right module
##  is denoted by <v>^<a>.
##
InstallOtherMethod( \^,
    "for an algebra element and an element of an algebra module",
    function( F1, F2 )
         return CollectionsFamily( F1 )!.rightAlgebraElementsFam = F2;
    end,
    [ IsRightAlgebraModuleElement and IsPackedElementDefaultRep,
          IsRingElement ], 0,
    function( u, x  )
        return ObjByExtRep( FamilyObj( u ),
                       FamilyObj( u )!.right_operation(u![1],x));
end );

#############################################################################
##
#M  Basis( <V> )  . . . . . . . . . . . . . . . . . . . for an algebra module
#M  Basis( <V> )  . . . . . . . . . .  for a space of algebra module elements
##
InstallMethod( Basis,
    "for an algebra module",
    true, [ IsFreeLeftModule and IsAlgebraModule ], 0,
    function( V )

      local A, gens, F, fam, B, vecs, from, op, ready;

      gens:= GeneratorsOfAlgebraModule( V );
      F:= LeftActingDomain( V );
      fam:= ElementsFamily( FamilyObj( V ) );
      if IsLeftAlgebraModuleElementCollection( V ) then
          if IsRightAlgebraModuleElementCollection( V ) then

              # We let the algebra act alternatingly from the left
              # and the right.
              vecs:= List( gens, ExtRepOfObj );
              from:= "left";
              op:= fam!.left_operation;
              ready:= false;
              A:= LeftActingAlgebra( V );

              while not ready do
                  B:= MutableBasisOfClosureUnderAction( F,
                              GeneratorsOfAlgebra( A ),
                              from,
                              vecs,
                              op,
                              ExtRepOfObj( Zero(V) ), "infinity" );
                  if Length( BasisVectors( B ) ) = Length( vecs ) and
                     from = "right" then
                      # from = "right", means that we acted both from the
                      # left and the right, and we did not find anything new.
                      # So we have a set of vectors closed under both the
                      # left and the right action.
                      ready:= true;
                  else
                      vecs:= BasisVectors( B );
                      if from = "left" then
                          from:= "right";
                          op:= fam!.right_operation;
                          A:= RightActingAlgebra( V );
                      else
                          from:= "left";
                          op:= fam!.left_operation;
                          A:= LeftActingAlgebra( V );
                      fi;
                  fi;

              od;

              vecs:= List( vecs, x -> ObjByExtRep( fam, x ) );
              SetDimension( V, Length( vecs ) );
              return BasisOfAlgebraModule( V, vecs );

          else
              from:= "left";
              op:= fam!.left_operation;
              A:= LeftActingAlgebra( V );
          fi;
      else
          from:= "right";
          op:= fam!.right_operation;
          A:= RightActingAlgebra( V );
      fi;
      B:= MutableBasisOfClosureUnderAction( F,
                  GeneratorsOfAlgebra( A ),
                  from,
                  List( gens, ExtRepOfObj ),
                  op,
                  ExtRepOfObj( Zero(V) ), "infinity" );
      vecs:= List( BasisVectors(B), x -> ObjByExtRep( fam, x ) );
      SetDimension( V, Length( vecs ) );
      return BasisOfAlgebraModule( V, vecs );
end );

InstallMethod( Basis,
    "for a space of algebra module elements",
    true, [ IsFreeLeftModule and IsAlgebraModuleElementCollection ], 0,
    function( V )

    local   g,  fam,  B,  vecs;

    if HasIsAlgebraModule( V ) and IsAlgebraModule( V ) then
        TryNextMethod();
    fi;

    # In this case `V' is just a vector space of algebra module
    # elements, so there is no need to apply the action of an
    # algebra to get the basis.

    g:= List( GeneratorsOfLeftModule( V ), ExtRepOfObj );
    fam:= ElementsFamily( FamilyObj( V ) );
    B:= Basis( VectorSpace( LeftActingDomain( V ), g ) );
    vecs:= List( BasisVectors(B), x -> ObjByExtRep( fam, x ) );
    return BasisOfAlgebraModule( V, vecs );
end );




##############################################################################
##
#M  Coefficients( <B>, <v> ). . . . . . for basis of a space of algebra
##                                      module elements and vector
##
InstallMethod( Coefficients,
    "for basis of a space of algebra module elements, and algebra module element",
    true, [ IsBasisOfAlgebraModuleElementSpace,
            IsAlgebraModuleElement and IsPackedElementDefaultRep ], 0,
    function( B, v )

      return Coefficients( B!.delegateBasis, v![1] );
end );

##############################################################################
##
#M  Basis( <V>, <vecs> )
#M  BasisNC( <V>, <vecs> )
##
##  The basis of the space of algebra module elements <V> consisting of the
##  vectors in <vecs>.
##  In the NC version it is not checked whether the elements of <vecs> are
##  linearly independent.
##
InstallMethod( Basis,
    "for a space of algebra module elements and a collection of algebra module elements",
    IsIdenticalObj,
    [ IsFreeLeftModule and IsAlgebraModuleElementCollection,
      IsAlgebraModuleElementCollection and IsList ], 0,
    function( V, vectors )

     local W;

      if not ForAll( vectors, x -> x in V ) then return fail; fi;

      W:= VectorSpace( LeftActingDomain(V), List( vectors, ExtRepOfObj ) );
      if Dimension( W ) <> Length( vectors ) then return fail; fi;
      return BasisOfAlgebraModule( V, vectors );
end );


InstallMethod( BasisNC,
    "for a space of algebra module elements and a collection of algebra module elements",
    IsIdenticalObj,
    [ IsFreeLeftModule and IsAlgebraModuleElementCollection,
      IsAlgebraModuleElementCollection and IsList ], 0,
    function( V, vectors )

      return BasisOfAlgebraModule( V, vectors );
end );

##########################################################################
##
#M  IsFiniteDimensional( <V> ) . . . . . . .  . for a space of algebra module
##                                              elements
##
InstallMethod( IsFiniteDimensional,
        "for a space of algebra module elements",
        true, [ IsFreeLeftModule and IsAlgebraModuleElementCollection ], 0,
        function( V )

    return Length( Basis( V ) ) < infinity;
end );

##########################################################################
##
#M  GeneratorsOfLeftModule( <V> ) . . . . . . .  . for a space of algebra
##                                                 module elements
##
InstallMethod( GeneratorsOfLeftModule,
        "for a space of algebra module elements",
        true, [ IsFreeLeftModule and IsAlgebraModuleElementCollection ], 0,
        function( V )

    return BasisVectors( Basis( V ) );
end );

############################################################################
##
#M  SubAlgebraModule( <V>, <gens> [,<"basis">] )
##
##  Is the submodule of <V> generated by <gens>.
##
BindGlobal("_SubAlgebraModuleHelper", function( V, gens, args... )
    local sub, isBasis;

    if Length(args)>0 and args[1]<>"basis" then
        Error( "Usage: SubAlgebraModule( <V>, <gens>, <str>) where the last argument is string \"basis\"" );
    fi;
    isBasis := Length(gens) = 0 or (Length(args)>0 and args[1]="basis");

    sub:= Objectify( NewType( FamilyObj( V ),
                     IsLeftModule and IsAttributeStoringRep ), rec() );
    SetIsAlgebraModule( sub, true );
    SetLeftActingDomain( sub, LeftActingDomain( V ) );
    SetGeneratorsOfAlgebraModule( sub, gens );

    if HasIsFiniteDimensional( V ) and IsFiniteDimensional( V ) then
        SetIsFiniteDimensional( sub, true );
    fi;

    if IsLeftAlgebraModuleElementCollection( V ) then
        SetLeftActingAlgebra( sub, LeftActingAlgebra( V ) );
    fi;

    if IsRightAlgebraModuleElementCollection( V ) then
        SetRightActingAlgebra( sub, RightActingAlgebra( V ) );
    fi;

    if isBasis then
        SetGeneratorsOfLeftModule( sub, gens );
        SetBasis( sub, BasisOfAlgebraModule( sub, gens ) );
        SetDimension( sub, Length( gens ) );
    fi;

    return sub;
end );

InstallMethod( SubAlgebraModule,
   "for algebra module, and a list of submodule generators",
   IsIdenticalObj,
   [ IsFreeLeftModule and IsAlgebraModule,
     IsAlgebraModuleElementCollection and IsList ],
   _SubAlgebraModuleHelper );

InstallOtherMethod( SubAlgebraModule,
   "for algebra module, and an empty list of submodule generators",
   [ IsFreeLeftModule and IsAlgebraModule,
     IsEmpty and IsList ],
   _SubAlgebraModuleHelper );

InstallOtherMethod( SubAlgebraModule,
   "for algebra module, and a list of submodule generators, and string",
   IsFamFamX,
   [ IsFreeLeftModule and IsAlgebraModule,
     IsAlgebraModuleElementCollection and IsList,
     IsString ],
   _SubAlgebraModuleHelper );

InstallOtherMethod( SubAlgebraModule,
   "for algebra module, and an empty list of submodule generators, and string",
   [ IsFreeLeftModule and IsAlgebraModule,
     IsEmpty and IsList,
     IsString ],
   _SubAlgebraModuleHelper );

##############################################################################
##
#M  LeftModuleByHomomorphismToMatAlg( <A>, <f> ) . . for algebra and hom to
##                                                   matrix algebra
##
InstallMethod( LeftModuleByHomomorphismToMatAlg,
   "for an algebra and a homomorphism to a matrix algebra",
   true, [ IsAlgebra, IsAlgebraHomomorphism ], 0,
   function( A, f )

     local zero,bas;

     if not A = Source(f) then
        Error( "<A> must be the source of the homomorphism <f>" );
     fi;

     zero:= Zero( Range( f ) );
     if not IsMatrix( zero ) then
        Error( "the range of <f> must be a matrix algebra" );
     fi;

     bas:= IdentityMat( Length(zero), LeftActingDomain(A) );
     return LeftAlgebraModuleByGenerators( A,
                      function( x, v ) return Image( f, x )*v; end,
                      bas, "basis");


   end );

##############################################################################
##
#M  RightModuleByHomomorphismToMatAlg( <A>, <f> ) . . for algebra and hom to
##                                                    matrix algebra
##
InstallMethod( RightModuleByHomomorphismToMatAlg,
   "for an algebra and a homomorphism to a matrix algebra",
   true, [ IsAlgebra, IsAlgebraHomomorphism ], 0,
   function( A, f )

     local zero,bas;

     if not A = Source(f) then
        Error( "<A> must be the source of the homomorphism <f>" );
     fi;

     zero:= Zero( Range( f ) );
     if not IsMatrix( zero ) then
        Error( "the range of <f> must be a matrix algebra" );
     fi;

     bas:= IdentityMat( Length(zero), LeftActingDomain(A) );
     return RightAlgebraModuleByGenerators( A,
                    function( v, x ) return v*Image( f, x ); end,
                      bas, "basis");


   end );

##############################################################################
##
#M  AdjointModule( <A> ) . . . . . . . . . . . . . . . . . . . for an algebra
##
##
InstallMethod( AdjointModule,
   "for an algebra",
   true, [ IsAlgebra ], 0,
    function( A )

    return LeftAlgebraModule( A, function( a, b ) return a*b; end, A);

end );


#############################################################################
##
#M  FaithfulModule( <A> ) . . . . . . . . . . . . for an associative algebra
##
##
InstallMethod( FaithfulModule,
   "for an algebra",
   true, [ IsAlgebra ], 0,
   function( A )

    local   bb,  n,  BA,  F,  bv,  i,  M,  j,  col, B;

    if One( A ) <> fail then
        # the adjoint module is faithful.
        return AdjointModule( A );
    fi;

    # construct the adjoint representation of A on the algebra
    # gotten from A by adding a one (Dorroh extension).

    bb:= [];
    n:= Dimension( A );
    BA:= Basis( A );
    F:= LeftActingDomain( A );
    bv:= BasisVectors( BA );

    for i in [1..n] do
        M:=[];
        for j in [1..n] do
            col:= ShallowCopy( Coefficients( BA, bv[i] * bv[j] ) );
            col[n+1]:= Zero( F );
            Add( M, col );
        od;
        col:= [ 1 .. n+1 ] * Zero( F );
        col[i]:= One( F );
        Add( M, col );
        Add( bb, TransposedMat( M ) );
    od;

    B:= Algebra( Rationals, bb, "basis" );

    return LeftModuleByHomomorphismToMatAlg( A,
                   AlgebraHomomorphismByImages( A, B, bv, bb ) );

end );



#############################################################################
##
#M  ModuleByRestriction( <V>, <sub> ) . . .for an alg module and a subalgebra
#M  ModuleByRestriction( <V>, <sub>, <sub> ) for a bi-alg module and
##                                           two subalgebras
##
InstallMethod( ModuleByRestriction,
   "for an algebra module and a subalgebra",
   true, [ IsAlgebraModule, IsAlgebra ], 0,
   function( V, sub )

    local   op, M;

    if IsLeftAlgebraModuleElementCollection( V ) then
        if IsRightAlgebraModuleElementCollection( V ) then
            return ModuleByRestriction( V, sub, sub );
        fi;
        op:= ElementsFamily( FamilyObj( V ) )!.left_operation;
        M:= UnderlyingLeftModule( V );
        if HasBasis( V ) and not HasBasis( M ) then
           if IsBound( Basis(V)!.delegateBasis ) then
              SetBasis( M, Basis(V)!.delegateBasis );
           fi;
        fi;
        return LeftAlgebraModule( sub, op, UnderlyingLeftModule( V ) );
    else
        op:= ElementsFamily( FamilyObj( V ) )!.right_operation;
        M:= UnderlyingLeftModule( V );
        if HasBasis( V ) and not HasBasis( M ) then
           if IsBound( Basis(V)!.delegateBasis ) then
              SetBasis( M, Basis(V)!.delegateBasis );
           fi;
        fi;
        return RightAlgebraModule( sub, op, M );
    fi;

end );


InstallOtherMethod( ModuleByRestriction,
   "for a bi-algebra module and a subalgebra and a subalgebra",
    true, [ IsAlgebraModule, IsAlgebra, IsAlgebra ], 0,
    function( V, subl, subr )

    local  basis, gens, M;

    if IsLeftAlgebraModuleElementCollection( V ) then
        if IsRightAlgebraModuleElementCollection( V ) then
           M:= UnderlyingLeftModule( V );
           if HasBasis( V ) and not HasBasis( M ) then
              if IsBound( Basis(V)!.delegateBasis ) then
                 SetBasis( M, Basis(V)!.delegateBasis );
              fi;
           fi;
            return BiAlgebraModule( subl, subr,
                        ElementsFamily( FamilyObj( V ) )!.left_operation,
                        ElementsFamily( FamilyObj( V ) )!.right_operation,
                               M );
        else
            Error( "<V> must be a bi-module");
        fi;
    else
        Error( "<V> must be a bi-module");
    fi;

end );


########################################################################
##
#M  NaturalHomomorphismBySubAlgebraModule( <V>, <W> )
##
##
InstallMethod( NaturalHomomorphismBySubAlgebraModule,
        "for algebra module and a submodule",
        IsIdenticalObj, [ IsAlgebraModule, IsAlgebraModule ], 0,
        function( V, W )

    local   f,  quot,  left_op,  right_op,  bb,  qmod,  imgs, nathom;

    f:= NaturalHomomorphismBySubspace( V, W );
    quot:= ImagesSource( f );

    if IsTrivial(quot) then
        quot := SubAlgebraModule( V, [], "basis" );
        nathom := ZeroMapping( V, quot );
        SetIsSurjective( nathom, true );
        SetImagesSource(nathom, quot);
        SetKernelOfAdditiveGeneralMapping( nathom, W );
        return nathom;
    fi;

    imgs:= List( Basis( V ), x -> Coefficients( Basis( quot ),
                   ImagesRepresentative(f,x)));

    # We make V/W into an algebra module and produce new linear map from
    # V into this module, doing exactly the same as f does.

    if IsLeftAlgebraModuleElementCollection( V ) then
        if IsRightAlgebraModuleElementCollection( V ) then
            left_op:= function( x, v )
                 return ImagesRepresentative( f, x^PreImagesRepresentative( f, v ) );
            end;
            right_op:= function( v, x )
                 return ImagesRepresentative( f, PreImagesRepresentative( f, v )^x );
            end;
            qmod:= BiAlgebraModule( LeftActingAlgebra( V ),
                           RightActingAlgebra( V ),
                           left_op, right_op, quot );
        else
            left_op:= function( x, v )
                 return ImagesRepresentative( f, x^PreImagesRepresentative( f, v ) );
            end;
            qmod:= LeftAlgebraModule( LeftActingAlgebra( V ),
                           left_op, quot);
        fi;
    else
        right_op:= function( v, x )
             return ImagesRepresentative( f, PreImagesRepresentative( f, v )^x );
        end;
        qmod:= RightAlgebraModule( RightActingAlgebra( V ),
                       right_op, quot );
    fi;

    nathom:= LeftModuleHomomorphismByMatrix( Basis( V ), imgs, Basis( qmod ) );
    SetIsSurjective( nathom, true );

    # Enter the preimages info.
    nathom!.basisimage:= Basis( qmod );
    if IsBound(f!.preimagesbasisimage) then
        nathom!.preimagesbasisimage:= f!.preimagesbasisimage;
    fi;
    SetKernelOfAdditiveGeneralMapping( nathom, W );

    # Run the implications for the factor.
    UseFactorRelation( V, W, qmod );

    return nathom;

end );

#############################################################################
##
#M  \/( <V>, <W> )  . . . . . . .  factor of an algebra module by a submodule
#M  \/( <V>, <vectors> )  . . . .  factor of an algebra module by a submodule
##
InstallOtherMethod( \/,
        "for an algebra module and collection",
        IsIdenticalObj,
        [ IsVectorSpace and IsAlgebraModule, IsCollection ], 0,
        function( V, vectors )
    if IsAlgebraModule( vectors ) then
        TryNextMethod();
    else
        return V / SubAlgebraModule( V, vectors );
    fi;
end );

InstallOtherMethod( \/,
        "for two algebra modules",
        IsIdenticalObj,
        [ IsVectorSpace and IsAlgebraModule, IsAlgebraModule ], 0,
        function( V, W )
    return ImagesSource( NaturalHomomorphismBySubAlgebraModule( V, W ) );
end );


##############################################################################
##
#M  MatrixOfAction( <B>, <x> )
#M  MatrixOfAction( <B>, <x>, <side> )
##
InstallMethod( MatrixOfAction,
        "for a basis of an algebra module and an algebra element",
        true, [ IsBasisOfAlgebraModuleElementSpace, IsObject ], 0,
        function( B, x )


    if IsRightAlgebraModuleElementCollection( B ) then
        if IsLeftAlgebraModuleElementCollection( B ) then
            Error( "usage MatrixOfAction( <B>, <x>, <side> )" );
        fi;

        return List( B, b -> Coefficients( B, b^x ) );
    else
        return TransposedMatDestructive(
                       List( B, b -> ShallowCopy( Coefficients( B, x^b ) ) ) );
    fi;

end );

InstallOtherMethod( MatrixOfAction,
        "for a basis of an algebra module, an algebra element and a side",
        true, [ IsBasisOfAlgebraModuleElementSpace, IsObject, IsObject ], 0,
        function( B, x, side )


    if side = "right" then
        return List( B, b -> Coefficients( B, b^x ) );
    else
        return TransposedMatDestructive(
                       List( B, b -> ShallowCopy( Coefficients( B, x^b ) ) ) );
    fi;

end );


##############################################################################
##
#R  IsMonomialElementRep( <obj> )
##
##  A monomial element is a list of two components: the first component
##  is a list of the form [ t1, c1, t2, c2...] where the ci are coefficients,
##  and the ti are monomials (where the meaning of the word `monomial'
##  may differ according to the context).
##  The second component is `true' or `false',
##  `true' if the monomial element is in normal form, `false' otherwise.
##
DeclareRepresentation( "IsMonomialElementRep", IsPositionalObjectRep, [1,2] );


############################################################################
##
#M  ObjByExtRep( <fam>, <list> ) . . . for a MonomialElementFamily and a list
#M  ExtRepOfObj( <t> )  . . . . . . .  for a monomial element in monomial rep.
##
InstallMethod( ObjByExtRep,
        "for a family of monomial elements and a list",
        true, [ IsMonomialElementFamily, IsList] , 0,
        function( fam, list )
    return Objectify( fam!.monomialElementDefaultType,
                   [ Immutable( list ), false ] );
end );


InstallMethod( ExtRepOfObj,
        "for a monomial element",
        true, [ IsMonomialElement and IsMonomialElementRep ] , 0,
        function( t )  return t![1];
end );

##############################################################################
##
#M  ZeroOp( <m> ) . . . . . . . . . . . . . . for a monomial element
#M  \+( <m1>, <m2> )  . . . . . . . . . . . . for two monomial elements
#M  AdditiveInverseOp( <m> ) . . . . . . . . . . . . . . . for a monomial element
#M  \*( <m>, <scal> ) . . . . . . . . . . for a monomial element and a scalar
#M  \*( <scal>, <m> ) . . . . . . . . . . for scalar and a monomial element
#M  \<( <m1>, <m2> ) . . . . . . . . . . . .  for two monomial elements
#M  \=( <m1>, <m2> ) . . . . . . . . . . . .  for two monomial elements
##
InstallMethod( ZeroOp,
        "for monomial elements",
        true, [ IsMonomialElement and IsMonomialElementRep ], 0,
        function( u )
    local res;
    res:= ObjByExtRep( FamilyObj( u ),
                  [ [], FamilyObj(u)!.zeroCoefficient ] );
    res![2]:= true;
    return res;
end );


InstallMethod(\+,
        "for monomial elements",
        IsIdenticalObj,
        [ IsMonomialElement and IsMonomialElementRep,
          IsMonomialElement and IsMonomialElementRep], 0,
        function( u, v )

    local lu,lv,zero, sum, res;

    # We assume that the monomials in the monomial elements are sorted
    # according to \<.

    lu:= u![1];
    lv:= v![1];
    zero:= FamilyObj( u )!.zeroCoefficient;
    sum:=  ZippedSum( lu, lv, zero, [\<,\+] );
    if Length( sum ) >= 2 then
        if sum[1] = [] and sum[2] = zero then
            Remove( sum, 1 );
            Remove( sum, 1 );
        fi;
    fi;
    if sum = [ ] then sum:= [ [], zero ]; fi;
    res:= ObjByExtRep( FamilyObj( u ), sum );
    if u![2] and v![2] then res![2]:= true; fi;
    return res;

end );

InstallMethod( AdditiveInverseOp,
        "for a monomial element",
        true,
        [ IsMonomialElement and IsMonomialElementRep ], 0,
        function( u )

    local lu,k,res;

    lu:= ShallowCopy( u![1] );
    for k in [2,4..Length(lu)] do
        lu[k]:= -lu[k];
    od;
    res:= ObjByExtRep( FamilyObj( u ), lu );
    if u![2] then res![2]:= true; fi;
    return res;

end );


InstallMethod(\*,
        "for a monomial element and a scalar",
        true,
        [ IsMonomialElement and IsMonomialElementRep, IsRingElement ], 0,
        function( u, scal )
    local lu,k,res;

    if IsZero(scal) then return Zero(u); fi;
    lu:= ShallowCopy( u![1] );
    for k in [2,4..Length(lu)] do
        lu[k]:= scal*lu[k];
    od;
    res:= ObjByExtRep( FamilyObj( u ), lu );
    if u![2] then res![2]:= true; fi;
    return res;

end );

InstallMethod(\*,
        "for a scalar and a monomial element",
        true,
        [ IsRingElement, IsMonomialElement and IsMonomialElementRep ], 0,
        function( scal, u  )
    local lu,k,res;

    if IsZero(scal) then return Zero(u); fi;
    lu:= ShallowCopy( u![1] );
    for k in [2,4..Length(lu)] do
        lu[k]:= scal*lu[k];
    od;
    res:= ObjByExtRep( FamilyObj( u ), lu );
    if u![2] then res![2]:= true; fi;
    return res;

end );


InstallMethod(\<,
        "for monomial elements",
        IsIdenticalObj,
        [ IsMonomialElement and IsMonomialElementRep,
          IsMonomialElement and IsMonomialElementRep], 0,
        function( u, v )
    local u1, v1;

    u1:= ConvertToNormalFormMonomialElement( u );
    v1:= ConvertToNormalFormMonomialElement( v );
    return u1![1] < v1![1];
end );

InstallMethod(\=,
        "for monomial elements",
        IsIdenticalObj,
        [ IsMonomialElement and IsMonomialElementRep,
          IsMonomialElement and IsMonomialElementRep], 0,
        function( u, v )

        local u1, v1;

    u1:= ConvertToNormalFormMonomialElement( u );
    v1:= ConvertToNormalFormMonomialElement( v );
    return u1![1] = v1![1];
end );

############################################################################
##
#F  TriangulizeMonomialElementList( <tt>, <zero>, <LM>, <LC> )
##
##  Here <tt> is a list of monomial elements, <zero> is the zero
##  of the ground field, <LM> is a function that calculates the
##  leading monomial of a monomial element (with respect to the ordering
##  \<), and <LC> is a function calculating the coefficient of the
##  leading monomial of a monomial element.
##
##  This function triangulizes the list <tt>, and returns a record with
##  the following components:
##
##  echelonbas: a list of basis vectors of the space spanned by <tt>,
##              in echelon form (with leading coefficients 1).
##
##  heads: a list of leading monomials of the elements of `echelonbas'.
##
##  basechange: a list of the same length as `ecelonbas' describing
##  the elements of `echlonbas' as linear combinations of the original
##  elements of `tt'. The elements of `basechange' are lists of the form
##  `[ l1, l2,...,lk ]', where the `li' are lists of the form `[ ind, cf ]';
##  the i-th element of `echelonbas' is the sum of `cf*tt[ind]'
##  when we loop over the entire list `basechange[i]'.
##
##  All of this is used to produce a basis of the space spaned by
##  `tt'.
##
BindGlobal( "TriangulizeMonomialElementList", function( tt, zero, LM, LC )

    local   basechange,  heads,  k,  cf,  i,  head,  b,  b1,  pos;

    # Initially `basechange' is just the identity.
    # We sort `tt' to get the smallest leading monomials first.

    basechange:= List( [1..Length(tt)], x -> [ [ x, One( zero ) ] ] );
    SortParallel( tt, basechange,
            function( u, v ) return LM(u) < LM(v); end );

    heads:= [ ];
    k:= 1;

    # We perform a Gaussian elimination...

    while k <= Length( tt ) do

        if IsZero( tt[k] ) then

            # Get rid of it.
            Remove( tt, k );
            Remove( basechange, k );
        else

            # Eliminate all instances of `LM( tt[k] )' that occur `below'
            # `tt[k]'.
            cf:= LC( tt[k] );
            tt[k]:= (1/cf)*tt[k];
            for i in [1..Length(basechange[k])] do
                basechange[k][i][2]:= basechange[k][i][2]/cf;
            od;

            head:= LM( tt[k] );
            Add( heads, head );
            i:= k+1;
            while i <= Length(tt) do
                if LM( tt[i] ) = head then
                    cf:= LC( tt[i] );
                    tt[i]:= tt[i] - cf*tt[k];
                    if IsZero( tt[i] ) then

                        # Get rid of it.
                        Remove( tt, i );
                        Remove( basechange, i );
                    else

                        # Adjust the i-th entry in basechange, we basically
                        # subtract `cf' times the k-th entry of basechange.
                        for b in basechange[k] do
                            b1:= [ b[1], -cf*b[2] ];
                            pos := PositionSorted( basechange[i], [b[1]]);
                            if pos > Length( basechange[i] ) or
                               basechange[i][pos][1] <> b1[1] then
                                Add(basechange[i],b1,pos);
                            else
                               basechange[i][pos][2]:= basechange[i][pos][2]+
                                                                  b1[2];
                            fi;

                        od;
                        i:= i+1;
                    fi;
                else
                    i:= i+1;
                fi;
            od;
            k:= k+1;
        fi;
        # sort the lists again...
        SortParallel( tt, basechange,
                function( u, v ) return LM(u) < LM(v); end );
    od;

    return rec( echelonbas:= tt, heads:= heads, basechange:= basechange );

end );

#############################################################################
##
#R  IsBasisOfMonomialSpaceRep( <B> )
##
##  A basis of a monomial space knows the output of
##  `TriangulizeMonomialElementList' with its basis vectors as input.
##  It also knows the zero of the ground field.
##
DeclareRepresentation( "IsBasisOfMonomialSpaceRep", IsComponentObjectRep,
        [ "echelonBasis", "heads", "baseChange", "zeroCoefficient" ] );


#############################################################################
##
#F  BasisOfMonomialSpace( <V>, <vecs> )  for space of monomial elements
##                           and a list of elements thereof
##
BindGlobal( "BasisOfMonomialSpace",
    function( V, vectors )
    local B;

    B:= Objectify( NewType( FamilyObj( V ),
                            IsFiniteBasisDefault and
                            IsBasisOfMonomialSpaceRep and
                            IsAttributeStoringRep ),
                   rec() );
    SetUnderlyingLeftModule( B, V );
    SetBasisVectors( B, vectors );

    return B;

end );


##############################################################################
##
#M  Basis( <V>, <vecs> )
#M  BasisNC( <V>, <vecs> )
##
##  The basis of the space of monomial elements <V> consisting of the
##  vectors in <vecs>.
##  In the NC version it is not checked whether the elements of <vecs> lie
##  in <V>.
##
##  In both cases the list of vectors <vecs> is triangulized, and the data
##  produced by this is stored in the basis.
##
InstallMethod( Basis,
    "for a space of monomial elements and a list of tensor elements",
    IsIdenticalObj,
    [ IsFreeLeftModule and IsMonomialElementCollection,
      IsMonomialElementCollection and IsList ], SUM_FLAGS,
    function( V, vectors )

      local B, info;

      if not ForAll( vectors, x -> x in V ) then return fail; fi;

      # A call to `ConvertToNormalFormMonomialElement' makes sure
      # that all monomial elements
      # are in normal form, and that they are all sorted. So the leading
      # element is just the first element in the list etc.

      vectors:= List( vectors, x -> ConvertToNormalFormMonomialElement( x ) );
      info:= TriangulizeMonomialElementList( ShallowCopy( vectors ),
                     ElementsFamily(FamilyObj(V))!.zeroCoefficient,
                     x -> ExtRepOfObj(x)[1],
                     x -> ExtRepOfObj(x)[2] );
      if Length( info.echelonbas ) <> Length( vectors ) then return fail; fi;
      B:= BasisOfMonomialSpace( V, vectors );
      B!.echelonBasis:= info.echelonbas;
      B!.heads:= info.heads;
      B!.baseChange:= info.basechange;
      B!.zeroCoefficient:= ElementsFamily(FamilyObj(V))!.zeroCoefficient;
      return B;
end );

InstallMethod( BasisNC,
    "for a space of monomial elements and a list of monomial elements",
    IsIdenticalObj,
    [ IsFreeLeftModule and IsMonomialElementCollection,
      IsMonomialElementCollection and IsList ], SUM_FLAGS,
    function( V, vectors )

      local B, info;

      # A call to `ConvertToNormalFormMonomialElement' makes sure that
      # all monomial elements
      # are in normal form, and that they are all sorted. So the leading
      # element is just the first element in the list etc.

      vectors:= List( vectors, x -> ConvertToNormalFormMonomialElement( x ) );
      info:= TriangulizeMonomialElementList( ShallowCopy( vectors ),
                     ElementsFamily(FamilyObj(V))!.zeroCoefficient,
                     x -> ExtRepOfObj(x)[1],
                     x -> ExtRepOfObj(x)[2] );
      if Length( info.echelonbas ) <> Length( vectors ) then return fail; fi;
      B:= BasisOfMonomialSpace( V, vectors );
      B!.echelonBasis:= info.echelonbas;
      B!.heads:= info.heads;
      B!.baseChange:= info.basechange;
      B!.zeroCoefficient:= ElementsFamily(FamilyObj(V))!.zeroCoefficient;
      return B;
end );

#############################################################################
##
#M  Basis( <V> ) . . . . . . . . . . . . . . for a space of monomial elements
##
InstallMethod( Basis,
    "for a space of monomial elements",
    true, [ IsFreeLeftModule and IsMonomialElementCollection ], SUM_FLAGS,
    function( V )

    local B, vectors, info;

    vectors:= List( GeneratorsOfLeftModule(V), x ->
                    ConvertToNormalFormMonomialElement( x ) );
    info:= TriangulizeMonomialElementList( vectors,
                   ElementsFamily(FamilyObj(V))!.zeroCoefficient,
                   x -> ExtRepOfObj(x)[1],
                   x -> ExtRepOfObj(x)[2] );
    B:= BasisOfMonomialSpace( V, info.echelonbas );
    B!.echelonBasis:= info.echelonbas;
    B!.heads:= info.heads;
    B!.baseChange:= List( [1..Length(info.echelonbas)], x -> [[ x, 1 ]] );
    B!.zeroCoefficient:= ElementsFamily(FamilyObj(V))!.zeroCoefficient;
    return B;

end );


##############################################################################
##
#M  Coefficients( <B>, <v> ). . . . . . for basis of a monomial space
##                                      and vector
##
InstallMethod( Coefficients,
    "for basis of a monomial space, and a vector",
        IsCollsElms, [ IsBasis and IsBasisOfMonomialSpaceRep,
                IsMonomialElement and IsMonomialElementRep], SUM_FLAGS,
    function( B, v )

    local   w,  cf,  i,  b, c;

    # We use the echelon basis that comes with <B>.

    w:= ConvertToNormalFormMonomialElement( v );
    cf:= List( BasisVectors( B ), x -> B!.zeroCoefficient );
    for i in [1..Length(B!.heads)] do

        if IsZero( w ) then return cf; fi;

        if  w![1][1] < B!.heads[i] then
            return fail;
        elif w![1][1] = B!.heads[i] then
            c:= w![1][2];
            w:= w - c*B!.echelonBasis[i];
            for b in B!.baseChange[i] do
                cf[b[1]]:= cf[b[1]] + b[2]*c;
            od;
        fi;
    od;

    if not IsZero( w ) then return fail; fi;
    return cf;

end );

##############################################################################
##
#M  PrintObj( <te> ) . . . . . . . . . . . . . for tensor elements
##
##  The zero tenso is represented by `[ [], 0 ]'.
##
InstallMethod( PrintObj,
        "for tensor elements",
        true, [ IsTensorElement and IsMonomialElementRep ], 0,
        function( u )

    local   eu,  k,  i;

    eu:= u![1];

    if eu[1] = [] then
        Print("<0-tensor>");
    else

        for k in [1,3..Length(eu)-1] do
            Print( eu[k+1], "*(" );
            for i in [1..Length(eu[k])-1] do
                Print(eu[k][i],"<x>");
            od;
            Print( Last(eu[k]), ")" );
            if k+1 <> Length( eu ) then
                if not ( IsRat( eu[k+3] ) and eu[k+3] < 0 ) then
                    Print("+");
                fi;
            fi;
        od;

    fi;

end );

##############################################################################
##
#M  ConvertToNormalFormMonomialElement( <te> ) . . for a tensor element
##
InstallMethod( ConvertToNormalFormMonomialElement,
        "for a tensor element",
        true, [ IsTensorElement ], 0,
        function( u )

    local   eu,  fam,  bases,  rank,  tensors,  cfts,  i,  le,  k,
            tt,  cf,  c,  is_replaced,  j,  tt1,  res, len;

    # We expand every component of every tensor in `u' wrt the bases
    # of the constituents of the tensor product. We assume those bases
    # are stored in the FamilyObj of the tensor element.

    if u![2] then return u; fi;

    eu:= ExtRepOfObj( u );
    fam:= FamilyObj( u );
    bases:= fam!.constituentBases;
    rank:= Length( bases );

    # `tensors' will be a list of tensors, i.e., a list of lists
    # of algebra module elements. `cfts' will be the list of their
    # coefficients.

    tensors:= [ ];
    cfts:= [ ];
    for i in [1,3..Length(eu)-1] do
        if eu[i] <> [ ] then #i.e., if it is not the zero tensor
            Add( tensors, eu[i] );
            Add( cfts, eu[i+1] );
        fi;
    od;
    if tensors = [ ] then
        # the thing is zero...
        res:= ObjByExtRep( fam, [ [], fam!.zeroCoefficient ] );
        res![2]:= true;
        return res;
    fi;

    for i in [1..rank] do

        # in all tensors expand the i-th component

        le:= Length( tensors );
        for k in [1..le] do
            tt:= ShallowCopy( tensors[k] );
            cf:= Coefficients( bases[i], tensors[k][i] );
            c:= cfts[k];

            # we replace the tensor on position `k', and add the rest
            # to the and of the list.

            is_replaced:= false;
            for j in [1..Length(cf)] do
                if cf[j] <> 0*cf[j] then
                    if not is_replaced then
                        tt1:= ShallowCopy( tt );
                        tt1[i]:= bases[i][j];
                        tensors[k]:= tt1;
                        cfts[k]:= c*cf[j];
                        is_replaced:= true;
                    else
                        tt1:= ShallowCopy( tt );
                        tt1[i]:= bases[i][j];
                        Add( tensors, tt1 );
                        Add( cfts, c*cf[j] );
                    fi;
                fi;
            od;
            if not is_replaced then
                # i.e., the tensor is zero, erase it
                Unbind( tensors[k] );
                Unbind( cfts[k] );
            fi;

        od;
        tensors:= Compacted( tensors );
        cfts:= Compacted( cfts );
    od;

    # Merge tensors and coefficients, take equal tensors together.
    SortParallel( tensors, cfts );
    res:= [ ];
    len:= 0;
    for i in [1..Length(tensors)] do
        if len > 0 and tensors[i] = res[len-1] then
            res[len]:= res[len]+cfts[i];
            if res[len] = 0*res[len] then
                Unbind( res[len-1] );
                Unbind( res[len] );
                len:= len-2;
            fi;
        else
            Add( res, tensors[i] );
            Add( res, cfts[i] );
            len:= len+2;
        fi;
    od;
    if res = [] then res:= [ [], fam!.zeroCoefficient ]; fi;

    res:= ObjByExtRep( fam, res );
    res![2]:= true;
    return res;

end );


##############################################################################
##
#M  TensorProductOp( <list> ) . . . . for a list of vectorspaces.
##
InstallMethod( TensorProductOp,
        "for a list of finite dimensional vector spaces, and a space (for method selection)",
        true, [ IsDenseList, IsVectorSpace ], 0,
        function( list, list1 )

    local   F,  fam,  type,  gens,  i,  gV,  gens1,  ten,  v,  ten1,
            VT,  BT;

    # We first make the family of the tensor elements, and construct
    # a basis of the tensor space. Note that if the arguments do not
    # know how to compute bases, then the rewriting of tensors to normal
    # forms will fail. Hence we can assume that every module has a basis,
    # and therefore we have a basis of the tensor space as well.

    F:= LeftActingDomain( list1 );

    if not ForAll( list, x -> LeftActingDomain(x) = F ) then
        Error("all vector spaces must be defined over the same field.");
    fi;

    fam:= NewFamily( "TensorElementsFam", IsTensorElement );
    type:= NewType( fam, IsMonomialElementRep );
    fam!.monomialElementDefaultType:= type;
    fam!.zeroCoefficient:= Zero( F );
    fam!.constituentBases:= List( list, Basis );

    if Length(list)=0 then
        gens := [One(F)];
    else
        gens:= List( Basis( list[1] ), x -> [ x ] );
    fi;
    for i in [2..Length(list)] do
        gV:= Basis( list[i] );
        gens1:= [ ];
        for i in [1..Length(gens)] do
            ten:= ShallowCopy( gens[i] );
            for v in gV do
                ten1:= ShallowCopy( ten );
                Add( ten1, v );
                Add( gens1, ten1 );
            od;
        od;
        gens:= gens1;
    od;

    Sort( gens );

    gens:= List( gens, x -> ObjByExtRep( fam, [ x , One(F) ] ) );
    for i in [1..Length(gens)] do
        gens[i]![2]:= true;
    od;


    # We already know a basis of the tensor product, so we don't want
    # to construct this later on; in particular we don't want
    # a call to `Triangulize....' (because we already
    # know that our basis is triangular). So we basically do everything
    # ourselves.

    VT:= VectorSpace( F, gens );
    BT:= BasisOfMonomialSpace( VT, gens );
    BT!.echelonBasis:= gens;
    BT!.baseChange:= List( [ 1..Length(gens)], x -> [ [ x, One(F) ] ] );
    BT!.heads:= List( gens, x -> ExtRepOfObj(x)[1] );
    BT!.zeroCoefficient:= Zero( F );
    SetBasis( VT, BT );
    return VT;

end );

InstallGlobalFunction(TensorProduct, function(arg)
    local d;
    if Length(arg) = 0 then
        Error("<arg> must be nonempty");
    elif Length(arg) = 1 and IsList(arg[1])  then
        if IsEmpty(arg[1])  then
            Error("<arg>[1] must be nonempty");
        fi;
        arg := arg[1];
    fi;
    d := TensorProductOp(arg,arg[1]);
    if ForAll(arg, HasSize) then
        if ForAll(arg, IsFinite) then
            SetSize(d, Product( List(arg, Size)));
        else
            SetSize(d, infinity);
        fi;
    fi;
    return d;
end);

##############################################################################
##
#M  TensorProductOfAlgebraModules( <list> )  for a list of Lie algebra modules
##
InstallMethod( TensorProductOfAlgebraModules,
        "for a list of algebra modules",
        true, [ IsDenseList ], 0,
        function( list )

    local   left_lie_action,  right_lie_action,  VT,  A,  B,  lefta,
            righta,  Tprod;

    # There are two types of actions on a tensor product: left and right.

    left_lie_action:= function( x, tn )

        local   res,  etn,  k,  i,  s;

        res:= [ ];
        etn:= tn![1];
        for k in [1,3..Length(etn)-1] do
            for i in [1..Length(etn[k])] do
                s:= ShallowCopy( etn[k] );
                s[i]:= x^s[i];
                Add( res, s );
                Add( res, etn[k+1] );
            od;
        od;
        return ConvertToNormalFormMonomialElement(
                             ObjByExtRep( FamilyObj(tn), res ) );
    end;

    right_lie_action:= function( tn, x )

        local   res,  etn,  k,  i,  s;

        res:= [ ];
        etn:= tn![1];
        for k in [1,3..Length(etn)-1] do
            for i in [1..Length(etn[k])] do
                s:= ShallowCopy( etn[k] );
                s[i]:= s[i]^x;
                Add( res, s );
                Add( res, etn[k+1] );
            od;
        od;
        return ConvertToNormalFormMonomialElement(
                       ObjByExtRep( FamilyObj( tn ), res ) );
    end;

    # Now we make the tensor module, we need to consider a few cases...

    VT:= TensorProduct( list );

    if IsLeftAlgebraModuleElementCollection( list[1] ) then
        if IsRightAlgebraModuleElementCollection( list[1] ) then

            if not ForAll( list, V ->
                       IsLeftAlgebraModuleElementCollection(V) and
                       IsRightAlgebraModuleElementCollection(V)) then
              Error("for all modules the algebra must act om the same side");
            fi;

            A:= LeftActingAlgebra( list[1] );
            B:= RightActingAlgebra( list[1] );
            if not ForAll( list, V ->
                       IsIdenticalObj( LeftActingAlgebra(V), A ) and
                       IsIdenticalObj( RightActingAlgebra(V), B ) )
             then Error("all modules must have the same acting algebras" );
            fi;

            if HasIsLieAlgebra( A ) and IsLieAlgebra( A ) then
                lefta:= left_lie_action;
            else
                TryNextMethod();
            fi;

            if HasIsLieAlgebra( B ) and IsLieAlgebra( B ) then
                righta:= right_lie_action;
            else
                TryNextMethod();
            fi;

            Tprod:= BiAlgebraModule( A, B, lefta, righta, VT );
        fi;

        if not ForAll( list, IsLeftAlgebraModuleElementCollection ) then
            Error( "for all modules the algebra must act om the same side" );
        fi;

        A:= LeftActingAlgebra( list[1] );
        if not ForAll( list, V -> IsIdenticalObj( LeftActingAlgebra(V), A ) )
           then Error( "all modules must have the same left acting algebra" );
        fi;
        if HasIsLieAlgebra( A ) and IsLieAlgebra( A ) then
            lefta:= left_lie_action;
        else
            TryNextMethod();
        fi;

        Tprod:= LeftAlgebraModule( A, lefta, VT );
    else

        if not ForAll( list, IsRightAlgebraModuleElementCollection ) then
            Error( "for all modules the algebra must act om the same side" );
        fi;

        A:= RightActingAlgebra( list[1] );
        if not ForAll( list, V -> IsIdenticalObj( RightActingAlgebra(V), A ) )
           then Error( "all modules must have the same left acting algebra" );
        fi;

        if HasIsLieAlgebra( A ) and IsLieAlgebra( A ) then
            righta:= right_lie_action;
        else
            TryNextMethod();
        fi;

        Tprod:= RightAlgebraModule( A, righta, VT );
    fi;

    return Tprod;

end );

InstallOtherMethod( TensorProductOfAlgebraModules,
        "for two algebra modules",
        true, [ IsAlgebraModule, IsAlgebraModule ], 0,
        function( V, W )
    return TensorProductOfAlgebraModules( [V,W] );

end );


#############################################################################
##
#M  PrintObj( <we> ) . . . . . . . . . . . . . . for wedge elements
##
##  The zero wedge is represented by the list `[ [], 0 ]'.
##
InstallMethod( PrintObj,
        "for wedge elements",
        true, [ IsWedgeElement and IsMonomialElementRep ], 0,
        function( u )

    local   eu,  k,  i;

    eu:= u![1];

    if eu[1] = [] then
        Print("<0-wedge>");
    else

        for k in [1,3..Length(eu)-1] do
            Print( eu[k+1], "*(" );
            for i in [1..Length(eu[k])-1] do
                Print(eu[k][i],"/\\");
            od;
            Print( Last(eu[k]), ")" );
            if k+1 <> Length( eu ) then
                if not ( IsRat( eu[k+3] ) and eu[k+3] < 0 ) then
                    Print("+");
                fi;
            fi;
        od;

    fi;

end );

###########################################################################
##
#M  ConvertToNormalFormMonomialElement( <we> ) . . . . for a wedge element
##
##
InstallMethod( ConvertToNormalFormMonomialElement,
        "for a wedge element",
        true, [ IsWedgeElement ], 0,
        function( u )

    local   eu,  fam,  basis,  rank,  tensors,  cfts,  wedge_inds,  i,
            le,  k,  tt,  cf,  c,  is_replaced,  j,  tt1,  ind,  perm,
            res,  len, wed;

    # We expand every component of every wedge in `u' wrt the basis
    # of the algebra module from which the exterior product was formed.

    if u![2] then return u; fi;

    eu:= ExtRepOfObj( u );
    fam:= FamilyObj( u );
    basis:= fam!.constituentBasis;
    rank:= fam!.rank;

    # `tensors' will be a list of wedges, i.e., a list of lists
    # of algebra module elements. `cfts' will be the list of their
    # coefficients.
    # `wedge_inds' will be a list of lists of indices in bijection
    # with `tensors'; if `wedge_inds[k] = [ 1, 2 ]' then `tensors[k]=
    # v1 /\ v2' where `v1' and `v2' are the first and second basis elements.

    tensors:= [ ];
    cfts:= [ ];
    for i in [1,3..Length(eu)-1] do
        if eu[i] <> [ ] then #i.e., if it is not the zero tensor
            Add( tensors, eu[i] );
            Add( cfts, eu[i+1] );
        fi;
    od;
    if tensors = [ ] then
        # the thing is zero...
        res:= ObjByExtRep( fam, [ [], fam!.zeroCoefficient ] );
        res![2]:= true;
        return res;
    fi;

    wedge_inds:= List( tensors, x -> [] );

    for i in [1..rank] do

        # in all wedges expand the i-th component

        le:= Length( tensors );
        for k in [1..le] do
            tt:= ShallowCopy( tensors[k] );
            cf:= Coefficients( basis, tensors[k][i] );
            c:= cfts[k];

            # we replace the wedge on position `k', and add the rest
            # to the and of the list.

            is_replaced:= false;
            for j in [1..Length(cf)] do
                if cf[j] <> 0*cf[j] then
                    if not is_replaced then
                        tt1:= ShallowCopy( tt );
                        tt1[i]:= basis[j];
                        tensors[k]:= tt1;
                        cfts[k]:= c*cf[j];
                        wedge_inds[k][i]:= j;
                        is_replaced:= true;
                    else
                        tt1:= ShallowCopy( tt );
                        tt1[i]:= basis[j];
                        Add( tensors, tt1 );
                        Add( cfts, c*cf[j] );
                        ind:= ShallowCopy( wedge_inds[k] );
                        ind[i]:= j;
                        Add( wedge_inds, ind );
                    fi;
                fi;
            od;
            if not is_replaced then
                # i.e., the wedge is zero, erase it
                Unbind( tensors[k] );
                Unbind( cfts[k] );
                Unbind( wedge_inds[k] );
            fi;

        od;
        tensors:= Compacted( tensors );
        cfts:= Compacted( cfts );
        wedge_inds:= Compacted( wedge_inds );
    od;

    # Merge wedges and coefficients, apply permutations to make the wedges
    # increasing, take equal wedges together.

    for i in [1..Length(tensors)] do

        # The tensors with duplicate entries are zero, we get rid of them.

        if not IsDuplicateFree( wedge_inds[i] ) then
            Unbind( wedge_inds[i] );
            Unbind( tensors[i] );
            Unbind( cfts[i] );
        else
            perm:= Sortex( wedge_inds[i] );
            tensors[i]:= Permuted( tensors[i], perm );
            cfts[i]:= SignPerm( perm )*cfts[i];
        fi;

    od;

    tensors:= Compacted( tensors );
    wedge_inds:= Compacted( wedge_inds );
    cfts:= Compacted( cfts );

    perm:= Sortex( tensors );
    cfts:= Permuted( cfts, perm );
    wedge_inds:= Permuted( wedge_inds, perm );
    res:= [ ];
    len:= 0;
    for i in [1..Length(tensors)] do

        if len > 0 and tensors[i] = res[len-1] then
            res[len]:= res[len]+cfts[i];
            if res[len] = 0*res[len] then
                Unbind( res[len-1] );
                Unbind( res[len] );
                len:= len-2;
            fi;
        else
            Add( res, tensors[i] );
            Add( res, cfts[i] );
            len:= len+2;
        fi;
    od;
    if res = [] then res:= [ [], fam!.zeroCoefficient ]; fi;

    res:= ObjByExtRep( fam, res );
    res![2]:= true;
    return res;

end );

#############################################################################
##
#M  ExteriorPower( <V>, <k> ) . . . . . . for a vector space and an integer
##
InstallMethod( ExteriorPower,
        "for a vector space and an integer",
        true, [ IsLeftModule, IsInt ], 0,
        function( V, n )

    local   F,  fam,  type,  combs,  gens,  i,  VT,  BT;

    # We first make the family of the wedge elements, and construct
    # a basis of the exterior product. Note that if the arguments do not
    # know how to compute bases, then the rewriting of wedges to normal
    # forms will fail. Hence we can assume that every module has a basis,
    # and therefore we have a basis of the exterior power as well.


    F:= LeftActingDomain( V );
    fam:= NewFamily( "WedgeElementsFam", IsWedgeElement );
    type:= NewType( fam, IsMonomialElementRep );
    fam!.monomialElementDefaultType:= type;
    fam!.zeroCoefficient:= Zero( F );
    fam!.constituentBasis:= Basis( V );
    fam!.rank:= n;

    combs:= Combinations( [1..Dimension(V)], n );
    gens:= List( combs, x -> Basis(V){x} );
    gens:= List( gens, x -> ObjByExtRep( fam, [ x , One(F) ] ) );

    for i in [1..Length(gens)] do
        gens[i]![2]:= true;
    od;

    Sort( gens );

    # we know a basis of VT:

    if gens = [ ]  then
        VT := VectorSpace( F, [ ObjByExtRep( fam, [] ) ] );
    else
        VT:= VectorSpace( F, gens );
    fi;
    BT:= BasisOfMonomialSpace( VT, gens );
    BT!.echelonBasis:= gens;
    BT!.baseChange:= List( [ 1..Length(gens)], x -> [ [ x, One(F) ] ] );
    BT!.heads:= List( gens, x -> ExtRepOfObj(x)[1] );
    BT!.zeroCoefficient:= Zero( F );
    SetBasis( VT, BT );
    SetDimension( VT, Length(gens) );
    return VT;

end);


#############################################################################
##
#M  ExteriorPowerOfAlgebraModule( <V>, <k> )
##
InstallMethod( ExteriorPowerOfAlgebraModule,
        "for an algebra module and an integer",
        true, [ IsAlgebraModule, IsInt ], 0,
        function( V, n )

    local   left_lie_action,  right_lie_action,  VT,  A,  B,  lefta,
            righta,  Ext;

    # There are two types of actions on an exterior power: left and right.

    left_lie_action:= function( x, tn )

        local   res,  etn,  k,  i,  s;

        res:= [ ];
        etn:= tn![1];
        for k in [1,3..Length(etn)-1] do
            for i in [1..Length(etn[k])] do
                s:= ShallowCopy( etn[k] );
                s[i]:= x^s[i];
                Add( res, s );
                Add( res, etn[k+1] );
            od;
        od;
        return ConvertToNormalFormMonomialElement(
                       ObjByExtRep( FamilyObj(tn), res ) );
    end;

    right_lie_action:= function( tn, x )

        local   res,  etn,  k,  i,  s;

        res:= [ ];
        etn:= tn![1];
        for k in [1,3..Length(etn)-1] do
            for i in [1..Length(etn[k])] do
                s:= ShallowCopy( etn[k] );
                s[i]:= s[i]^x;
                Add( res, s );
                Add( res, etn[k+1] );
            od;
        od;
        return ConvertToNormalFormMonomialElement(
                       ObjByExtRep( FamilyObj(tn), res ) );
    end;

    VT:= ExteriorPower( V, n );

    # Now we make the exterior module, we need to consider a few cases...

    if IsLeftAlgebraModuleElementCollection( V ) then
        if IsRightAlgebraModuleElementCollection( V ) then

            A:= LeftActingAlgebra( V );
            B:= RightActingAlgebra( V );

            if HasIsLieAlgebra( A ) and IsLieAlgebra( A ) then
                lefta:= left_lie_action;
            else
                Error("exterior powers are only defined for modules over Lie algebras");
            fi;

            if HasIsLieAlgebra( B ) and IsLieAlgebra( B ) then
                righta:= right_lie_action;
            else
                Error("exterior powers are only defined for modules over Lie algebras");
            fi;

            Ext:= BiAlgebraModule( A, B, lefta, righta, VT );
        fi;

        A:= LeftActingAlgebra( V );
        if HasIsLieAlgebra( A ) and IsLieAlgebra( A ) then
            lefta:= left_lie_action;
        else
            Error("exterior powers are only defined for modules over Lie algebras");
        fi;

        Ext:= LeftAlgebraModule( A, lefta, VT );
    else

        A:= RightActingAlgebra( V );

        if HasIsLieAlgebra( A ) and IsLieAlgebra( A ) then
            righta:= right_lie_action;
        else
            Error("exterior powers are only defined for modules over Lie algebras");
        fi;

        Ext:= RightAlgebraModule( A, righta, VT );
    fi;

    return Ext;

end );

############################################################################
##
#M  PrintObj( <se> ) . . . . . . . . . . . for symmetric elements
##
InstallMethod( PrintObj,
        "for symmetric elements",
        true, [ IsSymmetricPowerElement and IsMonomialElementRep ], 0,
        function( u )

    local   eu,  k,  i;

    eu:= u![1];

    if eu[1] = [] then
        Print("<0-symmetric element>");
    else

        for k in [1,3..Length(eu)-1] do
            Print( eu[k+1], "*(" );
            for i in [1..Length(eu[k])-1] do
                Print(eu[k][i],".");
            od;
            Print( Last(eu[k]), ")" );
            if k+1 <> Length( eu ) then
                if not ( IsRat( eu[k+3] ) and eu[k+3] < 0 ) then
                    Print("+");
                fi;
            fi;
        od;

    fi;

end );

############################################################################
##
#M  ConvertToNormalFormMonomialElement( <se> ) . . . for a symmetric element
##
InstallMethod( ConvertToNormalFormMonomialElement,
        "for a symmetric element",
        true, [ IsSymmetricPowerElement ], 0,
        function( u )

    local   eu,  fam,  basis,  rank,  tensors,  cfts,  symmetric_inds,  i,
            le,  k,  tt,  cf,  c,  is_replaced,  j,  tt1,  ind,  perm,
            res,  len, wed;

    # We expand every component of every symmetric elt in `u' wrt the basis
    # of the algebra module of which the symmetric product was formed.

    if u![2] then return u; fi;

    eu:= ExtRepOfObj( u );
    fam:= FamilyObj( u );
    basis:= fam!.constituentBasis;
    rank:= fam!.rank;

    # `tensors' will be a list of symmetric elements, i.e., a list of lists
    # of algebra module elements. `cfts' will be the list of their
    # coefficients.
    # `symmetric_inds' is a list of lists of indices, exactly analogous
    # to the list `wedge_inds' in the method for
    # `ConvertToNormalFormMonomialElement' for wedge elements.

    tensors:= [ ];
    cfts:= [ ];
    for i in [1,3..Length(eu)-1] do
        if eu[i] <> [ ] then #i.e., if it is not the zero tensor
            Add( tensors, eu[i] );
            Add( cfts, eu[i+1] );
        fi;
    od;
    if tensors = [ ] then
        # the thing is zero...
        res:= ObjByExtRep( fam, [ [], fam!.zeroCoefficient ] );
        res![2]:= true;
        return res;
    fi;

    symmetric_inds:= List( tensors, x -> [] );

    for i in [1..rank] do

        # in all tensor expand the i-th component

        le:= Length( tensors );
        for k in [1..le] do
            tt:= ShallowCopy( tensors[k] );
            cf:= Coefficients( basis, tensors[k][i] );
            c:= cfts[k];

            # we replace the symmetric element on position `k', and add the
            # rest to the and of the list.

            is_replaced:= false;
            for j in [1..Length(cf)] do
                if cf[j] <> 0*cf[j] then
                    if not is_replaced then
                        tt1:= ShallowCopy( tt );
                        tt1[i]:= basis[j];
                        tensors[k]:= tt1;
                        cfts[k]:= c*cf[j];
                        symmetric_inds[k][i]:= j;
                        is_replaced:= true;
                    else
                        tt1:= ShallowCopy( tt );
                        tt1[i]:= basis[j];
                        Add( tensors, tt1 );
                        Add( cfts, c*cf[j] );
                        ind:= ShallowCopy( symmetric_inds[k] );
                        ind[i]:= j;
                        Add( symmetric_inds, ind );
                    fi;
                fi;
            od;
            if not is_replaced then
                # i.e., the symmetric element is zero, erase it
                Unbind( tensors[k] );
                Unbind( cfts[k] );
                Unbind( symmetric_inds[k] );
            fi;

        od;
        tensors:= Compacted( tensors );
        cfts:= Compacted( cfts );
        symmetric_inds:= Compacted( symmetric_inds );
    od;

    # Merge symmetric elements and coefficients, apply permutations to make
    # the symmetric elements
    # increasing, take equal symmetric elements together.

    for i in [1..Length(tensors)] do

        perm:= Sortex( symmetric_inds[i] );
        tensors[i]:= Permuted( tensors[i], perm );

    od;


    perm:= Sortex( tensors );
    cfts:= Permuted( cfts, perm );
    symmetric_inds:= Permuted( symmetric_inds, perm );
    res:= [ ];
    len:= 0;
    for i in [1..Length(tensors)] do

        wed:= tensors[i];
        if len > 0 and wed = res[len-1] then
            res[len]:= res[len]+cfts[i];
            if res[len] = 0*res[len] then
                Unbind( res[len-1] );
                Unbind( res[len] );
                len:= len-2;
            fi;
        else
            Add( res, wed );
            Add( res, cfts[i] );
            len:= len+2;
        fi;
    od;
    if res = [] then res:= [ [], fam!.zeroCoefficient ]; fi;

    res:= ObjByExtRep( fam, res );
    res![2]:= true;
    return res;

end );


############################################################################
##
#M  SymmetricPower( <V>, <k> ) . . . . . for a vector space and an integer
##
InstallMethod( SymmetricPower,
        "for an algebra module and an integer",
        true, [ IsLeftModule, IsInt ], 0,
        function( V, n )

    local   F,  fam,  type,  combs,  gens,  i,  VT,  BT;

    # We first make the family of the symmetric elements, and construct
    # a basis of the symmetric product. Note that if the arguments do not
    # know how to compute bases, then the rewriting of symmetrics to normal
    # forms will fail. Hence we can assume that every module has a basis,
    # and therefore we have a basis of the symmetric power as well.

    F:= LeftActingDomain( V );
    fam:= NewFamily( "SymmetricElementsFam", IsSymmetricPowerElement );
    type:= NewType( fam, IsMonomialElementRep );
    fam!.monomialElementDefaultType:= type;
    fam!.zeroCoefficient:= Zero( F );
    fam!.constituentBasis:= Basis( V );
    fam!.rank:= n;

    combs:= UnorderedTuples( [1..Dimension(V)], n );
    gens:= List( combs, x -> Basis(V){x} );
    gens:= List( gens, x -> ObjByExtRep( fam, [ x , One(F) ] ) );
    for i in [1..Length(gens)] do
        gens[i]![2]:= true;
    od;

    Sort( gens );

    # we know a basis of VT:

    VT:= VectorSpace( F, gens );
    BT:= BasisOfMonomialSpace( VT, gens );
    BT!.echelonBasis:= gens;
    BT!.baseChange:= List( [ 1..Length(gens)], x -> [ [ x, One(F) ] ] );
    BT!.heads:= List( gens, x -> ExtRepOfObj(x)[1] );
    BT!.zeroCoefficient:= Zero( F );
    SetBasis( VT, BT );
    return VT;
end);


############################################################################
##
#M  SymmetricPowerOfAlgebraModule( <V>, <k> )
##
InstallMethod( SymmetricPowerOfAlgebraModule,
        "for an algebra module and an integer",
        true, [ IsAlgebraModule, IsInt ], 0,
        function( V, n )

    local   left_lie_action,  right_lie_action,  VT,  A,  B,  lefta,
            righta,  Symm;


    # There are two types of actions on the symmetric power: left and right.

    left_lie_action:= function( x, tn )

        local   res,  etn,  k,  i,  s;

        res:= [ ];
        etn:= tn![1];
        for k in [1,3..Length(etn)-1] do
            for i in [1..Length(etn[k])] do
                s:= ShallowCopy( etn[k] );
                s[i]:= x^s[i];
                Add( res, s );
                Add( res, etn[k+1] );
            od;
        od;
        return ConvertToNormalFormMonomialElement(
                       ObjByExtRep( FamilyObj(tn), res ) );
    end;

    right_lie_action:= function( tn, x )

        local   res,  etn,  k,  i,  s;

        res:= [ ];
        etn:= tn![1];
        for k in [1,3..Length(etn)-1] do
            for i in [1..Length(etn[k])] do
                s:= ShallowCopy( etn[k] );
                s[i]:= s[i]^x;
                Add( res, s );
                Add( res, etn[k+1] );
            od;
        od;
        return ConvertToNormalFormMonomialElement(
                       ObjByExtRep( FamilyObj(tn), res ) );
    end;

    VT:= SymmetricPower( V, n );

    # Now we make the symmetric power, we need to consider a few cases...

    if IsLeftAlgebraModuleElementCollection( V ) then
        if IsRightAlgebraModuleElementCollection( V ) then

            A:= LeftActingAlgebra( V );
            B:= RightActingAlgebra( V );

            if HasIsLieAlgebra( A ) and IsLieAlgebra( A ) then
                lefta:= left_lie_action;
            else
                Error("symmetric powers are only defined for modules over Lie algebras");
            fi;

            if HasIsLieAlgebra( B ) and IsLieAlgebra( B ) then
                righta:= right_lie_action;
            else
                Error("symmetric powers are only defined for modules over Lie algebras");
            fi;

            Symm:= BiAlgebraModule( A, B, lefta, righta, VT );
        fi;

        A:= LeftActingAlgebra( V );
        if HasIsLieAlgebra( A ) and IsLieAlgebra( A ) then
            lefta:= left_lie_action;
        else
            Error("symmetric powers are only defined for modules over Lie algebras");
        fi;

        Symm:= LeftAlgebraModule( A, lefta, VT );
    else

        A:= RightActingAlgebra( V );

        if HasIsLieAlgebra( A ) and IsLieAlgebra( A ) then
            righta:= right_lie_action;
        else
            Error("symmetric powers are only defined for modules over Lie algebras");
        fi;

        Symm:= RightAlgebraModule( A, righta, VT );
    fi;

    return Symm;

end );


##############################################################################
##
#M  ObjByExtRep( <fam>, <list> ) . . . for a sparse rowspace elt fam. and list
#M  ExtRepOfObj( <v> ) . . . . . . . . for a sparse rowspace element.
##
##  Elements of sparse rowspaces are represented by a list of the
##  form [ i1, c1, i2, c2, ...], where the ik are the indices of the
##  standard row vectors, and the ck are coefficients, and  i1<i2<...
##  So if ek are the unit row vectos then such a sparse element represents
##  c1*e{i1}+c2*e{i2}+...
##
InstallMethod( ObjByExtRep,
        "for a sparse rowspace element family and a list",
        true, [ IsSparseRowSpaceElementFamily, IsList ], 0,
        function( fam, lst )
    return Objectify( fam!.sparseRowSpaceElementDefaultType,
                   [ Immutable(lst) ] );
end );

InstallMethod( ExtRepOfObj,
        "for a sparse rowspace element",
        true, [ IsSparseRowSpaceElement and IsPackedElementDefaultRep ], 0,
        function( v )
    return v![1];
end);


##############################################################################
##
#M  PrintObj( <v> ) . . . . . . for a sparse rowspace element
##
##  A sparse rowspace element is printed as c1*v.i1+c2*v.i2+....
##
InstallMethod( PrintObj,
        "for a sparse rowspace element",
        true, [ IsSparseRowSpaceElement ], 0,
        function( v )

    local   ev,  k;

    ev:= ExtRepOfObj( v );
    if ev = [ ] then Print( "<zero of...>" ); fi;

    for k in [1,3..Length(ev)-1] do
        if k <> 1 then Print("+"); fi;
        Print( "(", ev[k+1], ")*e.", ev[k] );
    od;
end );


#############################################################################
##
#M  ZeroOp( <v> ) . . . . . . . . . . . . . for a sparse rowspace element
#M  \+( <u>, <v> ) . . . . . . . . . . . .  for sparse rowspace elements
#M  AdditiveInverseOp( <u> ) . . . . . . . . . . . . . . for a sparse rowspace element
#M  \*( <scal>, <u> )  . . . . . for a sparse rowspace element and scalar
#M  \*( <u>, <scal> ) . . . . . .for a sclalar and sparse rowspace element
#M  \<( <u>, <v> )  . . . . . . . . . . . . for sparse rowspace elements
#M  \=( <u>, <v> ) . . . . . . . . . . . . for sparse rowspace elements
##
InstallMethod( ZeroOp,
        "for sparse rowspace elements",
        true, [ IsSparseRowSpaceElement and IsPackedElementDefaultRep ], 0,
        function( u )

    return ObjByExtRep( FamilyObj( u ), [] );
end );


InstallMethod(\+,
        "for sparse rowspace elements",
        IsIdenticalObj,
        [ IsSparseRowSpaceElement and IsPackedElementDefaultRep,
          IsSparseRowSpaceElement and IsPackedElementDefaultRep], 0,
        function( u, v )

    local lu,lv,zero, sum, res;

    lu:= u![1];
    lv:= v![1];
    zero:= FamilyObj( u )!.zeroCoefficient;
    sum:=  ZippedSum( lu, lv, zero, [\<,\+] );
    return ObjByExtRep( FamilyObj( u ), sum );

end );

InstallMethod( AdditiveInverseOp,
        "for a sparse rowspace element",
        true,
        [ IsSparseRowSpaceElement and IsPackedElementDefaultRep ], 0,
        function( u )

    local   eu,  k;

    eu:= ShallowCopy( u![1] );
    for k in [2,4..Length(eu)] do
        eu[k]:= -eu[k];
    od;

    return ObjByExtRep( FamilyObj( u ), eu );
end );

InstallMethod( \*,
        "for a sparse rowspace element and a scalar",
        true,
        [ IsSparseRowSpaceElement and IsPackedElementDefaultRep,
          IsRingElement ], 0,
        function( u, scal )

    local   eu,  k;

    if IsZero(scal) then return Zero(u); fi;
    eu:= ShallowCopy( u![1] );
    for k in [2,4..Length(eu)] do
        eu[k]:= scal*eu[k];
    od;

    return ObjByExtRep( FamilyObj( u ), eu );
end );


InstallMethod( \*,
        "for a scalar and a sparse rowspace element",
        true,
        [ IsRingElement,
          IsSparseRowSpaceElement and IsPackedElementDefaultRep ], 0,
        function( scal, u )

    local   eu,  k;

    if IsZero(scal) then return Zero(u); fi;
    eu:= ShallowCopy( u![1] );
    for k in [2,4..Length(eu)] do
        eu[k]:= scal*eu[k];
    od;

    return ObjByExtRep( FamilyObj( u ), eu );
end );


InstallMethod(\<,
        "for sparse rowspace elements",
        IsIdenticalObj,
        [ IsSparseRowSpaceElement and IsPackedElementDefaultRep,
          IsSparseRowSpaceElement and IsPackedElementDefaultRep], 0,
        function( u, v )
    return u![1] < v![1];
end );

InstallMethod(\=,
        "for sparse rowspace elements",
        IsIdenticalObj,
        [ IsSparseRowSpaceElement and IsPackedElementDefaultRep,
          IsSparseRowSpaceElement and IsPackedElementDefaultRep], 0,
        function( u, v )
    return u![1] = v![1];
end );

#############################################################################
##
#R  IsBasisOfSparseRowSpaceRep( <B> )
##
##  A basis of a sparse rowspace has the record components
##  `echelonBasis' (a list of vectors spanning the same space, and in
##  echelon form), `heads' (the indices of the `leading' vectors of
##  the elements of `echelonBasis'), `baseChange' ( a list of the same length
##  as `ecelonBasis' describing
##  the elements of `echlonBasis' as linear combinations of the basis vectors
##  of the basis <B>. The elements of `baseChange' are lists of the form
##  `[ l1, l2,...,lk ]', where the `li' are lists of the form `[ ind, cf ]';
##  the i-th element of `echelonBas' is the sum of `cf*B[ind]'
##  when we loop over the entire list `basechange[i]'.), `zeroCoefficient'
##  (the zero of the ground field).
##
DeclareRepresentation( "IsBasisOfSparseRowSpaceRep", IsComponentObjectRep,
        [ "echelonBasis", "heads", "baseChange", "zeroCoefficient" ] );

##############################################################################
##
#F  BasisOfSparseRowSpace( <V>, <vectors> )  for a sparse row space and a list
##
##  We note that in this function the list <vectors> gets triangulized,
##  and a basis is always returned, also if the dimension of <V> is less
##  than the length of <vectors>.
##
BindGlobal( "BasisOfSparseRowSpace",
        function( V, vectors )

    local   tt,  zero,  basechange,  heads,  k,  cf,  i,  head,  b,
            b1,  pos,  B;

    # We first triangulize the elements of `vectors'.

    tt:= ShallowCopy( vectors );
    zero:= Zero( LeftActingDomain( V ) );

    # Initially `basechange' is just the identity.
    # We sort `tt' to get the smallest leading monomials first.

    basechange:= List( [1..Length(tt)], x -> [ [ x, One( zero ) ] ] );
    SortParallel( tt, basechange,
            function( u, v ) return u![1][1] < v![1][1]; end );

    heads:= [ ];
    k:= 1;

    # We perform a Gaussian elimination...

    while k <= Length( tt ) do

        if IsZero( tt[k] ) then

            # Get rid of it.
            Remove( tt, k );
            Remove( basechange, k );
        else

            # If there is a vector starting with the same index as `tt[k]'
            # occurring "below" `tt[k]' then subtract `tt[k]' the appropriate
            # number of times.
            # First we make the leading coefficient of `tt[k]' equal to 1.

            cf:= tt[k]![1][2];
            tt[k]:= (1/cf)*tt[k];
            for i in [1..Length(basechange[k])] do
                basechange[k][i][2]:= basechange[k][i][2]/cf;
            od;

            head:= tt[k]![1][1];
            Add( heads, head );
            i:= k+1;
            while i <= Length(tt) do
                if tt[i]![1][1] = head then
                    cf:= tt[i]![1][2];
                    tt[i]:= tt[i] - cf*tt[k];
                    if IsZero( tt[i] ) then

                        # Get rid of it.
                        Remove( tt, i );
                        Remove( basechange, i );
                    else

                        # Adjust the i-th entry in basechange, we basically
                        # subtract `cf' times the k-th entry of basechange.
                        for b in basechange[k] do
                            b1:= [ b[1], -cf*b[2] ];
                            pos := PositionSorted( basechange[i], [b[1]]);
                            if pos > Length( basechange[i] ) or
                               basechange[i][pos][1] <> b1[1] then
                                Add(basechange[i],b1,pos);
                            else
                               basechange[i][pos][2]:= basechange[i][pos][2]+
                                                                  b1[2];
                            fi;

                        od;
                        i:= i+1;
                    fi;
                else
                    i:= i+1;
                fi;
            od;
            k:= k+1;
        fi;
        # Sort the lists again...
        # This is necessary, because by the elim operation the lists may have
        # become unsorted.
        SortParallel( tt, basechange,
                function( u, v ) return u![1][1] < v![1][1]; end );
    od;

    # Finally we construct the basis.

    B:= Objectify( NewType( FamilyObj( V ),
                IsBasisOfSparseRowSpaceRep and
                IsFiniteBasisDefault and
                IsAttributeStoringRep ),
                rec() );

    B!.semiEchelonBasis:= tt;
    B!.heads:= heads;
    B!.baseChange:= basechange;
    B!.zeroCoefficient:= zero;

    SetUnderlyingLeftModule( B, V );

    return B;
end );

#############################################################################
##
#M  Basis( <V>, <vectors> )
#M  BasisNC( <V>, <vectors> )
#M  Basis( <V> )
##
InstallMethod( Basis,
        "for a free module of sparse row space elements, and list",
        true,
        [ IsFreeLeftModule and IsSparseRowSpaceElementCollection,
          IsHomogeneousList ], SUM_FLAGS,
        function( V, vectors )
    local B;

    if not ForAll( vectors, x -> x in V ) then return fail; fi;
    B:= BasisOfSparseRowSpace( V, vectors );
    if Length( B!.semiEchelonBasis ) <> Length( vectors ) then return fail; fi;
    SetBasisVectors( B, vectors );
    return B;

end );


InstallMethod( BasisNC,
        "for a free module of sparse row space elements, and list",
        true,
        [ IsFreeLeftModule and IsSparseRowSpaceElementCollection,
          IsHomogeneousList ], SUM_FLAGS,
        function( V, vectors )
    local B;

    B:= BasisOfSparseRowSpace( V, vectors );
    SetBasisVectors( B, vectors );
    return B;

end );


InstallMethod( Basis,
        "for a free module of sparse row space elements",
        true,
        [ IsFreeLeftModule and IsSparseRowSpaceElementCollection ], SUM_FLAGS,
        function( V )
    local B, BV;

    # We return an echelonized basis.

    B:= BasisOfSparseRowSpace( V, GeneratorsOfLeftModule( V ) );
    BV:= B!.semiEchelonBasis;
    SetBasisVectors( B, BV );
    B!.baseChange:= List( [1..Length(BV)], x ->
                          [ [ x, One( LeftActingDomain(V) ) ] ] );
    return B;

end );

##############################################################################
##
#M  Coefficients( <B>, <v> ). . . . . . for basis of a sparse row space
##                                      and vector
##
InstallMethod( Coefficients,
        "for basis of a sparse rowspace, and a vector",
        IsCollsElms, [ IsBasis and IsBasisOfSparseRowSpaceRep,
                IsSparseRowSpaceElement ], SUM_FLAGS,
    function( B, v )

    local   w,  cf,  i,  b, c;

    # We use the echelon basis that comes with <B>.

    w:= v;
    cf:= List( BasisVectors( B ), x -> B!.zeroCoefficient );
    for i in [1..Length(B!.heads)] do

        if IsZero( w ) then return cf; fi;

        if  w![1][1] < B!.heads[i] then
            return fail;
        elif w![1][1] = B!.heads[i] then
            c:= w![1][2];
            w:= w - c*B!.semiEchelonBasis[i];
            for b in B!.baseChange[i] do
                cf[b[1]]:= cf[b[1]] + b[2]*c;
            od;
        fi;
    od;

    if not IsZero( w ) then return fail; fi;
    return cf;

end );


#############################################################################
##
##  Prevent nice basis handling to kick in for vector spaces over sparse
##  elements (including monomial elements), as that ends up trying to
##  enumerate the vector space, which is not a good idea for non-trivial
##  examples.
##
InstallHandlingByNiceBasis( "IsSparseVectorSpace", rec(
    detect:= function( R, gens, V, zero )
        if IsSparseRowSpaceElementCollection(V) then
            return fail;
        else
            return false;
        fi;
    end,
    NiceFreeLeftModuleInfo := function( C ) end,
    NiceVector := function( C, c ) end,
    UglyVector := function( C, vec ) end,
) );

InstallHandlingByNiceBasis( "IsMonomialElementVectorSpace", rec(
    detect:= function( R, gens, V, zero )
        if IsMonomialElementCollection(V) then
            return fail;
        else
            return false;
        fi;
    end,
    NiceFreeLeftModuleInfo := function( C ) end,
    NiceVector := function( C, c ) end,
    UglyVector := function( C, vec ) end,
) );


#############################################################################
##
#M  FullSparseRowSpace( <F>, <n> )  . . . . . . for a ring and an integer
##
##
InstallMethod( FullSparseRowSpace,
        "for a ring and an integer",
        true, [ IsRing, IsInt ], 0,
        function( F, n )

    local   fam,  bV,  V,  B;

    fam:= NewFamily( "FamilyOfSparseRowSpaceElements",
                  IsSparseRowSpaceElement );
    fam!.sparseRowSpaceElementDefaultType:= NewType( fam,
                                               IsPackedElementDefaultRep );
    fam!.zeroCoefficient:= Zero( F );
    bV:= List( [1..n], x -> ObjByExtRep( fam, [ x, One(F) ] ) );
    V:= VectorSpace( F, bV );
    B:= Objectify( NewType( FamilyObj( V ),
                IsBasisOfSparseRowSpaceRep and
                IsFiniteBasisDefault and
                IsAttributeStoringRep ),
                rec() );

    B!.semiEchelonBasis:= bV;
    B!.heads:= [1..n];
    B!.baseChange:= List( [1..n], x -> [ [ x, One( F ) ] ] );
    B!.zeroCoefficient:= Zero( F );

    SetUnderlyingLeftModule( B, V );
    SetBasisVectors( B, bV );
    SetBasis( V, B );
    SetDimension( V, n );
    return V;

end );


###############################################################################
##
#M  PrintObj( <u> ) . . . . . . . . . . . . . . . . . for a direct sum element
##
InstallMethod( PrintObj,
        "for direct sum elements",
        true, [ IsDirectSumElement and IsPackedElementDefaultRep ], 0,
        function( u )

    local   eu,  k,  i;

    eu:= u![1];
    for k in [1..Length(eu)] do
        Print("( ",eu[k]," )");
        if k <> Length( eu ) then
            Print( "(+)" );
        fi;
    od;

end );

############################################################################
##
#M  ObjByExtRep( <fam>, <list> ) . . . for a DirectSumElementFamily and a list
#M  ExtRepOfObj( <t> )  . . . . . . .  for a direct sum element in packed rep.
##
InstallMethod( ObjByExtRep,
        "for a family of direct sum elements and a list",
        true, [ IsDirectSumElementFamily, IsList] , 0,
        function( fam, list )
    return Objectify( fam!.directSumElementDefaultType,
                   [ Immutable( list ) ] );
end );


InstallMethod( ExtRepOfObj,
        "for a direct sum element",
        true, [ IsDirectSumElement and IsPackedElementDefaultRep ] , 0,
        function( t )  return t![1];
end );

InstallMethod( ZeroOp,
        "for direct sum elements",
        true, [ IsDirectSumElement and IsPackedElementDefaultRep ], 0,
        function( u )

    return ObjByExtRep( FamilyObj( u ), List(
                   FamilyObj( u )!.constituentModules, Zero ) );
end );


InstallMethod(\+,
        "for direct sum elements",
        IsIdenticalObj,
        [ IsDirectSumElement and IsPackedElementDefaultRep,
          IsDirectSumElement and IsPackedElementDefaultRep], 0,
        function( u, v )
    return ObjByExtRep( FamilyObj( u ), ExtRepOfObj( u )+ ExtRepOfObj( v ) );
end );

InstallMethod( AdditiveInverseOp,
        "for a direct sum element",
        true,
        [ IsDirectSumElement and IsPackedElementDefaultRep ], 0,
        function( u )
    return ObjByExtRep( FamilyObj( u ), -ExtRepOfObj( u ) );
end );


InstallMethod(\*,
        "for a direct sum element and a scalar",
        true,
        [ IsDirectSumElement and IsPackedElementDefaultRep, IsRingElement ], 0,
        function( u, scal )
    return ObjByExtRep( FamilyObj( u ), scal*ExtRepOfObj( u ) );
end );

InstallMethod(\*,
        "for a direct sum element and a scalar",
        true,
        [ IsRingElement, IsDirectSumElement and IsPackedElementDefaultRep ],0,
        function( scal, u  )
    return ObjByExtRep( FamilyObj( u ), scal*ExtRepOfObj( u ) );
end );


InstallMethod(\<,
        "for direct sum elements",
        IsIdenticalObj,
        [ IsDirectSumElement and IsPackedElementDefaultRep,
          IsDirectSumElement and IsPackedElementDefaultRep], 0,
        function( u, v )
    return u![1] < v![1];
end );

InstallMethod(\=,
        "for direct sum elements",
        IsIdenticalObj,
        [ IsDirectSumElement and IsPackedElementDefaultRep,
          IsDirectSumElement and IsPackedElementDefaultRep], 0,
        function( u, v )
    return u![1] = v![1];
end );


#############################################################################
##
#M  NiceFreeLeftModuleInfo( <C> ) . . . . . . .  for a module of dir sum elts
#M  NiceVector ( <C>, <c> ) . . for a module of dir sum elts and a dir sum elt
#M  UglyVector( <C>, <v> ) . . .for a module of dir sum elts and a row vector
##
InstallHandlingByNiceBasis( "IsDirectSumElementsSpace", rec(
    detect:= function( R, gens, V, zero )
      return IsDirectSumElementCollection( V );
      end,

    NiceFreeLeftModuleInfo := ReturnFalse,

    NiceVector := function( V, v )
      local   ev,  vec,  num,  i,  cf,  k;

      if not IsPackedElementDefaultRep( v ) then
        TryNextMethod();
      fi;
      ev:= ExtRepOfObj( v );
      vec:= [ ];
      num:= 0;
      for i in [1..Length(ev)] do
          cf:= Coefficients( Basis(
                       FamilyObj(v)!.constituentModules[i] ), ev[i] );
          for k in [1..Length(cf)] do
              if cf[k] <> 0*cf[k] then
                  Add( vec, num+k );
                  Add( vec, cf[k] );
              fi;
          od;
          num:= num + Dimension( FamilyObj(v)!.constituentModules[i] );
      od;
      return ObjByExtRep( FamilyObj( v )!.niceVectorFam, vec );
      end,

    UglyVector := function( V, vec )
      local   ev,  fam,  mods,  u,  d,  k,  i;

      # We do the inverse of `NiceVector'.
      ev:= ShallowCopy( vec![1] );
      fam:= ElementsFamily( FamilyObj( V ) );
      mods:= fam!.constituentModules;
      u:= List( mods, Zero );
      d:= 0;
      k:= 1;
      i:= 1;
      while IsBound( ev[k] ) and i <= Length( mods ) do
          if ev[k] <= d+Dimension(mods[i]) then
              u[i]:= u[i] + ev[k+1]*Basis(mods[i])[ev[k]-d];
              k:= k+2;
          else
              d:= d + Dimension( mods[i] );
              i:= i+1;
          fi;
      od;
      return ObjByExtRep( fam, u );
      end ) );


############################################################################
##
#M  DirectSumOfAlgebraModules( <list> )
#M  DirectSumOfAlgebraModules( <V>, <W> )
##
InstallMethod( DirectSumOfAlgebraModules,
        "for a list of algebra modules",
        true, [ IsDenseList ], 0,
        function( list )

    local   left_action,  right_action,  F,  fam,  type,  niceVF,
            gens,  zero,  i,  gV,  v,  be,  A,  B,  V,  W,  niceMod,
            BW;

    # There are two types of action on a direct sum: left and right.

    left_action:= function( x, tn )

        return ObjByExtRep( FamilyObj( tn ),
                       List( ShallowCopy( ExtRepOfObj( tn ) ), u -> x^u ) );
    end;

    right_action:= function( tn, x )

        return ObjByExtRep( FamilyObj( tn ),
                       List( ShallowCopy( ExtRepOfObj( tn ) ), u -> u^x ) );
    end;


    # We first make the family of the direct sum elements, and construct
    # a basis of the direct sum. Note that if the arguments do not
    # know how to compute bases, then the rewriting of direct sum elements
    # to normal
    # forms will fail. Hence we can assume that every module has a basis,
    # and therefore we have a basis of the direct sum as well.

    F:= LeftActingDomain( list[1] );
    fam:= NewFamily( "DirectSumElementsFam", IsDirectSumElement );
    type:= NewType( fam, IsPackedElementDefaultRep );
    fam!.directSumElementDefaultType:= type;
    fam!.zeroCoefficient:= Zero( F );
    fam!.constituentModules:= list;

    niceMod:= FullSparseRowSpace( F, Sum( List( list, Dimension ) ) );
    niceVF:= ElementsFamily( FamilyObj( niceMod ) );
    fam!.niceVectorFam:= niceVF;

    gens:= [ ];
    zero:= List( list, Zero );
    for i in [1..Length(list)] do
        gV:= Basis( list[i] );
        for v in gV do
            be:= ShallowCopy( zero );
            be[i]:= v;
            Add( gens, be );
        od;
    od;

    if gens = [ ] then
        gens:= [ zero ];
    fi;

    gens:= List( gens, x -> ObjByExtRep( fam, x ) );

    # Now we make the direct sum, we need to consider a few cases...

    if IsLeftAlgebraModuleElementCollection( list[1] ) then
        if IsRightAlgebraModuleElementCollection( list[1] ) then

            if not ForAll( list, V ->
                       IsLeftAlgebraModuleElementCollection(V) and
                       IsRightAlgebraModuleElementCollection(V)) then
              Error("for all modules the algebra must act om the same side");
            fi;

            A:= LeftActingAlgebra( list[1] );
            B:= RightActingAlgebra( list[1] );
            if not ForAll( list, V ->
                       IsIdenticalObj( LeftActingAlgebra(V), A ) and
                       IsIdenticalObj( RightActingAlgebra(V), B ) )
             then Error("all modules must have the same left acting algebra" );
            fi;

            V:= BiAlgebraModuleByGenerators( A, B, left_action, right_action,
                           gens );
        fi;

        if not ForAll( list, IsLeftAlgebraModuleElementCollection ) then
            Error( "for all modules the algebra must act om the same side" );
        fi;

        A:= LeftActingAlgebra( list[1] );
        if not ForAll( list, V -> IsIdenticalObj( LeftActingAlgebra(V), A ) )
           then Error( "all modules must have the same left acting algebra" );
        fi;

        V:= LeftAlgebraModuleByGenerators( A, left_action, gens );
    else

        if not ForAll( list, IsRightAlgebraModuleElementCollection ) then
            Error( "for all modules the algebra must act om the same side" );
        fi;

        A:= RightActingAlgebra( list[1] );
        if not ForAll( list, V -> IsIdenticalObj( RightActingAlgebra(V), A ) )
           then Error( "all modules must have the same left acting algebra" );
        fi;

        V:= RightAlgebraModuleByGenerators( A, right_action, gens );
    fi;

    if IsZero( gens[1] ) then
        return V;
    fi;

    # We construct a basis `B' of the direct sum.
    # This is a basis of an algebra module, so it works via a delegate
    # basis, which is a basis of the module spanned by the elements `gens'.
    # We call this module `W', and `BW' will be a basis of `W'.
    # Now `W' works via a nice basis and we know the basis vectors of this
    # nice basis (namely all unit vectors). So we set the attribute `NiceBasis'
    # of `BW' to be the standard basis of the full row space.

    W:= VectorSpace( F, gens, "basis" );
    SetNiceFreeLeftModule( W, niceMod );
    B:= Objectify( NewType( FamilyObj( V ), IsFiniteBasisDefault and
                 IsBasisOfAlgebraModuleElementSpace and
                 IsAttributeStoringRep ), rec() );
    SetUnderlyingLeftModule( B, V );
    SetBasisVectors( B, GeneratorsOfAlgebraModule(V) );

    BW:= Objectify( NewType( FamilyObj( W ), IsBasisByNiceBasis and
                                            IsAttributeStoringRep ), rec() );
    SetUnderlyingLeftModule( BW, W );
    SetBasisVectors( BW, gens );
    SetNiceBasis( BW, Basis( niceMod ) );

    B!.delegateBasis:= BW;
    SetBasis( V, B );
    SetDimension( V, Length( gens ) );
    return V;


end );


InstallOtherMethod( DirectSumOfAlgebraModules,
        "for two algebra modules",
        true, [ IsAlgebraModule, IsAlgebraModule ], 0,
        function( V, W )
    return DirectSumOfAlgebraModules( [ V, W ] );
end );

############################################################################
##
#M  TranslatorSubalgebra( <M>, <U>, <W> )
##
InstallMethod( TranslatorSubalgebra,
     "for an algebra, an algebra module and two subspaces", true,
     [ IsAlgebraModule, IsFreeLeftModule, IsFreeLeftModule ], 0,
     function( V, U, W )

     local alg, isleft, x, u, n, s, r, t, a, i, j, k, l, c, eqs, eqno, b, bas;

    if Dimension( U ) = 0 then
       return ActingAlgebra( V );
    fi;

    if IsLeftAlgebraModuleElementCollection( V ) then
       alg:= LeftActingAlgebra( V );
       isleft:= true;
    else
       alg:= RightActingAlgebra( V );
       isleft:= false;
    fi;

    if not IsFiniteDimensional( alg ) then
        Error("TranslatorSubalgebra works only when the acting algebra is finite-dimensional");
    fi;

    x:= BasisVectors( Basis( alg ) );
    u:= BasisVectors( Basis( U ) );

    n:= Dimension( alg );
    s:= Dimension( U );
    t:= Dimension( W );
    r:= Dimension( V );

    a:= List( [1..n], ii -> [] );

    for k in [1..n] do
        for i in [1..s] do
            if isleft then
               a[k][i]:= Coefficients( Basis(V), x[k]^u[i] );
            else
               a[k][i]:= Coefficients( Basis(V), u[i]^x[k] );
            fi;
        od;
    od;

    c:= List( [1..t], ii -> [] );
    for l in [1..t] do
        c[l]:= Coefficients( Basis(V), Basis(W)[l] );
    od;

    eqs:= NullMat( n+s*t, r*s, Zero( LeftActingDomain( alg ) ) );
    for j in [1..r] do
        for i in [1..s] do
            eqno:= j+(i-1)*r;
            for k in [1..n] do
                eqs[k][eqno]:= a[k][i][j];
            od;
            for l in [1..t] do
                eqs[n+i+(l-1)*s][eqno]:= -c[l][j];
            od;
        od;
    od;


    # Solve the equation system:
    b := NullspaceMat( eqs );

    # Extract the `algebra part' of the solution.
    bas:= List( b, e -> LinearCombination( Basis( alg ), e{[1..n]} ) );

    # If W is a sub-algebra-module, then the result is a subalgebra,
    # otherwise it is just a subspace.
    if HasIsAlgebraModule(W) and IsAlgebraModule( W ) then
       return SubalgebraNC( alg, bas, "basis" );
    else
       return Subspace( alg, bas, "basis" );
    fi;

end );

[Dauer der Verarbeitung: 0.61 Sekunden, vorverarbeitet 2026-05-01]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge