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


Impressum algebra.gi   Interaktion und
Portierbarkeitunbekannt

 
#############################################################################
##
##  This file is part of GAP, a system for computational discrete algebra.
##  This file's authors include Thomas Breuer, and 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 generic methods for algebras and algebras-with-one.
##


#############################################################################
##
#M  Representative( <A> ) . . . . . . . . one element of a left operator ring
##
InstallMethod( Representative,
    "for left operator ring with known generators",
    [ IsLeftOperatorRing and HasGeneratorsOfLeftOperatorRing ],
    RepresentativeFromGenerators( GeneratorsOfLeftOperatorRing ) );


#############################################################################
##
#M  Representative( <A> ) . . .  one element of a left operator ring-with-one
##
InstallMethod( Representative,
    "for left operator ring-with-one with known generators",
    [ IsLeftOperatorRingWithOne and HasGeneratorsOfLeftOperatorRingWithOne ],
    RepresentativeFromGenerators( GeneratorsOfLeftOperatorRingWithOne ) );


#############################################################################
##
#M  FLMLORByGenerators( <R>, <gens> ) . . . .  <R>-FLMLOR generated by <gens>
#M  FLMLORByGenerators( <R>, <gens>, <zero> )
##
InstallMethod( FLMLORByGenerators,
    "for ring and collection",
    [ IsRing, IsCollection ],
    function( R, gens )
    local A;
    A:= Objectify( NewType( FamilyObj( gens ),
                            IsFLMLOR and IsAttributeStoringRep ),
                   rec() );
    SetLeftActingDomain( A, R );
    SetGeneratorsOfLeftOperatorRing( A, AsList( gens ) );

    CheckForHandlingByNiceBasis( R, gens, A, false );
    return A;
    end );

InstallOtherMethod( FLMLORByGenerators,
    "for ring, homogeneous list, and ring element",
    [ IsRing, IsHomogeneousList, IsRingElement ],
    function( R, gens, zero )
    local A;
    A:= Objectify( NewType( CollectionsFamily( FamilyObj( zero ) ),
                            IsFLMLOR and IsAttributeStoringRep ),
                   rec() );
    SetLeftActingDomain( A, R );
    SetGeneratorsOfLeftOperatorRing( A, gens );
    SetZero( A, zero );

    if IsEmpty( gens ) then
      SetDimension( A, 0 );
      SetGeneratorsOfLeftModule( A, gens );
    fi;

    CheckForHandlingByNiceBasis( R, gens, A, zero );
    return A;
    end );


#############################################################################
##
#M  FLMLORWithOneByGenerators( <R>, <gens> )  unit. <R>-FLMLOR gen. by <gens>
#M  FLMLORWithOneByGenerators( <R>, <gens>, <zero> )
##
InstallMethod( FLMLORWithOneByGenerators,
    "for ring and collection",
    [ IsRing, IsCollection ],
    function( R, gens )
    local A;
    A:= Objectify( NewType( FamilyObj( gens ),
                            IsFLMLORWithOne and IsAttributeStoringRep ),
                   rec() );
    SetLeftActingDomain( A, R );
    SetGeneratorsOfLeftOperatorRingWithOne( A, AsList( gens ) );

    CheckForHandlingByNiceBasis( R, gens, A, false );
    return A;
    end );

InstallOtherMethod( FLMLORWithOneByGenerators,
    "for ring, homogeneous list, and ring element",
    [ IsRing, IsHomogeneousList, IsRingElement ],
    function( R, gens, zero )
    local A;
    A:= Objectify( NewType( CollectionsFamily( FamilyObj( zero ) ),
                            IsFLMLORWithOne and IsAttributeStoringRep ),
                   rec() );
    SetLeftActingDomain( A, R );
    SetGeneratorsOfLeftOperatorRingWithOne( A, AsList( gens ) );
    SetZero( A, zero );

    CheckForHandlingByNiceBasis( R, gens, A, zero );
    return A;
    end );


#############################################################################
##
#F  Algebra( <F>, <gens> )
#F  Algebra( <F>, <gens>, <zero> )
#F  Algebra( <F>, <gens>, "basis" )
#F  Algebra( <F>, <gens>, <zero>, "basis" )
##
InstallGlobalFunction( FLMLOR, function( arg )
    local A;

    # ring and list of generators
    if Length( arg ) = 2 and IsRing( arg[1] )
                         and IsList( arg[2] ) and 0 < Length( arg[2] ) then
      A:= FLMLORByGenerators( arg[1], arg[2] );

    # ring, list of generators plus zero
    elif Length( arg ) = 3 and IsRing( arg[1] )
                           and IsList( arg[2] ) then
      if arg[3] = "basis" then
        A:= FLMLORByGenerators( arg[1], arg[2] );
        UseBasis( A, arg[2] );
      else
        A:= FLMLORByGenerators( arg[1], arg[2], arg[3] );
      fi;

    # ring, list of generators plus zero
    elif Length( arg ) = 4 and IsRing( arg[1] )
                           and IsList( arg[2] )
                           and arg[4] = "basis" then
      A:= FLMLORByGenerators( arg[1], arg[2], arg[3] );
      UseBasis( A, arg[2] );

    # no argument given, error
    else
      Error( "usage: FLMLOR( <F>, <gens> ), ",
             "FLMLOR( <F>, <gens>, <zero> )" );
    fi;

    # Return the result.
    return A;
end );


#############################################################################
##
#F  Subalgebra( <A>, <gens> ) . . . . . subalgebra of <A> generated by <gens>
#F  Subalgebra( <A>, <gens>, "basis" )
##
InstallGlobalFunction( SubFLMLOR, function( arg )
    local S;
    if    Length( arg ) <= 1
       or not IsFLMLOR( arg[1] )
       or not IsHomogeneousList( arg[2] ) then
      Error( "first argument must be a FLMLOR,\n",
             "second argument must be a list of generators" );

    elif IsEmpty( arg[2] ) then

      return SubFLMLORNC( arg[1], arg[2] );

    elif     IsIdenticalObj( FamilyObj( arg[1] ),
                          FamilyObj( arg[2] ) )
         and ForAll( arg[2], v -> v in arg[1] ) then

      S:= FLMLORByGenerators( LeftActingDomain( arg[1] ), arg[2] );
      SetParent( S, arg[1] );
      if Length( arg ) = 3 and arg[3] = "basis" then
        UseBasis( S, arg[2] );
      fi;
      return S;

    fi;
    Error( "usage: SubFLMLOR( <V>, <gens> [, \"basis\"] )" );
end );


#############################################################################
##
#F  SubalgebraNC( <A>, <gens>, "basis" )
#F  SubalgebraNC( <A>, <gens> )
##
InstallGlobalFunction( SubFLMLORNC, function( arg )
    local S;
    if IsEmpty( arg[2] ) then
      S:= Objectify( NewType( FamilyObj( arg[1] ),
                                  IsFLMLOR
                              and IsTrivial
                              and IsTwoSidedIdealInParent
                              and IsAttributeStoringRep ),
                     rec() );
      SetDimension(S, 0);
      SetLeftActingDomain( S, LeftActingDomain( arg[1] ) );
      SetGeneratorsOfLeftModule( S, AsList( arg[2] ) );
    else
      S:= FLMLORByGenerators( LeftActingDomain( arg[1] ), arg[2] );
    fi;
    if Length( arg ) = 3 and arg[3] = "basis" then
      UseBasis( S, arg[2] );
    fi;
    SetParent( S, arg[1] );
    return S;
end );


#############################################################################
##
#F  AlgebraWithOne( <F>, <gens> )
#F  AlgebraWithOne( <F>, <gens>, <zero> )
#F  AlgebraWithOne( <F>, <gens>, "basis" )
#F  AlgebraWithOne( <F>, <gens>, <zero>, "basis" )
##
InstallGlobalFunction( FLMLORWithOne, function( arg )
    local A;

    # ring and list of generators
    if Length( arg ) = 2 and IsRing( arg[1] )
                         and IsList( arg[2] ) and 0 < Length( arg[2] ) then
      A:= FLMLORWithOneByGenerators( arg[1], arg[2] );

    # ring, list of generators plus zero
    elif Length( arg ) = 3 and IsRing( arg[1] )
                           and IsList( arg[2] ) then
      if arg[3] = "basis" then
        A:= FLMLORWithOneByGenerators( arg[1], arg[2] );
        UseBasis( A, arg[2] );
      else
        A:= FLMLORWithOneByGenerators( arg[1], arg[2], arg[3] );
      fi;

    # ring, list of generators plus zero
    elif Length( arg ) = 4 and IsRing( arg[1] )
                           and IsList( arg[2] )
                           and arg[4] = "basis" then
      A:= FLMLORWithOneByGenerators( arg[1], arg[2], arg[3] );
      UseBasis( A, arg[2] );

    # no argument given, error
    else
      Error( "usage: FLMLORWithOne( <F>, <gens> ), ",
             "FLMLORWithOne( <F>, <gens>, <zero> )" );
    fi;

    # Return the result.
    return A;
end );


#############################################################################
##
#F  SubalgebraWithOne( <A>, <gens> )   subalg.-with-one of <A> gen. by <gens>
##
InstallGlobalFunction( SubFLMLORWithOne, function( arg )
    local S;
    if Length( arg ) <= 1 or not IsFLMLOR( arg[1] )
                          or not IsHomogeneousList( arg[2] ) then

      Error( "first argument must be a FLMLOR,\n",
             "second argument must be a list of generators" );

    elif IsEmpty( arg[2] ) then

      return SubFLMLORWithOneNC( arg[2], arg[2] );

    elif     IsIdenticalObj( FamilyObj( arg[1] ),
                          FamilyObj( arg[2] ) )
         and ForAll( arg[2], v -> v in arg[1] )
         and ( IsFLMLORWithOne( arg[1] ) or One( arg[1] ) <> fail ) then
      S:= FLMLORWithOneByGenerators( LeftActingDomain( arg[1] ), arg[2] );
      SetParent( S, arg[1] );
      if Length( arg ) = 3 and arg[3] = "basis" then
        UseBasis( S, arg[2] );
      fi;
      return S;
    fi;
    Error( "usage: SubFLMLORWithOne( <V>, <gens> [, \"basis\"] )" );
end );


#############################################################################
##
#F  SubalgebraWithOneNC( <A>, <gens> )
##
InstallGlobalFunction( SubFLMLORWithOneNC, function( arg )
    local S, gens;
    if IsEmpty( arg[2] ) then

      # Note that `S' is in general not trivial,
      # and if we call `Objectify' here then `S' does not get a special
      # representation (e.g., as a matrix algebra).
      # So the argument that special methods would catch this case
      # does not hold!
      gens:= [ One( arg[1] ) ];
      S:= FLMLORWithOneByGenerators( LeftActingDomain( arg[1] ), gens );
      UseBasis( S, gens );

    else

      S:= FLMLORWithOneByGenerators( LeftActingDomain( arg[1] ), arg[2] );
      if Length( arg ) = 3 and arg[3] = "basis" then
        UseBasis( S, arg[2] );
      fi;

    fi;

    SetParent( S, arg[1] );
    return S;
end );


#############################################################################
##
#M  LieAlgebraByDomain( <A> )
##
##  The Lie algebra of the associative algebra <A>
##
InstallMethod( LieAlgebraByDomain,
    "for an algebra",
    [ IsAlgebra ],
    function( A )
       local T, n, zero, nullvec, S, i, j, k, m, cfs, cij, cji;

       if not IsAssociative( A ) then TryNextMethod(); fi;

# We construct a structure constants table for the  Lie algebra
# corresponding to <A>. If the structure constants of <A> are given by
# d_{ij}^k, then the structure constants of the Lie algebra will be given
# by d_{ij}^k - d_{ji}^k.


       T:= StructureConstantsTable( Basis( A ) );
       n:= Dimension( A );
       zero:= Zero( LeftActingDomain( A ) );
       nullvec:= List( [1..n], x -> zero );
       S:= EmptySCTable( n, zero, "antisymmetric" );
       for i in [1..n] do
         for j in [i+1..n] do
           cfs:= ShallowCopy( nullvec );
           cij:= T[i][j]; cji:= T[j][i];
           for m in [1..Length(cij[1])] do
             k:= cij[1][m];
             cfs[k]:= cfs[k] + cij[2][m];
           od;
           for m in [1..Length(cji[1])] do
             k:= cji[1][m];
             cfs[k]:= cfs[k] - cji[2][m];
           od;

           cij:= [ ];

           for m in [1..n] do
             if cfs[m] <> zero then
                 Add( cij, cfs[m] );
                 Add( cij, m );
             fi;
           od;
           SetEntrySCTable( S, i, j, cij );
         od;
       od;

       return LieAlgebraByStructureConstants( LeftActingDomain( A ), S );
  end );


#############################################################################
##
#F  LieAlgebra( <A> )
#F  LieAlgebra( <F>, <gens> )
#F  LieAlgebra( <F>, <gens>, <zero> )
#F  LieAlgebra( <F>, <gens>, "basis" )
#F  LieAlgebra( <F>, <gens>, <zero>, "basis" )
##
InstallGlobalFunction( LieAlgebra, function( arg )
#T check that the families have the same characteristic?
#T `CharacteristicFamily' ?
    local A,gens;

    # In the case of one domain argument,
    # construct the isomorphic Lie algebra.
    if Length( arg ) = 1 and IsDomain( arg[1] ) then
      A:= LieAlgebraByDomain( arg[1] );

    # division ring and list of generators
    elif Length( arg ) >= 2 and IsList( arg[2] ) then

       gens:= List( arg[2], x -> LieObject( x ) );

       if Length( arg ) = 2 and IsDivisionRing( arg[1] )
                            and 0 < Length( arg[2] ) then
         A:= AlgebraByGenerators( arg[1], gens );

       # division ring, list of generators plus zero
       elif Length( arg ) = 3 and IsDivisionRing( arg[1] ) then
          if arg[3] = "basis" then
            A:= AlgebraByGenerators( arg[1], gens );
            UseBasis( A, gens );
          else
            A:= AlgebraByGenerators( arg[1], gens, arg[3] );
          fi;

       # division ring, list of generators plus zero
       elif Length( arg ) = 4 and IsDivisionRing( arg[1] )
                              and arg[4] = "basis" then
          A:= AlgebraByGenerators( arg[1], gens, arg[3] );
          UseBasis( A, gens );

       else
         Error( "usage: LieAlgebra( <F>, <gens> ), ",
              "LieAlgebra( <F>, <gens>, <zero> ), LieAlgebra( <D> )");

       fi;
    # no argument given, error
    else
      Error( "usage: LieAlgebra( <F>, <gens> ), ",
             "LieAlgebra( <F>, <gens>, <zero> ), LieAlgebra( <D> )");
    fi;

    # Return the result.
    return A;
end );


#############################################################################
##
#F  EmptySCTable( <dim>, <zero> )
#F  EmptySCTable( <dim>, <zero>, \"symmetric\" )
#F  EmptySCTable( <dim>, <zero>, \"antisymmetric\" )
##
InstallGlobalFunction( EmptySCTable, function( arg )
    local dim, T, entry, i;

    if     2 <= Length( arg )
       and IsInt( arg[1] ) and IsZero( arg[2] )
       and ( Length( arg ) = 2 or IsString( arg[3] ) ) then

      dim:= arg[1];
      T:= [];
      entry:= Immutable( [ [], [] ] );
      for i in [ 1 .. dim ] do
        T[i]:= List( [ 1 .. dim ], x -> entry );
      od;

      # Store the symmetry flag.
      if Length( arg ) = 3 then
        if   arg[3] = "symmetric" then
          Add( T, 1 );
        elif arg[3] = "antisymmetric" then
          Add( T, -1 );
        else
          Error("third argument must be \"symmetric\" or \"antisymmetric\"");
        fi;
      else
        Add( T, 0 );
      fi;

      # Store the zero coefficient.
      Add( T, arg[2] );

    else
      Error( "usage: EmptySCTable( <dim>, <zero> [,\"symmetric\"] )" );
    fi;

    return T;
end );


#############################################################################
##
#F  SetEntrySCTable( <T>, <i>, <j>, <list> )
##
InstallGlobalFunction( SetEntrySCTable, function( T, i, j, list )
    local range, zero, Fam, entry, k, val, pos;

    # Check that `i' and `j' are admissible.
    range:= [ 1 .. Length( T ) - 2 ];
    if   not i in range then
      Error( "<i> must lie in ", range );
    elif not j in range then
      Error( "<j> must lie in ", range );
    fi;

    # Check `list', and construct the table entry.
    zero:= Last(T);
    Fam:= FamilyObj( zero );
    entry:= [ [], [] ];
    for k in [ 1, 3 .. Length( list ) -1 ] do

      val:= list[k];
      pos:= list[k+1];

      # Check that `pos' is inside the table,
      # and that its entry is assigned only once.
      if not pos in range then
        Error( "list entry ", list[k+1], " must lie in ", range );
      elif pos in entry[1] then
        Error( "position ", pos, " must occur at most once in <list>" );
      fi;

      # Check that the coefficients either fit to the zero element
      # or are rationals (with suitable denominators).
      if FamilyObj( val ) = Fam then
        if val <> zero then
          Add( entry[1], pos );
          Add( entry[2], val );
        fi;
      elif IsRat( val ) then
        if val <> 0 then
          Add( entry[1], pos );
          Add( entry[2], val * One( zero ) );
        fi;
      else
        Error( "list entry ", list[k], " does not fit to zero element" );
      fi;

    od;

    # Set the table entry.
    SortParallel( entry[1], entry[2] );
    T[i][j]:= Immutable( entry );

    # Add the value `T[j][i]' in the case of (anti-)symmetric tables.
    if   T[ Length(T) - 1 ] =  1 then
      T[j][i]:= T[i][j];
    elif T[ Length(T) - 1 ] = -1 then
      T[j][i]:= Immutable( [ entry[1], -entry[2] ] );
    fi;
end );


#############################################################################
##
#F  ReducedSCTable( <T>, <one> )
##
InstallGlobalFunction( ReducedSCTable, function( T, one )
    local new, n, i, j, entry;

    new:= [];
    n:= Length( T ) - 2;

    # Reduce the entries.
    for i in [ 1 .. n ] do
      new[i]:= [];
      for j in [ 1 .. n ] do
        entry:= T[i][j];
        entry:= [ Immutable( entry[1] ), entry[2] * one ];
        MakeImmutable( entry );
        new[i][j]:= entry;
      od;
    od;

    # Store zero coefficient and symmetry flag.
    new[ n+1 ]:= T[ n+1 ];
    new[ n+2 ]:= T[ n+2 ] * one;

    # Return the immutable new table.
    MakeImmutable( new );
    return new;
end );


#############################################################################
##
#F  GapInputSCTable( <T>, <varnam> )
##
InstallGlobalFunction( GapInputSCTable, function( T, varnam )
    local dim, str, lower, i, j, entry, k;

    # Initialize, and set the ranges for the loops.
    dim:= Length( T ) - 2;
    str:= Concatenation( varnam, ":= EmptySCTable( ",
                         String( dim ), ", ", String( Last(T) ) );
    lower:= [ 1 .. dim ];
    if   T[ dim+1 ] =  1 then
      Append( str, ", \"symmetric\"" );
    elif T[ dim+1 ] = -1 then
      Append( str, ", \"antisymmetric\"" );
    else
      lower:= ListWithIdenticalEntries( dim, 1 );
    fi;
    Append( str, " );\n" );

    # Fill up the table.
    for i in [ 1 .. dim ] do
      for j in [ lower[i] .. dim ] do
        entry:= T[i][j];
        if not IsEmpty( entry[1] ) then
          Append( str, "SetEntrySCTable( " );
          Append( str, varnam );
          Append( str, ", " );
          Append( str, String(i) );
          Append( str, ", " );
          Append( str, String(j) );
          Append( str, ", [" );
          for k in [ 1 .. Length( entry[1] )-1 ] do
            Append( str, String( entry[2][k] ) );
            Add( str, ',' );
            Append( str, String( entry[1][k] ) );
            Add( str, ',' );
          od;
          k:= Length( entry[1] );
          Append( str, String( entry[2][k] ) );
          Add( str, ',' );
          Append( str, String( entry[1][k] ) );
          Append( str, "] );\n" );
        fi;
      od;
    od;

    ConvertToStringRep( str );
    return str;
end );


#############################################################################
##
#F  IdentityFromSCTable( <T> )
##
InstallGlobalFunction( IdentityFromSCTable, function( T )
    local n,       # dimension of the underlying algebra
          equ,     # equation system to solve
          zero,    # zero of the field
          zerovec, # zero vector
          vec,     # right hand side of the equation system
          one,     # identity of the field
          i, j, k, # loop over rows of `equ'
          row,     # one row of the equation system
          Tpos,    #
          Tval,    #
          p,       #
          sol,
          sum;

    n:= Length( T ) - 2;
    zero:= T[ n+2 ];

    # If the table belongs to a trivial algebra,
    # the identity is equal to the zero.
    if n = 0 then
      return EmptyRowVector( FamilyObj( zero ) );
    fi;

    # Set up the equation system,
    # in row $i$ and column $(k-1)*n + j$ we have $c_{ijk}$.
    equ:= [];
    zerovec:= ListWithIdenticalEntries( n^2, zero );
    vec:= ShallowCopy( zerovec );
    one:= One( zero );

    for i in [ 1 .. n ] do
      row:= ShallowCopy( zerovec );
      for j in [ 1 .. n ] do
        Tpos:= T[i][j][1];
        Tval:= T[i][j][2];
        p:= (j-1)*n;
        for k in [ 1 .. Length( Tpos ) ] do
          row[ p + Tpos[k] ]:= Tval[k];
        od;
      od;
      Add( equ, row );
      vec[ (i-1)*n + i ]:= one;
    od;

    sol:= SolutionMat( equ, vec );

    # If we have a candidate and if the algebra is not known
    # to be commutative then check whether the candidate
    # acts trivially also from the right.
    if sol <> fail and T[ n+1 ] <> 1 then

      for j in [ 1 .. n ] do
        for k in [ 1 .. n ] do
          sum:= zero;
          for i in [ 1 .. n ] do
            Tpos:= T[j][i];
            p:= Position( Tpos[1], k );
#T cheaper !!!
            if p <> fail then
              sum:= sum + sol[i] * Tpos[2][p];
            fi;
          od;
          if ( j = k and sum <> one ) or ( j <> k and sum <> zero ) then
            return fail;
          fi;
        od;
      od;

    fi;

    # Return the result.
    return sol;
end );


#############################################################################
##
#F  QuotientFromSCTable( <T>, <num>, <den> )
##
##  We solve the equation system $<num> = x <den>$.
##  If no solution exists, `fail' is returned.
##
##  In terms of the basis $B$ with vectors $b_1, \ldots, b_n$ this means
##  for $<num> = \sum_{i=1}^n a_i b_i$,
##      $<den> = \sum_{i=1}^n c_i b_i$,
##      $x     = \sum_{i=1}^n x_i b_i$ that
##  $a_k = \sum_{i,j} c_i x_j c_{ijk}$ for all $k$.
##  Here $c_{ijk}$ denotes the structure constants w.r.t. $B$.
##  This means $a = x M$ with $M_{ik} = \sum_{j=1}^n c_{ijk} c_j$.
##
InstallGlobalFunction( QuotientFromSCTable, function( T, x, c )
    local M,        # matrix of the equation system
          n,        # dimension of the algebra
          zero,     # zero vector
          i, j,     # loop variables
          row,      # one row of `M'
          entry,    #
          val;      #

    M:= [];
    n:= Length( c );

    # If the algebra is zero dimensional,
    # the zero is also the identity and thus also its inverse.
    if n = 0 then
      return c;
    fi;

    zero:= ListWithIdenticalEntries( n, Last(T) );
    for i in [ 1 .. n ] do
      row:= ShallowCopy( zero );
      for j in [ 1 .. n ] do
        entry:= T[i][j];
        val:= c[j];
        row{ entry[1] }:= row{ entry[1] } + val * entry[2];
#T better!
      od;
      Add( M, row );
    od;

    # Return the quotient, or `fail'.
    return SolutionMat( M, x );
end );


#############################################################################
##
#F  TestJacobi( <T> )
##
##  We check whether for all $1 \leq m \leq n$ the equality
##  $\sum_{l=1}^n c_{jkl} c_{ilm} + c_{kil} c_{jlm} + c_{ijl} c_{klm} = 0$
##  holds.
##
InstallGlobalFunction( TestJacobi, function( T )
    local zero,           # the zero of the field
          n,              # dimension of the algebra
          i, j, k, m,     # loop variables
          cij, cki, cjk,  # structure constant vectors
          sum,
          t;

    zero:= Last(T);
    n:= Length( T ) - 2;

    for i in [ 1 .. n ] do
      for j in [ i+1 .. n ] do
        cij:= T[i][j];
        for k in [ j+1 .. n ] do
          cki:= T[k][i];
          cjk:= T[j][k];
          for m in [ 1 .. n ] do
            sum:= zero;
            for t in [ 1 .. Length( cjk[1] ) ] do
              sum:= sum + cjk[2][t] * SCTableEntry( T, i, cjk[1][t], m );
            od;
            for t in [ 1 .. Length( cki[1] ) ] do
              sum:= sum + cki[2][t] * SCTableEntry( T, j, cki[1][t], m );
            od;
            for t in [ 1 .. Length( cij[1] ) ] do
              sum:= sum + cij[2][t] * SCTableEntry( T, k, cij[1][t], m );
            od;
            if sum <> zero then
              return [ i, j, k ];
            fi;
          od;
        od;
      od;
    od;

    return true;
end );


#############################################################################
##
#M  MultiplicativeNeutralElement( <A> )
##
##  is the multiplicative neutral element of <A> if this exists,
##  otherwise is `fail'.
##
##  Let $(b_1, b_2, \ldots, b_n)$ be a basis of $A$, and $e$ the result of
##  `MultiplicativeNeutralElement( <A> )'.
##  Then $e = \sum_{i=1}^n a_i b_i$, and for $1 \leq k \leq n$ we have
##  $e \cdot b_j = b_j$, or equivalently
##  $\sum_{i=1}^n a_i b_i \cdot b_j = b_j$.
##  Define the structure constants by
##  $b_i \cdot b_j = \sum_{k=1}^n c_{ijk} b_k$.
##
##  Then $\sum_{i=1}^n a_i c_{ijk} = \delta_{jk}$ for $1 \leq k \leq n$.
##
##  This yields $n^2$ linear equations for the $n$ indeterminates $a_i$,
##  and a solution is a left identity.
##  For this we have to test whether it is also a right identity.
##
InstallMethod( MultiplicativeNeutralElement,
    [ IsFLMLOR and IsFiniteDimensional ],
    function( A )
    local B,       # basis of `A'
          one;     # result

    B:= Basis( A );
    one:= IdentityFromSCTable( StructureConstantsTable( B ) );
    if one <> fail then
      one:= LinearCombination( B, one );
    fi;
    return one;
    end );


#############################################################################
##
#M  IsAssociative( <A> )
##
##  We check whether the vectors of a basis satisfy the associativity law.
##  (Bilinearity of the multiplication is of course assumed.)
##
##  If $b_i \cdot b_j = \sum_{l=1}^n c_{ijl} b_l$ then we have
##  $b_i \cdot ( b_j \cdot b_k ) = ( b_i \cdot b_j ) \cdot b_k$
##  if and only if
##  $\sum_{l=1}^n c_{jkl} c_{ilm} = \sum_{l=1}^n c_{ijl} c_{lkm}$ for all
##  $1 \leq m \leq n$.
##
##  We check this equality for all $1 \leq i, j, k \leq n$.
##
InstallMethod( IsAssociative,
    "generic method for a (finite dimensional) FLMLOR",
    [ IsFLMLOR ],
    function( A )
    local T,            # structure constants table w.r.t. a basis of `A'
          zero,
          range,
          i, j, k, l, m,
          Ti,
          Tj,
          cijpos,
          cijval,
          cjkpos,
          cjkval,
          sum,
          x,
          pos;

    if not IsFiniteDimensional( A ) then
      TryNextMethod();
    fi;

    T:= StructureConstantsTable( Basis( A ) );
    zero:= Zero( LeftActingDomain( A ) );
    range:= [ 1 .. Length( T[1] ) ];
    for i in range do
      Ti:= T[i];
      for j in range do
        cijpos:= Ti[j][1];
        cijval:= Ti[j][2];
        Tj:= T[j];
        for k in range do
          cjkpos:= Tj[k][1];
          cjkval:= Tj[k][2];
          for m in range do
            sum:= zero;
            for l in [ 1 .. Length( cjkpos ) ] do
              x:= Ti[ cjkpos[l] ];
              pos:= Position( x[1], m );
              if pos <> fail then
                sum:= sum + cjkval[l] * x[2][ pos ];
              fi;
            od;
            for l in [ 1 .. Length( cijpos ) ] do

              x:= T[ cijpos[l] ][k];
              pos:= Position( x[1], m );
              if pos <> fail then
                sum:= sum - cijval[l] * x[2][ pos ];
              fi;
            od;
            if sum <> zero then
              # $i, j, k$ fail
              Info( InfoAlgebra, 2,
                    "IsAssociative fails for i = ", i, ", j = ", j,
                    ", k = ", k );
              return false;
            fi;
          od;
        od;
      od;
    od;
    return true;
    end );


#############################################################################
##
#M  IsAnticommutative( <A> )  . . . . . . . . . . . . .for a fin.-dim. FLMLOR
##
##  is `true' if the multiplication in <A> is anticommutative,
##  and `false' otherwise.
##
InstallMethod( IsAnticommutative,
    "generic method for a (finite dimensional) FLMLOR",
    [ IsFLMLOR ],
    function( A )
    local n,      # dimension of `A'
          T,      # table of structure constants for `A'
          i, j;   # loop over rows and columns ot `T'

    if not IsFiniteDimensional( A ) then
      TryNextMethod();
    fi;

    n:= Dimension( A );
    T:= StructureConstantsTable( Basis( A ) );
    for i in [ 2 .. n ] do
      for j in [ 1 .. i-1 ] do
        if    T[i][j][1] <> T[j][i][1]
           or ( not IsEmpty( T[i][j][1] )
                and PositionNonZero( T[i][j][2] + T[j][i][2] )
                        <= Length( T[i][j][2] ) ) then
          return false;
        fi;
      od;
    od;

    if Characteristic( A ) <> 2 then

      # The values on the diagonal must be zero.
      for i in [ 1 .. n ] do
        if not IsEmpty( T[i][i][1] ) then
          return false;
        fi;
      od;

    fi;

    return true;
    end );


#############################################################################
##
#M  IsCommutative( <A> )  . . . . . . . . . . . for finite dimensional FLMLOR
##
##  Check whether every basis vector commutes with every basis vector.
##
InstallMethod( IsCommutative,
    "generic method for a finite dimensional FLMLOR",
    [ IsFLMLOR ],
    IsCommutativeFromGenerators( GeneratorsOfVectorSpace ) );
#T use structure constants!


#############################################################################
##
#M  IsCommutative( <A> )  . . . . . . . . . . . . . for an associative FLMLOR
##
##  If <A> is associative then we can restrict the check to a smaller
##  equation system than that for arbitrary algebras, since we have to check
##  $x a = a x$ only for algebra generators $a$ and $x$, not for all vectors
##  of a basis.
##
InstallMethod( IsCommutative,
    "for an associative FLMLOR",
    [ IsFLMLOR and IsAssociative ],
    IsCommutativeFromGenerators( GeneratorsOfAlgebra ) );

InstallMethod( IsCommutative,
    "for an associative FLMLOR-with-one",
    [ IsFLMLORWithOne and IsAssociative ],
    IsCommutativeFromGenerators( GeneratorsOfAlgebraWithOne ) );


#############################################################################
##
#M  IsZeroSquaredRing( <A> )  . . . . . . . . for a finite dimensional FLMLOR
##
InstallMethod( IsZeroSquaredRing,
    "for a finite dimensional FLMLOR",
    [ IsFLMLOR ],
    function( A )

    if not IsAnticommutative( A ) then

      # Every zero squared ring is anticommutative.
      return false;

    elif ForAny( BasisVectors( Basis( A ) ),
                 x -> not IsZero( x*x ) ) then

      # If not all basis vectors are zero squared then we return `false'.
      return false;

    elif IsCommutative( LeftActingDomain( A ) ) then

      # If otherwise the left acting domain is commutative then we return
      # `true' because we know that <A> is anticommutative and the basis
      # vectors are zero squared.
      return true;

    else

      # Otherwise we give up.
      TryNextMethod();

    fi;
    end );


#############################################################################
##
#M  IsJacobianRing( <A> )
##
InstallMethod( IsJacobianRing,
    "for a (finite dimensional) FLMLOR",
    [ IsFLMLOR ],
    function( A )
    local n,   # dimension of `A'
          T,   # table of structure constants for `A'
          i;   # loop over the diagonal of `T'

    if not IsFiniteDimensional( A ) then
      TryNextMethod();
    fi;

    # In characteristic 2 we have to make sure that $a \* a = 0$.
#T really?
    T:= StructureConstantsTable( Basis( A ) );
    if Characteristic( A ) = 2 then
      n:= Dimension( A );
      for i in [ 1 .. n ] do
        if not IsEmpty( T[i][i][1] ) then
          return false;
        fi;
      od;
    fi;

    # Check the Jacobi identity $[a,[b,c]] + [b,[c,a]] + [c,[a,b]] = 0$.
    return TestJacobi( T ) = true;
    end );


#############################################################################
##
#M  Intersection2( <A1>, <A2> ) . . . . . . . . . intersection of two FLMLORs
##
InstallMethod( Intersection2,
    "generic method for two FLMLORs",
    IsIdenticalObj,
    [ IsFLMLOR, IsFLMLOR ],
    Intersection2Spaces( AsFLMLOR, SubFLMLORNC, FLMLOR ) );


#############################################################################
##
#M  Intersection2( <A1>, <A2> ) . . . .  intersection of two FLMLORs-with-one
##
InstallMethod( Intersection2,
    "generic method for two FLMLORs-with-one",
    IsIdenticalObj,
    [ IsFLMLORWithOne, IsFLMLORWithOne ],
    Intersection2Spaces( AsFLMLORWithOne, SubFLMLORWithOneNC,
                         FLMLORWithOne ) );


#############################################################################
##
#M  \/( <A>, <I> )  . . . . . . . . . . . .  factor of an algebra by an ideal
#M  \/( <A>, <relators> ) . . . . . . . . .  factor of an algebra by an ideal
##
##  is the factor algebra of the finite dimensional algebra <A> modulo
##  the ideal <I> or the ideal spanned by the collection <relators>.
##
InstallOtherMethod( \/,
    "for FLMLOR and collection",
    IsIdenticalObj,
    [ IsFLMLOR, IsCollection ],
    function( A, relators )
    if IsFLMLOR( relators ) then
      TryNextMethod();
    else
      return A / TwoSidedIdealByGenerators( A, relators );
    fi;
    end );

InstallOtherMethod( \/,
    "for FLMLOR and empty list",
    [ IsFLMLOR, IsList and IsEmpty ],
    function( A, empty )
    # `NaturalHomomorphismByIdeal( A, TrivialSubFLMLOR( A ) )' is the
    # identity mapping on `A', and `ImagesSource' of it yields `A'.
    return A;
    end );

InstallOtherMethod( \/,
    "generic method for two FLMLORs",
    IsIdenticalObj,
    [ IsFLMLOR, IsFLMLOR ],
    function( A, I )
    return ImagesSource( NaturalHomomorphismByIdeal( A, I ) );
    end );


#############################################################################
##
#M  TrivialSubadditiveMagmaWithZero( <A> )  . . . . . . . . . .  for a FLMLOR
##
InstallMethod( TrivialSubadditiveMagmaWithZero,
    "for a FLMLOR",
    [ IsFLMLOR ],
    A -> SubFLMLORNC( A, [] ) );


#############################################################################
##
#M  AsFLMLOR( <R>, <D> )  . . view a collection as a FLMLOR over the ring <R>
##
InstallMethod( AsFLMLOR,
    "for a ring and a collection",
    [ IsRing, IsCollection ],
    function( F, D )
    local A, L;

    D:= AsSSortedList( D );
    L:= ShallowCopy( D );
    A:= TrivialSubFLMLOR( AsFLMLOR( F, D ) );
    SubtractSet( L, AsSSortedList( A ) );
    while 0 < Length(L)  do
      A:= ClosureLeftOperatorRing( A, L[1] );
#T call explicit function that maintains an elements list?
      SubtractSet( L, AsSSortedList( A ) );
    od;
    if Length( AsList( A ) ) <> Length( D )  then
      return fail;
    fi;
    A:= FLMLOR( F, GeneratorsOfLeftOperatorRing( A ), Zero( D[1] ) );
    SetAsSSortedList( A, D );
    SetSize( A, Length( D ) );
    SetIsFinite( A, true );
#T ?

    # Return the FLMLOR.
    return A;
    end );


#############################################################################
##
#M  AsFLMLOR( <F>, <V> )  . . view a left module as FLMLOR over the field <F>
##
##  is an algebra over <F> that is equal (as set) to <V>.
##  For that, perhaps the field of <A> has to be changed before
##  getting the correct list of generators.
##
InstallMethod( AsFLMLOR,
    "for a division ring and a free left module",
    [ IsDivisionRing, IsFreeLeftModule ],
    function( F, V )
    local L, A;

    if   LeftActingDomain( V ) = F then

      A:= FLMLOR( F, GeneratorsOfLeftModule( V ) );
      if A <> V then
        return fail;
      fi;
      if HasBasis( V ) then
        SetBasis( A, Basis( V ) );
      fi;

    elif IsTrivial( V ) then

      # We need the zero.
      A:= FLMLOR( F, [], Zero( V ) );

    elif IsSubset( LeftActingDomain( V ), F ) then

      # Make sure that the field change does not change the elements.
      L:= BasisVectors( Basis( AsField( F, LeftActingDomain(V) ) ) );
      L:= Concatenation( List( L, x -> List( GeneratorsOfLeftModule( V ),
                                             y -> x * y ) ) );
      A:= FLMLOR( F, L );
      if A <> V then
        return fail;
      fi;

    elif IsSubset( F, LeftActingDomain( V ) ) then

      # Make sure that the field change does not change the elements.
      L:= BasisVectors( Basis( AsField( LeftActingDomain(V), F ) ) );
      if ForAny( L, x -> ForAny( GeneratorsOfLeftModule( V ),
                                 y -> not x * y in V ) ) then
        return fail;
      fi;
      A:= FLMLOR( F, GeneratorsOfLeftModule( V ) );
      if A <> V then
        return fail;
      fi;

    else

      V:= AsFLMLOR( Intersection( F, LeftActingDomain( V ) ), V );
      return AsFLMLOR( F, V );

    fi;

    UseIsomorphismRelation( V, A );
    UseSubsetRelation( V, A );

    return A;
    end );


#############################################################################
##
#M  AsFLMLOR( <F>, <A> )  . . . view an algebra as algebra over the field <F>
##
##  is an algebra over <F> that is equal (as set) to <D>.
##  For that, perhaps the field of <A> has to be changed before
##  getting the correct list of generators.
##
InstallMethod( AsFLMLOR,
    "for a division ring and an algebra",
    [ IsDivisionRing, IsFLMLOR ],
    function( F, D )
    local L, A;

    if   LeftActingDomain( D ) = F then

      return D;

    elif IsTrivial( D ) then

      # We need the zero.
      A:= FLMLOR( F, [], Zero( D ) );

    elif IsSubset( LeftActingDomain( D ), F ) then

      # Make sure that the field change does not change the elements.
      L:= BasisVectors( Basis( AsField( F, LeftActingDomain(D) ) ) );
      L:= Concatenation( List( L, x -> List( GeneratorsOfAlgebra( D ),
                                             y -> x * y ) ) );
      A:= FLMLOR( F, L );

    elif IsSubset( F, LeftActingDomain( D ) ) then

      # Make sure that the field change does not change the elements.
      L:= BasisVectors( Basis( AsField( LeftActingDomain(D), F ) ) );
      if ForAny( L, x -> ForAny( GeneratorsOfAlgebra( D ),
                                 y -> not x * y in D ) ) then
        return fail;
      fi;
      A:= FLMLOR( F, GeneratorsOfAlgebra( D ) );

    else

      D:= AsFLMLOR( Intersection( F, LeftActingDomain( D ) ), D );
      return AsFLMLOR( F, D );

    fi;

    UseIsomorphismRelation( D, A );
    UseSubsetRelation( D, A );
    return A;
    end );


#############################################################################
##
#M  AsFLMLORWithOne( <R>, <D> ) . . . . . . view a coll. as a FLMLOR-with-one
##
InstallMethod( AsFLMLORWithOne,
    "for a ring and a collection",
    [ IsRing, IsCollection ],
    function( F, D )
    return AsFLMLORWithOne( AsFLMLOR( F, D ) );
    end );


#############################################################################
##
#M  AsFLMLORWithOne( <F>, <V> ) . . view a left module as an algebra-with-one
##
InstallMethod( AsFLMLORWithOne,
    "for a division ring and a free left module",
    [ IsDivisionRing, IsFreeLeftModule ],
    function( F, V )
    local L, A;

    # Check that `V' contains the identity.
    if One( V ) = fail then

      return fail;

    elif LeftActingDomain( V ) = F then

      A:= FLMLORWithOne( F, GeneratorsOfLeftModule( V ) );
      if A <> V then
        return fail;
      fi;

      # Left module generators and basis are maintained.
      if HasGeneratorsOfLeftModule( V ) then
        SetGeneratorsOfLeftModule( A, GeneratorsOfLeftModule( V ) );
      fi;
      if HasBasis( V ) then
        SetBasis( A, Basis( V ) );
      fi;

    elif IsSubset( LeftActingDomain( V ), F ) then

      # Make sure that the field change does not change the elements.
      L:= BasisVectors( Basis( AsField( F, LeftActingDomain(V) ) ) );
      L:= Concatenation( List( L, x -> List( GeneratorsOfLeftModule( V ),
                                             y -> x * y ) ) );
      A:= FLMLORWithOne( F, L );
      if A <> V then
        return fail;
      fi;

    elif IsSubset( F, LeftActingDomain( V ) ) then

      # Make sure that the field change does not change the elements.
      L:= BasisVectors( Basis( AsField( LeftActingDomain(V), F ) ) );
      if ForAny( L, x -> ForAny( GeneratorsOfLeftModule( V ),
                                 y -> not x * y in V ) ) then
        return fail;
      fi;
      A:= FLMLORWithOne( F, GeneratorsOfLeftModule( V ) );
      if A <> V then
        return fail;
      fi;

    else

      # Note that we need not use the isomorphism and subset relations
      # (see below) because this is the task of the calls to
      # `AsAlgebraWithOne'.
      A:= AsAlgebraWithOne( Intersection( F, LeftActingDomain( V ) ), V );
      return AsAlgebraWithOne( F, A );

    fi;

    UseIsomorphismRelation( V, A );
    UseSubsetRelation( V, A );
    return A;
    end );


#############################################################################
##
#M  AsFLMLORWithOne( <F>, <D> ) . . .  view an algebra as an algebra-with-one
##
InstallMethod( AsFLMLORWithOne,
    "for a division ring and an algebra",
    [ IsDivisionRing, IsFLMLOR ],
    function( F, D )
    local L, A;

    # Check that `D' contains the identity.
    if One( D ) = fail then

      return fail;

    elif LeftActingDomain( D ) = F then

      A:= FLMLORWithOne( F, GeneratorsOfLeftOperatorRing( D ) );

      # Left module generators and basis are maintained.
      if HasGeneratorsOfLeftModule( D ) then
        SetGeneratorsOfLeftModule( A, GeneratorsOfLeftModule( D ) );
      fi;
      if HasBasis( D ) then
        SetBasis( A, Basis( D ) );
      fi;

    elif IsSubset( LeftActingDomain( D ), F ) then

      # Make sure that the field change does not change the elements.
      L:= BasisVectors( Basis( AsField( F, LeftActingDomain(D) ) ) );
      L:= Concatenation( List( L, x -> List( GeneratorsOfAlgebra( D ),
                                             y -> x * y ) ) );
      A:= FLMLORWithOne( F, L );

    elif IsSubset( F, LeftActingDomain( D ) ) then

      # Make sure that the field change does not change the elements.
      L:= BasisVectors( Basis( AsField( LeftActingDomain(D), F ) ) );
      if ForAny( L, x -> ForAny( GeneratorsOfAlgebra( D ),
                                 y -> not x * y in D ) ) then
        return fail;
      fi;
      A:= FLMLORWithOne( F, GeneratorsOfLeftOperatorRing( D ) );

    else

      # Note that we need not use the isomorphism and subset relations
      # (see below) because this is the task of the calls to
      # `AsAlgebraWithOne'.
      D:= AsAlgebraWithOne( Intersection( F, LeftActingDomain( D ) ), D );
      return AsAlgebraWithOne( F, D );

    fi;

    UseIsomorphismRelation( D, A );
    UseSubsetRelation( D, A );
    return A;
    end );


#############################################################################
##
#M  AsFLMLORWithOne( <F>, <D> ) . . view an alg.-with-one as an alg.-with-one
##
InstallMethod( AsFLMLORWithOne,
    "for a division ring and an algebra-with-one",
    [ IsDivisionRing, IsFLMLORWithOne ],
    function( F, D )
    local L, A;

    if   LeftActingDomain( D ) = F then

      return D;

    elif IsSubset( LeftActingDomain( D ), F ) then

      # Make sure that the field change does not change the elements.
      L:= BasisVectors( Basis( AsField( F, LeftActingDomain(D) ) ) );
      L:= Concatenation( List( L, x -> List( GeneratorsOfAlgebra( D ),
                                             y -> x * y ) ) );
      A:= AlgebraWithOne( F, L );

    elif IsSubset( F, LeftActingDomain( D ) ) then

      # Make sure that the field change does not change the elements.
      L:= BasisVectors( Basis( AsField( LeftActingDomain(D), F ) ) );
      if ForAny( L, x -> ForAny( GeneratorsOfAlgebra( D ),
                                 y -> not x * y in D ) ) then
        return fail;
      fi;
      A:= AlgebraWithOne( F, GeneratorsOfAlgebra( D ) );

    else

      # Note that we need not use the isomorphism and subset relations
      # (see below) because this is the task of the calls to
      # `AsAlgebraWithOne'.
      D:= AsAlgebraWithOne( Intersection( F, LeftActingDomain( D ) ), D );
      return AsAlgebraWithOne( F, D );

    fi;

    UseIsomorphismRelation( D, A );
    UseSubsetRelation( D, A );
    return A;
    end );


#############################################################################
##
#M  ClosureLeftOperatorRing( <A>, <a> ) . . . . . . . closure with an element
##
InstallMethod( ClosureLeftOperatorRing,
    "for a FLMLOR and a ring element",
#T why not a general function for any left operator ring?
#T (need `LeftOperatorRingByGenerators' ?)
    IsCollsElms,
    [ IsFLMLOR, IsRingElement ],
    function( A, a )

    # if possible test if the element lies in the ring already,
    if     HasGeneratorsOfLeftOperatorRing( A )
       and a in GeneratorsOfLeftOperatorRing( A ) then
      return A;

    # otherwise make a new left operator ring
    else
      return FLMLOR( LeftActingDomain( A ),
                 Concatenation( GeneratorsOfLeftOperatorRing( A ), [ a ] ) );
    fi;
    end );

InstallMethod( ClosureLeftOperatorRing,
    "for an FLMLOR with basis, and a ring element",
    IsCollsElms,
    [ IsFLMLOR and HasBasis, IsRingElement ],
    function( A, a )

    # test if the element lies in the FLMLOR already,
    if a in A then
      return A;

    # otherwise make a new FLMLOR
    else
      return FLMLOR( LeftActingDomain( A ),
#T FLMLORByGenerators?
                 Concatenation( BasisVectors( Basis( A ) ), [ a ] ),
                 "basis" );
    fi;
    end );

InstallMethod( ClosureLeftOperatorRing,
    "for a FLMLOR-with-one and a ring element",
    IsCollsElms,
    [ IsFLMLORWithOne, IsRingElement ],
    function( A, a )

    # if possible test if the element lies in the ring already,
    if a in GeneratorsOfLeftOperatorRingWithOne( A ) then
      return A;

    # otherwise make a new left operator ring-with-one
    else
      return FLMLORWithOne( LeftActingDomain( A ),
                 Concatenation( GeneratorsOfLeftOperatorRingWithOne( A ),
                                [ a ] ) );
    fi;
    end );

InstallMethod( ClosureLeftOperatorRing,
    "for a FLMLOR-with-one with basis, and a ring element",
    IsCollsElms,
    [ IsFLMLORWithOne and HasBasis, IsRingElement ],
    function( A, a )

    # test if the element lies in the FLMLOR already,
    if a in A then
        return A;

    # otherwise make a new FLMLOR-with-one
    else
      return FLMLORWithOne( LeftActingDomain( A ),
                 Concatenation( BasisVectors( Basis( A ) ), [ a ] ),
                 "basis" );
    fi;
    end );

InstallMethod( ClosureLeftOperatorRing,
    "for a FLMLOR containing the whole family, and a ring element",
    IsCollsElms,
    [ IsFLMLOR and IsWholeFamily, IsRingElement ],
    SUM_FLAGS, # this is better than everything else
    ReturnFirst);

#############################################################################
##
#M  ClosureLeftOperatorRing( <A>, <U> ) .  closure of two left operator rings
##
InstallMethod( ClosureLeftOperatorRing,
    "for two left operator rings",
    IsIdenticalObj,
    [ IsLeftOperatorRing, IsLeftOperatorRing ],
    function( A, S )
    local   g;          # one generator

    for g in GeneratorsOfLeftOperatorRing( S ) do
      A := ClosureLeftOperatorRing( A, g );
    od;
    return A;
    end );

InstallMethod( ClosureLeftOperatorRing,
    "for two left operator rings-with-one",
    IsIdenticalObj,
    [ IsLeftOperatorRingWithOne, IsLeftOperatorRingWithOne ],
    function( A, S )
    local   g;          # one generator

    for g in GeneratorsOfLeftOperatorRingWithOne( S ) do
      A := ClosureLeftOperatorRing( A, g );
    od;
    return A;
    end );

InstallMethod( ClosureLeftOperatorRing,
    "for a left op. ring cont. the whole family, and a collection",
    IsIdenticalObj,
    [ IsLeftOperatorRing and IsWholeFamily, IsCollection ],
    SUM_FLAGS, # this is better than everything else
    ReturnFirst);

#############################################################################
##
#M  ClosureLeftOperatorRing( <A>, <list> )  . . . .  closure of left op. ring
##
InstallMethod( ClosureLeftOperatorRing,
    "for left operator ring and list of elements",
    IsIdenticalObj,
    [ IsLeftOperatorRing, IsCollection ],
    function( A, list )
    local   g;          # one generator
    for g in list do
      A:= ClosureLeftOperatorRing( A, g );
    od;
    return A;
    end );


#############################################################################
##
#F  MutableBasisOfClosureUnderAction( <F>, <Agens>, <from>, <init>, <opr>,
#F                                    <zero>, <maxdim> )
##
##  This function is used to compute bases of finite dimensional ideals $I$
##  in *associative* algebras that are given by ideal generators $J$ and
##  (generators of) the acting algebra $A$.
##  An important special case is that of the algebra $A$ itself, given by
##  algebra generators.
##
##  The algorithm assumes that it is possible to deal with mutable bases of
##  vector spaces generated by elements of $A$.
##  It proceeds as follows.
##
##  Let $A$ be a finite dimensional algebra over the ring $F$,
##  and $I$ a two-sided ideal in $A$ that is generated (as a two-sided ideal)
##  by the set $J$.
##  (For the cases of one-sided ideals, see below.)
##
##  Let $S$ be a set of algebra generators of $A$.
##  The identity of $A$, if exists, need not be contained in $S$.
##
##  Each element $x$ in $I$ can be written as a linear combination of
##  products $j a_1 a_2 \cdots a_n$, with $j \in J$ and $a_i \in S$ for
##  $1 \leq i \leq n$.
##  Let $l(x)$ denote the minimum of the largest $n$ for involved words
##  $a_1 a_2 \cdots a_n$, taken over all possible expressions for $x$.
##
##  Define $I_i = \{ x \in I \mid l(x) \leq i \}$.
##  Then $I_i$ is an $F$-space, $A_0 = \langle J \rangle_F$,
##  and $I_0 \< I_1 \< I_2 \< \cdots I_k \< I_{k+1} \< \ldots$
##  is an ascending chain that eventually reaches $I$.
##  For $i > 0$ we have
##  $I_{i+1} = \langle I_i\cup\bigcup_{s\in S} ( I_i s\cup s I_i )\rangle_F$.
##
##  (*Note* that the computation of the $I_i$ gives us the smallest value $k$
##  such that every element is a linear combination of words in terms of the
##  algebra generators, of maximal length $k$.)
##
InstallGlobalFunction( MutableBasisOfClosureUnderAction,
    function( F, Agens, from, init, opr, zero, maxdim )
    local MB,        # mutable basis, result
          gen,       # loop over generators
          v,         #
          dim,       # dimension of the actual left module
          right,     # `true' if we have to multiply from the right
          left;      # `true' if we have to multiply from the left

    # Get the side(s) from where to multiply.
    left  := true;
    right := true;
    if   from = "left" then
      right:= false;
    elif from = "right" then
      left:= false;
    fi;

    # $I_0$
    MB  := MutableBasis( F, init, zero );
    dim := 0;

    while dim < NrBasisVectors( MB ) and dim < maxdim do

      # `MB' is a mutable basis of $I_i$.
      dim:= NrBasisVectors( MB );

      if right then

        # Compute $I^{\prime}_i = I_i + \sum_{s \in S} I_i s$.
        for gen in Agens do
          for v in BasisVectors( MB ) do
            CloseMutableBasis( MB, opr( v, gen ) );
          od;
        od;

      fi;
      if left then

        # Compute $I_i + \sum_{s \in S} s I_i$
        # resp. $I^{\prime}_i + \sum_{s \in S} s I_i$.
        for gen in Agens do
          for v in BasisVectors( MB ) do
            CloseMutableBasis( MB, opr( gen, v ) );
          od;
        od;

      fi;

    od;

    # Return the mutable basis.
    return MB;
end );


#############################################################################
##
#F  MutableBasisOfNonassociativeAlgebra( <F>, <Agens>, <zero>, <maxdim> )
##
InstallGlobalFunction( MutableBasisOfNonassociativeAlgebra,
    function( F, Agens, zero, maxdim )
    local MB,        # mutable basis, result
          dim,       # dimension of the current left module
          bv,        # current basis vectors
          v, w;      # loop over basis vectors found already

    MB  := MutableBasis( F, Agens, zero );
    dim := 0;

    while dim < NrBasisVectors( MB ) and dim < maxdim do

      dim := NrBasisVectors( MB );
      bv  := BasisVectors( MB );

      for v in bv do
        for w in bv do
          CloseMutableBasis( MB, v * w );
          CloseMutableBasis( MB, w * v );
        od;
      od;

    od;

    # Return the mutable basis.
    return MB;
end );


#############################################################################
##
#F  MutableBasisOfIdealInNonassociativeAlgebra( <F>, <Vgens>, <Igens>,
#F                                              <zero>, <from>, <maxdim> )
##
InstallGlobalFunction( MutableBasisOfIdealInNonassociativeAlgebra,
    function( F, Vgens, Igens, zero, from, maxdim )
    local MB,        # mutable basis, result
          dim,       # dimension of the current left module
          bv,        # current basis vectors
          right,     # `true' if we have to multiply from the right
          left,      # `true' if we have to multiply from the left
          v, gen;    # loop over basis vectors found already

    # Get the side(s) from where to multiply.
    left  := true;
    right := true;
    if   from = "left" then
      right:= false;
    elif from = "right" then
      left:= false;
    fi;

    dim := 0;
    MB  := MutableBasis( F, Igens, zero );

    while dim < NrBasisVectors( MB ) and dim < maxdim do

      dim := NrBasisVectors( MB );
      bv  := BasisVectors( MB );

      for v in bv do
        for gen in Vgens do

          if left then
            CloseMutableBasis( MB, gen * v );
          fi;
          if right then
            CloseMutableBasis( MB, v * gen );
          fi;
        od;
      od;

    od;

    # Return the mutable basis.
    return MB;
end );


#############################################################################
##
#M  IsSubset( <A>, <B> )  . . . . . . . . . . . .  test for subset of FLMLORs
##
##  These methods are preferable to that for free left modules because they
##  use algebra generators.
##
##  We assume that generators of an extension of the left acting domains can
##  be computed if they are fields; note that infinite field extensions do
##  not (yet) occur in {\GAP} as `LeftActingDomain' values.
##
InstallMethod( IsSubset,
    "for two FLMLORs",
    IsIdenticalObj,
    [ IsFLMLOR, IsFLMLOR ],
    function( D1, D2 )
    local F1, F2;

    F1:= LeftActingDomain( D1 );
    F2:= LeftActingDomain( D2 );
    if not ( HasIsDivisionRing( F1 ) and IsDivisionRing( F1 ) and
             HasIsDivisionRing( F2 ) and IsDivisionRing( F2 ) ) then
      TryNextMethod();
    fi;

    # catch trivial case
    if IsSubset(GeneratorsOfLeftOperatorRing(D1),
                  GeneratorsOfLeftOperatorRing(D2)) then
        return true;
    fi;
    return IsSubset( D1, GeneratorsOverIntersection( D2,
                             GeneratorsOfLeftOperatorRing( D2 ),
                             F2, F1 ) );
    end );

InstallMethod( IsSubset,
    "for two FLMLORs-with-one",
    IsIdenticalObj,
    [ IsFLMLORWithOne, IsFLMLORWithOne ],
    function( D1, D2 )
    local F1, F2;

    F1:= LeftActingDomain( D1 );
    F2:= LeftActingDomain( D2 );
    if not ( HasIsDivisionRing( F1 ) and IsDivisionRing( F1 ) and
             HasIsDivisionRing( F2 ) and IsDivisionRing( F2 ) ) then
      TryNextMethod();
    fi;
    return IsSubset( D1, GeneratorsOverIntersection( D2,
                             GeneratorsOfLeftOperatorRingWithOne( D2 ),
                             F2, F1 ) );
    end );


#############################################################################
##
#M  ViewObj( <A> )  . . . . . . . . . . . . . . . . . . . . . . view a FLMLOR
##
##  print left acting domain, if known also dimension or no. of generators
##
InstallMethod( ViewObj,
    "for a FLMLOR",
    [ IsFLMLOR ],
    function( A )
    Print( "<free left module over ", LeftActingDomain( A ), ", and ring>" );
    end );

InstallMethod( ViewObj,
    "for a FLMLOR with known dimension",
    [ IsFLMLOR and HasDimension ], 1,   # override method requiring gens.
    function( A )
    Print( "<free left module of dimension ", Dimension( A ),
           " over ", LeftActingDomain( A ), ", and ring>" );
    end );

InstallMethod( ViewObj,
    "for a FLMLOR with known generators",
    [ IsFLMLOR and HasGeneratorsOfAlgebra ],
    function( A )
    Print( "<free left module over ", LeftActingDomain( A ),
           ", and ring, with ",
           Pluralize( Length( GeneratorsOfFLMLOR( A ) ), "generator" ), ">" );
    end );


#############################################################################
##
#M  PrintObj( <A> ) . . . . . . . . . . . . . . . . . . . . .  print a FLMLOR
##
InstallMethod( PrintObj,
    "for a FLMLOR",
    [ IsFLMLOR ],
    function( A )
    Print( "FLMLOR( ", LeftActingDomain( A ), ", ... )" );
    end );

InstallMethod( PrintObj,
    "for a FLMLOR with known generators",
    [ IsFLMLOR and HasGeneratorsOfFLMLOR ],
    function( A )
    if IsEmpty( GeneratorsOfFLMLOR( A ) ) then
      Print( "FLMLOR( ", LeftActingDomain( A ), ", [], ", Zero( A ), " )" );
    else
      Print( "FLMLOR( ", LeftActingDomain( A ), ", ",
             GeneratorsOfFLMLOR( A ), " )" );
    fi;
    end );


#############################################################################
##
#M  ViewObj( <A> )  . . . . . . . . . . . . . . . . .  view a FLMLOR-with-one
##
##  print left acting domain, if known also dimension or no. of generators
##
InstallMethod( ViewObj,
    "for a FLMLOR-with-one",
    [ IsFLMLORWithOne ],
    function( A )
    Print( "<free left module over ", LeftActingDomain( A ),
           ", and ring-with-one>" );
    end );

InstallMethod( ViewObj,
    "for a FLMLOR-with-one with known dimension",
    [ IsFLMLORWithOne and HasDimension ], 1,   # override method requ. gens.
    function( A )
    Print( "<free left module of dimension ", Dimension( A ),
           " over ", LeftActingDomain( A ), ", and ring-with-one>" );
    end );

InstallMethod( ViewObj,
    "for a FLMLOR-with-one with known generators",
    [ IsFLMLORWithOne and HasGeneratorsOfFLMLORWithOne ],
    function( A )
    Print( "<free left module over ", LeftActingDomain( A ),
           ", and ring-with-one, with ",
           Pluralize( Length( GeneratorsOfAlgebraWithOne( A ) ), "generator" ),
           ">" );
    end );


#############################################################################
##
#M  PrintObj( <A> ) . . . . . . . . . . . . . . . . . print a FLMLOR-with-one
##
InstallMethod( PrintObj,
    "for a FLMLOR-with-one",
    [ IsFLMLORWithOne ],
    function( A )
    Print( "FLMLORWithOne( ", LeftActingDomain( A ), ", ... )" );
    end );

InstallMethod( PrintObj,
    "for a FLMLOR-with-one with known generators",
    [ IsFLMLORWithOne and HasGeneratorsOfFLMLOR ],
    function( A )
    if IsEmpty( GeneratorsOfFLMLORWithOne( A ) ) then
      Print( "FLMLORWithOne( ", LeftActingDomain( A ), ", [], ",
             Zero( A ), " )" );
    else
      Print( "FLMLORWithOne( ", LeftActingDomain( A ), ", ",
             GeneratorsOfFLMLORWithOne( A ), " )" );
    fi;
    end );


#############################################################################
##
#M  ViewObj( <A> )  . . . . . . . . . . . . . . . . . . . . . view an algebra
##
##  print left acting domain, if known also dimension or no. of generators
##
InstallMethod( ViewObj,
    "for an algebra",
    [ IsAlgebra ],
    function( A )
    Print( "<algebra over ", LeftActingDomain( A ), ">" );
    end );

InstallMethod( ViewObj,
    "for an algebra with known dimension",
    [ IsAlgebra and HasDimension ], 1,   # override method requiring gens.
    function( A )
    Print( "<algebra of dimension ", Dimension( A ),
           " over ", LeftActingDomain( A ), ">" );
    end );

InstallMethod( ViewObj,
    "for an algebra with known generators",
    [ IsAlgebra and HasGeneratorsOfAlgebra ],
    function( A )
    Print( "<algebra over ", LeftActingDomain( A ), ", with ",
           Pluralize( Length( GeneratorsOfAlgebra( A ) ), "generator" ), ">" );
    end );


#############################################################################
##
#M  PrintObj( <A> ) . . . . . . . . . . . . . . . . . . . .  print an algebra
##
InstallMethod( PrintObj,
    "for an algebra",
    [ IsAlgebra ],
    function( A )
    Print( "Algebra( ", LeftActingDomain( A ), ", ... )" );
    end );

InstallMethod( PrintObj,
    "for an algebra with known generators",
    [ IsAlgebra and HasGeneratorsOfAlgebra ],
    function( A )
    if IsEmpty( GeneratorsOfAlgebra( A ) ) then
      Print( "Algebra( ", LeftActingDomain( A ), ", [], ", Zero( A ), " )" );
    else
      Print( "Algebra( ", LeftActingDomain( A ), ", ",
             GeneratorsOfAlgebra( A ), " )" );
    fi;
    end );


#############################################################################
##
#M  ViewObj( <A> )  . . . . . . . . . . . . . . . .  view an algebra-with-one
##
##  print left acting domain, if known also dimension or no. of generators
##
InstallMethod( ViewObj, "for an algebra-with-one", [ IsAlgebraWithOne ],
function( A )
  if IsIdenticalObj(A,LeftActingDomain(A)) then
    Print( "<algebra-with-one over itself>" );
  else
    Print( "<algebra-with-one over ", LeftActingDomain( A ), ">" );
  fi;
end );

InstallMethod( ViewObj,
    "for an algebra-with-one with known dimension",
    [ IsAlgebraWithOne and HasDimension ], 1,   # override method requ. gens.
    function( A )
    Print( "<algebra-with-one of dimension ", Dimension( A ),
           " over ", LeftActingDomain( A ), ">" );
    end );

InstallMethod( ViewObj,
    "for an algebra-with-one with known generators",
    [ IsAlgebraWithOne and HasGeneratorsOfAlgebraWithOne ],
    function( A )
    Print( "<algebra-with-one over ", LeftActingDomain( A ), ", with ",
           Pluralize( Length( GeneratorsOfAlgebraWithOne( A ) ), "generator" ),
           ">" );
    end );


#############################################################################
##
#M  PrintObj( <A> ) . . . . . . . . . . . . . . . . print an algebra-with-one
##
InstallMethod( PrintObj,
    "for an algebra-with-one",
    [ IsAlgebraWithOne ],
    function( A )
    Print( "AlgebraWithOne( ", LeftActingDomain( A ), ", ... )" );
    end );

InstallMethod( PrintObj,
    "for an algebra-with-one with known generators",
    [ IsAlgebraWithOne and HasGeneratorsOfAlgebra ],
    function( A )
    if IsEmpty( GeneratorsOfAlgebraWithOne( A ) ) then
      Print( "AlgebraWithOne( ", LeftActingDomain( A ), ", [], ",
             Zero( A ), " )" );
    else
      Print( "AlgebraWithOne( ", LeftActingDomain( A ), ", ",
             GeneratorsOfAlgebraWithOne( A ), " )" );
    fi;
    end );


#############################################################################
##
#M  ViewObj( <A> )  . . . . . . . . . . . . . . . . . . view a Lie algebra
##
##  print left acting domain, if known also dimension or no. of generators
##
InstallMethod( ViewObj,
    "for a Lie algebra",
    [ IsLieAlgebra ],
    function( A )
    Print( "<Lie algebra over ", LeftActingDomain( A ), ">" );
    end );

InstallMethod( ViewObj,
    "for a Lie algebra with known dimension",
    [ IsLieAlgebra and HasDimension ], 1,       # override method requ. gens.
    function( A )
    Print( "<Lie algebra of dimension ", Dimension( A ),
           " over ", LeftActingDomain( A ), ">" );
    end );

InstallMethod( ViewObj,
    "for a Lie algebra with known generators",
    [ IsLieAlgebra and HasGeneratorsOfAlgebra ],
    function( A )
    Print( "<Lie algebra over ", LeftActingDomain( A ), ", with ",
           Pluralize( Length( GeneratorsOfAlgebra( A ) ), "generator" ), ">" );
end );


#############################################################################
##
#M  AsSubalgebra(<A>, <U>) . view an algebra as subalgebra of another algebra
##
InstallMethod( AsSubalgebra,
    "for two algebras",
    IsIdenticalObj,
    [ IsAlgebra, IsAlgebra ],
    function( A, U )
    local samecoeffs, S;
    if not IsSubset( A, U ) then
      return fail;
    fi;

    # Construct the generators list.
    samecoeffs:= LeftActingDomain( A ) = LeftActingDomain( U );
    if not samecoeffs then
      U:= AsAlgebra( LeftActingDomain( A ), U );
    fi;

    # Construct the subalgebra.
    S:= SubalgebraNC( A, GeneratorsOfAlgebra( U ) );

    # Maintain useful information.
    UseIsomorphismRelation( U, S );
    UseSubsetRelation( U, S );
    if samecoeffs and HasDimension( U ) then
      SetDimension( S, Dimension( U ) );
    fi;

    # Return the subalgebra.
    return S;
    end );

InstallMethod( AsSubalgebra,
    "for an algebra and an algebra-with-one",
    IsIdenticalObj,
    [ IsAlgebra, IsAlgebraWithOne ],
    function( A, U )
    local samecoeffs, S;
    if not IsSubset( A, U ) then
      return fail;
    fi;

    # Construct the generators list.
    samecoeffs:= LeftActingDomain( A ) = LeftActingDomain( U );
    if not samecoeffs then
      U:= AsAlgebraWithOne( LeftActingDomain( A ), U );
    fi;

    # Construct the subalgebra.
    S:= SubalgebraWithOneNC( A, GeneratorsOfAlgebraWithOne( U ) );

    # Maintain useful information.
    UseIsomorphismRelation( U, S );
    UseSubsetRelation( U, S );
    if samecoeffs and HasDimension( U ) then
      SetDimension( S, Dimension( U ) );
    fi;

    # Return the subalgebra.
    return S;
    end );


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

--> maximum size reached

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

[ Seitenstruktur0.70Drucken  etwas mehr zur Ethik  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


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