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


Quelle  pathalg.gi   Sprache: unbekannt

 
# GAP Implementation
# This file was generated from
# $Id: algpath.gi,v 1.8 2012/06/18 16:00:57 andrzejmroz Exp $

InstallMethod( IsPathRing,
    "for magma ring modulo the span of zero",
    true,
    [ IsMagmaRingModuloSpanOfZero ], 0,

   # Check to see underlying magma is a proper Quiver object:
    RM -> IsQuiver( UnderlyingMagma( RM ))
);


InstallMethod( IsPathRing,
    "for algebras that are not path rings",
    true,
    [ IsAlgebra ], 0,
    false
);


InstallGlobalFunction( PathRing,
  function(R, Q)
    local v, one, eFam;

    if not IsQuiver(Q) then
        Error( "<Q> must be a quiver." );
    fi;

    R := MagmaRingModuloSpanOfZero( R, Q, Zero(Q) );

    SetIsPathRing( R, true );
    eFam := ElementsFamily(FamilyObj(R));
    eFam!.pathRing := R;
    SetFilterObj(eFam,IsElementOfPathRing);

    # Create multiplicative identity element for this
    #  path ring; which is the sum of all vertices:
    one := Zero(R);
    for v in VerticesOfQuiver(Q) do
        one := one + ElementOfMagmaRing(eFam, eFam!.zeroRing, 
                                        [One(eFam!.zeroRing)], [v]);
    od;

    SetIsAssociative(R, true);
    SetOne(eFam, one);
    SetGeneratorsOfLeftOperatorRingWithOne(R, GeneratorsOfLeftOperatorRing(R));
    SetFilterObj(R, IsRingWithOne);

    return R;
  end
);


InstallGlobalFunction( PathAlgebra,
  function(F, Q, arg...)
    if not IsDivisionRing(F) then
        Error( "<F> must be a division ring or field." );
    fi;
    F := PathRing( F, Q );
    SetOrderingOfAlgebra(F, OrderingOfQuiver(Q));
    if Length(arg) > 0 then
      SetGroebnerBasisFunction(F, arg[1]);
    else
      SetGroebnerBasisFunction(F, GBNPGroebnerBasis);
    fi;
    if NumberOfArrows(Q) > 0 then 
        SetGlobalDimension(F, 1);
        SetFilterObj( F, IsHereditaryAlgebra ); 
    else
        SetGlobalDimension(F, 0);
        SetFilterObj( F, IsSemisimpleAlgebra ); 
    fi;
    if IsAcyclicQuiver(Q) then
      Basis( F );
#        SetFilterObj( F, IsAdmissibleQuotientOfPathAlgebra);
    fi;
    return F;
  end
);

InstallMethod( QuiverOfPathRing,
    "for a path ring",
    true,
    [ IsPathRing ], 0,
    RQ -> UnderlyingMagma(RQ)
);

InstallMethod( ViewObj,
    "for a path algebra",
    true,
    [ IsPathAlgebra ], NICE_FLAGS + 1,
    function( A )

    Print("<");
    View(LeftActingDomain(A));
    Print("[");
    View(QuiverOfPathAlgebra(A));
    Print("]>");
end
);

InstallMethod( PrintObj,
    "for a path algebra",
    true,
    [ IsPathAlgebra ], NICE_FLAGS + 1,
    function( A )

    local Q;

    Print("<Path algebra of the quiver ");
    if HasName(QuiverOfPathAlgebra(A)) then
        Print(Name(QuiverOfPathAlgebra(A)));
    else
        View(QuiverOfPathAlgebra(A));
    fi;
    Print(" over the field ");
    View(LeftActingDomain(A));
    Print(">");
end
);

InstallMethod( CanonicalBasis,
  "for path algebras",
  true,
  [ IsPathAlgebra ],
  NICE_FLAGS+1,
  function( A )
    local q, bv, i;

    q := QuiverOfPathAlgebra(A);
    if IsFinite(q) then
        bv := [];
        for i in Iterator(q) do
            Add(bv, i * One(A));
        od;
        return Basis(A, bv);
    else
       return fail;
    fi;
  end
);


# What's this for?
InstallMethod( NormalizedElementOfMagmaRingModuloRelations,
  "for elements of path algebras",
  true,
  [ IsElementOfMagmaRingModuloSpanOfZeroFamily 
    and IsElementOfPathRing, IsList ],
  0,
  function( Fam, descr )
        local zeromagma, len;

        zeromagma:= Fam!.zeroOfMagma;
        len := Length( descr[2] );
        if len > 0 and descr[2][1] = zeromagma then
            descr := [descr[1], descr[2]{[3..len]}];
            MakeImmutable(descr);
        fi;
        return descr;
  end
);


InstallMethod( \*,
  "for path algebra elements (faster)",
  IsIdenticalObj,
  [ IsZero and IsElementOfMagmaRingModuloRelations,
    IsElementOfMagmaRingModuloRelations ],
  0,
  function( x, y )
    return x;
  end
);


InstallMethod( \*,
  "for path algebra elements (faster)",
  IsIdenticalObj,
  [ IsElementOfMagmaRingModuloRelations,
    IsZero and IsElementOfMagmaRingModuloRelations ],
  0,
  function( x, y )
    return y;
  end
);


InstallMethod( \+,
  "for path algebra elements (faster)",
  IsIdenticalObj,
  [ IsZero and IsElementOfMagmaRingModuloRelations,
    IsElementOfMagmaRingModuloRelations ],
  0,
  function( x, y )
    return y;
  end
);


InstallMethod( \+,
  "for path algebra elements (faster)",
  IsIdenticalObj,
  [ IsElementOfMagmaRingModuloRelations,
    IsZero and IsElementOfMagmaRingModuloRelations ],
  0,
  function( x, y )
    return x;
  end
);


InstallGlobalFunction( FactorPathAlgebraByRelators,
  function( P, I, O )
    local A, fam, R, elementFam, relators, gb;
   
    relators := GeneratorsOfIdeal( I );

    if not IsIdenticalObj(OrderingOfQuiver(QuiverOfPathAlgebra(P)), O) then
        # Create a path algebra with a newly ordered quiver
        R := PathAlgebra(LeftActingDomain(P),
                     OrderedBy(QuiverOfPathAlgebra(P), O));
    
        # Create relators in $R$
        elementFam := ElementsFamily(FamilyObj(R));
        relators := List(relators, function(rel)
           local newRelator, extRep, zero, terms, i;

           newRelator := Zero(R);
           extRep := ExtRepOfObj(rel);
           zero := extRep[1];
           terms := extRep[2];

           for i in [1,3..Length(terms) - 1] do
                newRelator := newRelator + 
                              ObjByExtRep(elementFam, [zero, [terms[i], terms[i+1]]]);
           od;
           return newRelator;
        end);
    else
        R := P;
    fi;
    
    # Create a new family
    fam := NewFamily( "FamilyElementsFpPathAlgebra",
                      IsElementOfQuotientOfPathAlgebra );


    # Create the default type of elements
    fam!.defaultType := NewType( fam, IsElementOfQuotientOfPathAlgebra 
                                      and IsPackedElementDefaultRep );


    # If the ideal has a Groebner basis, create a function for
    # finding normal forms of the elements
    if HasGroebnerBasisOfIdeal( I ) 
#       and IsCompleteGroebnerBasis( GroebnerBasisOfIdeal( I ) )
    then
       fam!.normalizedType := NewType( fam, IsElementOfQuotientOfPathAlgebra
                                            and IsNormalForm
                                            and IsPackedElementDefaultRep );
       gb := GroebnerBasisOfIdeal( I );
       # Make sure the groebner basis is tip reduced now.
       TipReduceGroebnerBasis(gb);
       SetNormalFormFunction( fam, function(fam, x)
           local y;
           y := CompletelyReduce(gb, x);
           return Objectify( fam!.normalizedType, [y] );
       end );
    fi;

    fam!.pathAlgebra := R;
    fam!.ideal := I;
    fam!.familyRing := FamilyObj(LeftActingDomain(R));

    # Set the characteristic.
    if HasCharacteristic( R ) or HasCharacteristic( FamilyObj( R ) ) then
      SetCharacteristic( fam, Characteristic( R ) );
    fi;

    # Path algebras are always algebras with one
    A := Objectify(
        NewType( CollectionsFamily( fam ),
                IsQuotientOfPathAlgebra
            and IsAlgebraWithOne
            and IsWholeFamily
            and IsAttributeStoringRep ),
        rec() );

    SetLeftActingDomain( A, LeftActingDomain( R ) );
    SetGeneratorsOfAlgebraWithOne( A, 
        List( GeneratorsOfAlgebra( R ), 
            a -> ElementOfQuotientOfPathAlgebra( fam, a, false ) ) );

    SetZero( fam, ElementOfQuotientOfPathAlgebra( fam, Zero( R ), true ) );
    SetOne( fam, ElementOfQuotientOfPathAlgebra( fam, One( R ), true ) );
    UseFactorRelation( R, relators, A );

    SetOrderingOfAlgebra( A, O );
    SetQuiverOfPathAlgebra(A, QuiverOfPathAlgebra(R));
    SetIsFullFpPathAlgebra(A, true);

    fam!.wholeAlgebra := A;

    return A;
  end
);


InstallOtherMethod( NaturalHomomorphismByIdeal,
  "for a path algebra and ideal",
  IsIdenticalObj,
  [ IsPathRing, IsFLMLOR ],
  0,
  function( A, I )
    local image, hom;

    image := FactorPathAlgebraByRelators( A, I, OrderingOfAlgebra(A) );

    if IsMagmaWithOne( A ) then
        hom := AlgebraWithOneHomomorphismByImagesNC( A, image,
                   GeneratorsOfAlgebraWithOne( A ),
                   GeneratorsOfAlgebraWithOne( image ) );
    else
        hom := AlgebraHomomorphismByImagesNC( A, image,
                   GeneratorsOfAlgebra( A ),
                   GeneratorsOfAlgebra( image ) );
    fi;

    SetIsSurjective( hom, true );

    return hom;
  end
);


# How is this used?
InstallMethod( \.,
  "for path algebras",
  true,
  [IsPathAlgebra, IsPosInt],
  0,
  function(A, name)
    local quiver, family;

    family := ElementsFamily(FamilyObj(A));
    quiver := QuiverOfPathAlgebra(A);
    return ElementOfMagmaRing(family, Zero(LeftActingDomain(A)),
        [One(LeftActingDomain(A))], [quiver.(NameRNam(name))] );
  end
);

InstallMethod( ViewObj,
    "for a quotient of a path algebra",
    true,
    [ IsQuotientOfPathAlgebra ], NICE_FLAGS + 1,
    function( A )

    local fam;

    fam := ElementsFamily(FamilyObj(A));
    Print("<");
    View(LeftActingDomain(A));
    Print("[");
    View(QuiverOfPathAlgebra(A));
    Print("]/");
    View(fam!.ideal);
    Print(">");
end
);

InstallMethod( PrintObj,
    "for a quotient of a path algebra",
    true,
    [ IsQuotientOfPathAlgebra ], NICE_FLAGS + 1,
    function( A )

    local fam;

    fam := ElementsFamily(FamilyObj(A));
    Print("<A quotient of the path algebra ");
    View(OriginalPathAlgebra(A));
    Print(" modulo the ideal ");
    View(fam!.ideal);
    Print(">");
end
);

InstallMethod( \<,
  "for path algebra elements",
  IsIdenticalObj,
  [IsElementOfMagmaRingModuloRelations, 
   IsElementOfMagmaRingModuloRelations], 10, # must be higher rank
  function( e, f )
    local i, swap;

    if not IsElementOfPathRing(FamilyObj(e)) then
        TryNextMethod();
    fi;
        
    e := Reversed(CoefficientsAndMagmaElements(e));
    f := Reversed(CoefficientsAndMagmaElements(f));

    # The reversal causes coefficients to come before
    # monomials. We need to swap these in order to
    # compare elements properly.
    for i in [ 1,3  .. Length( e )-1 ] do
        swap := e[i];
        e[i] := e[i+1];
        e[i+1] := swap;
    od;

    for i in [ 1,3  .. Length( f )-1 ] do
        swap := f[i];
        f[i] := f[i+1];
        f[i+1] := swap;
    od;

    for i in [ 1 .. Minimum(Length( e ), Length( f )) ] do
      if   e[i] < f[i] then
        return true;
      elif e[i] > f[i] then
        return false;
      fi;
    od;

    return Length( e ) < Length( f );

  end
);


InstallOtherMethod( LeadingTerm,
  "for a path algebra element",
  IsElementOfPathRing,
  [IsElementOfMagmaRingModuloRelations], 0,
  function(e)
    local termlist, n, tip, fam, P, embedding;

    termlist := CoefficientsAndMagmaElements(e);
    n := Length(termlist) - 1;
    if n < 1 then
       return Zero(e);
    else
       fam := FamilyObj(e);
       tip :=  ElementOfMagmaRing(fam,
                                  fam!.zeroRing,
                                  [termlist[n+1]], 
                                  [termlist[n]]);
       return tip;
    fi;

  end
);


InstallMethod( LeadingTerm,
  "for a quotient of path algebra element",
  true,
  [IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep],
  0,
  function(e)
    local lt, fam;

    fam := FamilyObj(e);
    lt :=  LeadingTerm(e![1]);

    return ElementOfQuotientOfPathAlgebra(fam, lt, IsNormalForm(e));

  end
);


InstallOtherMethod( LeadingCoefficient, 
  "for elements of path algebras",
  IsElementOfPathRing,
  [IsElementOfMagmaRingModuloRelations],
  0,
  function(e)
    local termlist, n, fam;

    termlist := CoefficientsAndMagmaElements(e);
    n := Length(termlist);
    if n < 1 then
        fam := FamilyObj(e);
        return fam!.zeroRing;
    else
        return termlist[n];
    fi;
  end
);


InstallOtherMethod( LeadingCoefficient, 
  "for elements of quotients of path algebras",
  true,
  [IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep], 0,
  function(e)

    return LeadingCoefficient(e![1]);

  end
);


InstallOtherMethod( LeadingMonomial,
  "for elements of path algebras",
  IsElementOfPathRing,
  [ IsElementOfMagmaRingModuloRelations ],
  0,
  function(e)
    local termlist, n, fam;

    termlist := CoefficientsAndMagmaElements(e);

    n := Length(termlist);

    if n < 1 then
        fam := FamilyObj(e);
        return fam!.zeroOfMagma;
    else
        return termlist[n-1];
    fi;

  end
);


InstallOtherMethod( LeadingMonomial, 
  "for elements of quotients of path algebras",
  true,
  [IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep],
  0,
  function(e)
      return LeadingMonomial(e![1]);
  end
);


InstallMethod( IsLeftUniform,
  "for path ring elements",
  IsElementOfPathRing,
  [ IsElementOfMagmaRingModuloRelations ],
  0,
  function( e )
      local terms, v;

      if IsZero(e) then
          return true;
      fi;

      terms := CoefficientsAndMagmaElements(e);
      v := SourceOfPath(terms[1]);
      return ForAll(terms{[1,3..Length(terms)-1]},
                    x -> SourceOfPath(x) = v);
  end
);


InstallMethod( IsLeftUniform,
  "for quotient of path algebra elements",
  true,
  [ IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep],
  0,
  function( e )
    return IsLeftUniform(e![1]);
  end
);


# Note: This will return true for zero entries in list
InstallMethod( IsLeftUniform,
  "for list of path ring elements",
  true,
  [ IsList, IsPath ],
  0,
  function( l, e )
      local terms, v, len, retflag, i;

      retflag := true;
      len := Length(l);

      # Strip off given vertex's coefficient:
#      terms := CoefficientsAndMagmaElements(e);
#      e := terms[1];
      terms := CoefficientsAndMagmaElements(e);
      e := terms[1];

      i := 1;
      while ( i <= len ) and ( retflag = true ) do
        terms := CoefficientsAndMagmaElements(l[i]);
        retflag :=  ForAll(terms{[1,3..Length(terms)-1]},
                      x -> SourceOfPath(x) = e);
        i := i + 1;
      od;

      return retflag;
  end
);



InstallMethod( IsRightUniform,
  "for path ring elements",
  IsElementOfPathRing,
  [ IsElementOfMagmaRingModuloRelations ],
  0,
  function( e )
    local terms, v;

    if IsZero(e) then
        return true;
    fi;

    terms := CoefficientsAndMagmaElements(e);
    v := TargetOfPath(terms[1]);
    return ForAll(terms{[1,3..Length(terms)-1]},
                  x -> TargetOfPath(x) = v);
  end
);


InstallMethod( IsRightUniform,
  "for quotient of path algebra elements",
  true,
  [ IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep], 0,
  function( e )
    return IsRightUniform(e![1]);
  end
);


# Note: This will return true for zero entries in list
InstallMethod( IsRightUniform,
  "for list of path ring elements",
  true,
  [ IsList, IsPath ],
  0,
  function( l, e )
      local terms, v, len, retflag, i;

      retflag := true;
      len := Length(l);

      # Strip off given vertex's coefficient:
#      terms := CoefficientsAndMagmaElements(e);
#      e := terms[1];
      terms := CoefficientsAndMagmaElements(e);
      e := terms[1];

      i := 1;
      while ( i <= len ) and ( retflag = true ) do
        terms := CoefficientsAndMagmaElements(l[i]);
        retflag :=  ForAll(terms{[1,3..Length(terms)-1]},
                      x -> TargetOfPath(x) = e);
        i := i + 1;
      od;

      return retflag;
  end
);



InstallMethod( IsUniform,
  "for path ring elements",
  IsElementOfPathRing,
  [ IsElementOfMagmaRingModuloRelations ], 0,
  function( e )

    if IsZero(e) then
        return true;
    fi;

    return IsRightUniform(e) and IsLeftUniform(e);
  end
);


InstallMethod( IsUniform,
  "for quotient of path algebra elements",
  true,
  [ IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep], 0,
  function( e )
    return IsUniform(e![1]);
  end
);


InstallOtherMethod( MappedExpression,
  "for a path algebra and two homogeneous lists",
  function( x, y, z)
    return IsElementOfPathRing(x)
           and IsElmsCollsX( x, y, z);
  end,
  [ IsElementOfMagmaRingModuloRelations, IsHomogeneousList,
    IsHomogeneousList ], 0,
  function( expr, gens1, gens2 )
    local MappedWord, genTable, i, mapped, one, coeff, mon;

    if IsZero(expr) then
        return Zero(gens2[1]);
    fi;

    expr := ExtRepOfObj( expr )[2];

    genTable := [];
    for i in [1..Length(gens1)] do
        coeff := LeadingCoefficient(gens1[i]);
        mon := LeadingMonomial(gens1[i]);
        if IsOne(coeff) and (IsQuiverVertex(mon) or IsArrow(mon)) then
            genTable[ExtRepOfObj(mon)[1]] := gens2[i];
        else
            Error( "gens1 must be a list of generators" );
        fi;
    od;

    one := One(expr[2]);

    MappedWord := function( word )
        local mapped, i, exponent;

        i := 2;
        exponent := 1;
        while i <= Length(word) and word[i] = word[i-1] do
            exponent := exponent + 1;
            i := i + 1;
        od;
        mapped := genTable[word[i-1]]^exponent;
        exponent := 1;

        while i <= Length(word) do
            i := i + 1;
            while i <= Length(word) and word[i] = word[i-1] do
                exponent := exponent + 1;
                i := i + 1;
            od;
            if exponent > 1 then
                mapped := mapped * genTable[word[i-1]]^exponent;
                exponent := 1;
            else
                mapped := mapped * genTable[word[i-1]];
            fi;
        od;

        return mapped;
    end;

    if expr[2] <> one then
        mapped := expr[2] * MappedWord(expr[1]);
    else
        mapped := MappedWord(expr[1]);
    fi;

    for i in [4,6 .. Length(expr)] do
        if expr[i] = one then
            mapped := mapped + MappedWord( expr[i-1] );
        else
            mapped := mapped + expr[i] * MappedWord( expr[ i-1 ] );
        fi;
    od;

    return mapped;
  end
);


InstallMethod( ImagesRepresentative,
  "for an alg. hom. from f. p. algebra, and an element",
  true,
  [ IsAlgebraHomomorphism
    and IsAlgebraGeneralMappingByImagesDefaultRep,
    IsRingElement ], 0,
  function( alghom, elem )

    local A;

    A := Source(alghom);
    if not (IsPathAlgebra(A) or IsQuotientOfPathAlgebra(A)) then
        TryNextMethod();
    fi;

    return MappedExpression( elem, alghom!.generators, alghom!.genimages );

  end
);


InstallOtherMethod( OrderedBy,
  "for a quotient of a path algebra",
  true,
  [IsQuotientOfPathAlgebra, IsQuiverOrdering], 0,
  function(A, O)
    local fam;
    fam := ElementsFamily(FamilyObj(A));
    return FactorPathAlgebraByRelators( fam!.pathAlgebra,
                                        fam!.relators,
                                        O);
  end
);


InstallMethod( \.,
  "for quotients of path algebras",
  true,
  [IsQuotientOfPathAlgebra, IsPosInt], 0,
  function(A, name)
    local parent, family;

    family := ElementsFamily(FamilyObj(A));
    parent := family!.pathAlgebra;

    return ElementOfQuotientOfPathAlgebra(family, parent.(NameRNam(name)), false );

  end
);


InstallMethod( RelatorsOfFpAlgebra,
  "for a quotient of a path algebra",
  true,
  [IsQuotientOfPathAlgebra and IsFullFpPathAlgebra], 0,
  A -> GeneratorsOfIdeal(ElementsFamily(FamilyObj(A))!.ideal)
);

#######################################################################
##
#A  RelationsOfAlgebra( <A> )
##
##  When  <A>  is a quiver algebra, then if  <A>  is a path algebra, 
##  then it returns an empty list.  If  <A>  is quotient of a path 
##  algebra, then it returns a list of generators for the ideal used
##  to define the algebra. 
##
InstallMethod( RelationsOfAlgebra,
    "for a quiver algebra",
    true,
    [ IsQuiverAlgebra ], 0,
    function( A );
    if IsPathAlgebra(A) then
        return [];
    else
        return GeneratorsOfIdeal(ElementsFamily(FamilyObj(A))!.ideal);
    fi;
end
  );

#######################################################################
##
#A  IdealOfQuotient( <A> )
##
##  When  <A>  is a quotient of a path algebra  kQ/I, then this function
##  returns the ideal  I  in the path algedra  kQ defining the quotient 
##  <A>. 
##
InstallMethod( IdealOfQuotient,
    "for a quiver algebra",
    true,
    [ IsQuiverAlgebra ], 0,
    function( A );
    if IsPathAlgebra(A) then
        return fail;
    else
        return ElementsFamily(FamilyObj(A))!.ideal;
    fi;
end
  );

################################################################
# Property IsFiniteDimensional for quotients of path algebras
# (analogue for path algebras uses standard GAP method)
# It uses Groebner bases machinery (computes G.b. only in case
# it has not been computed).

InstallMethod( IsFiniteDimensional,
  "for quotients of path algebras",
  true,
  [IsQuotientOfPathAlgebra and IsFullFpPathAlgebra], 0,
  function( A )
    local gb, fam, KQ, I, rels;
  
    fam := ElementsFamily(FamilyObj(A));
    KQ := fam!.pathAlgebra;
    I := fam!.ideal;

    if HasGroebnerBasisOfIdeal(I) then
      gb := GroebnerBasisOfIdeal(I);
    else
      rels := GeneratorsOfIdeal(I);     
      gb := GroebnerBasisFunction(KQ)(rels, KQ);
      gb := GroebnerBasis(I, gb);
    fi;
    
    if IsCompleteGroebnerBasis(gb) then
      return AdmitsFinitelyManyNontips(gb);
    elif IsFiniteDimensional(KQ) then
      return true;
    else
      TryNextMethod();
    fi;
  end
); # IsFiniteDimensional


################################################################
# Attribute Dimension for quotients of path algebras
# (analogue for path algebras uses standard GAP method,
# note that for infinite dimensional path algebras can fail!)
# It uses Groebner bases machinery (computes G.b. only in case
# it has not been computed).
# It returns "infinity" for infinite dimensional algebra.

InstallMethod( Dimension,
  "for quotients of path algebras",
  true,
  [IsQuotientOfPathAlgebra and IsFullFpPathAlgebra], 0,
  function( A )
    local gb, fam, KQ, I, rels;

    fam := ElementsFamily(FamilyObj(A));
    KQ := fam!.pathAlgebra;
    I := fam!.ideal;
    
    if HasGroebnerBasisOfIdeal(I) then
      gb := GroebnerBasisOfIdeal(I);
    else
      rels := GeneratorsOfIdeal(I);     
      gb := GroebnerBasisFunction(KQ)(rels, KQ);
      gb := GroebnerBasis(I, gb);
    fi;

    if IsCompleteGroebnerBasis(gb) then
      return NontipSize(gb);
    else
      TryNextMethod();
    fi;
  end
); # Dimension

InstallMethod( CanonicalBasis,
  "for quotients of path algebras",
  true,
  [IsQuotientOfPathAlgebra], 0,
  function( A )
    local B, fam, zero, nontips, parent, parentFam, parentOne;

    fam := ElementsFamily( FamilyObj( A ) );
    zero := Zero(LeftActingDomain(A));
    parent := fam!.pathAlgebra;
    parentFam := ElementsFamily( FamilyObj( parent ) );
    parentOne := One(parentFam!.zeroRing);

    B := Objectify( NewType( FamilyObj( A ),
                        IsBasis and IsCanonicalBasisFreeMagmaRingRep ),
                    rec() );
    SetUnderlyingLeftModule( B, A );
    if HasGroebnerBasisOfIdeal( fam!.ideal )
       and IsCompleteGroebnerBasis( GroebnerBasisOfIdeal( fam!.ideal ) )
       and IsFiniteDimensional( A )
    then
        nontips := Nontips(GroebnerBasisOfIdeal( fam!.ideal ));
        nontips := List( nontips, 
                         x -> ElementOfMagmaRing( parentFam,
                                                  parentFam!.zeroRing,
                                                  [parentOne],
                                                  [x] ) );
        SetBasisVectors( B,
            List( EnumeratorSorted( nontips ), 
                  x -> ElementOfQuotientOfPathAlgebra( fam, x, true ) ) );
        B!.zerovector := List( BasisVectors( B ), x -> zero );
    fi;
    SetIsCanonicalBasis( B, true );
    return B;
  end
);


InstallMethod( BasisOfDomain,
  "for quotients of path algebras (CanonicalBasis)",
  true,
  [IsQuotientOfPathAlgebra], 10,
  CanonicalBasis
);


InstallMethod( Coefficients,
  "for canonical bases of quotients of path algebras",
  IsCollsElms,
  [IsCanonicalBasisFreeMagmaRingRep, 
   IsElementOfQuotientOfPathAlgebra and IsNormalForm], 0,
  function( B, e )
    local coeffs, data, elms, i, fam;

    data := CoefficientsAndMagmaElements( e![1] );
    coeffs := ShallowCopy( B!.zerovector );
    fam := ElementsFamily(FamilyObj( UnderlyingLeftModule( B ) ));
    elms := EnumeratorSorted( Nontips( GroebnerBasisOfIdeal(fam!.ideal)));
    for i in [1, 3 .. Length( data )-1 ] do
        coeffs[ PositionSet( elms, data[i] ) ] := data[i+1];
    od;
    return coeffs;
  end
);


InstallMethod( ElementOfQuotientOfPathAlgebra, 
  "for family of quotient path algebra elements and a ring element",
  true,
  [ IsElementOfQuotientOfPathAlgebraFamily, IsRingElement, IsBool ], 0,
  function( fam, elm, normal )
      return Objectify( fam!.defaultType, [ Immutable(elm) ]);
  end
);


InstallMethod( ElementOfQuotientOfPathAlgebra,
  "for family of quotient path algebra elements and a ring element (n.f.)",
  true,
  [ IsElementOfQuotientOfPathAlgebraFamily and HasNormalFormFunction,
    IsRingElement, IsBool ], 0,
  function( fam, elm, normal )
    if normal then
        return Objectify( fam!.normalizedType, [ Immutable(elm) ] );
    else
        return NormalFormFunction(fam)(fam, elm);
    fi;
  end
);


# Embeds a path (element of a quiver) into a path algebra (of the same quiver)
InstallMethod( ElementOfPathAlgebra, 
  "for a path algebra  and a path = element of a quiver",
  true,
  [ IsPathAlgebra, IsPath  ], 0,
  function( PA, path )
      local F;
   
   if not path in QuiverOfPathAlgebra(PA) then
     Print("<path> should be an element of the quiver of the algebra <PA>\n");
  return false;
   fi;
   
   F := LeftActingDomain(PA);
      return ElementOfMagmaRing(FamilyObj(Zero(PA)),Zero(F),[One(F)],[path]);
  end
); 



InstallMethod( ExtRepOfObj,
  "for element of a quotient of a path algebra",
  true,
  [ IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep ], 0,
  elm -> ExtRepOfObj( elm![1] )
);


InstallMethod( IsNormalForm,
  "for f.p. algebra elements",
  true,
  [IsElementOfQuotientOfPathAlgebra], 0,
  ReturnFalse
);


#InstallMethod( \=,
#   "for normal forms of elements of quotients of path algebras",
#  IsIdenticalObj,
#  [IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep and IsNormalForm,
#   IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep and IsNormalForm],
#  0,
#  function(e, f)
#    return ExtRepOfObj(e![1]) = ExtRepOfObj(f![1]);
#  end
#);
  
InstallMethod( \=,
   "for normal forms of elements of quotients of path algebras",
  IsIdenticalObj,
  [IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep,
   IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep],
  0,
  function(e, f)
  local x, y;
     x := ElementOfQuotientOfPathAlgebra( FamilyObj( e ), e![ 1 ], IsNormalForm( e ) );
     y := ElementOfQuotientOfPathAlgebra( FamilyObj( f ), f![ 1 ], IsNormalForm( f ) );
     return ExtRepOfObj( x![ 1 ] ) = ExtRepOfObj( y![ 1 ] );
  end
);


InstallMethod( \<,
  "for elements of quotients of path algebras",
  IsIdenticalObj,
  [IsElementOfQuotientOfPathAlgebra and IsNormalForm and IsPackedElementDefaultRep,
   IsElementOfQuotientOfPathAlgebra and IsNormalForm and IsPackedElementDefaultRep],
  0,
  function(e, f)
    return e![1] < f![1];
  end
);


InstallMethod(\+,
  "quotient path algebra elements",
  IsIdenticalObj,
  [IsPackedElementDefaultRep and IsElementOfQuotientOfPathAlgebra,
   IsPackedElementDefaultRep and IsElementOfQuotientOfPathAlgebra], 0,
  function(e, f)
    return ElementOfQuotientOfPathAlgebra(FamilyObj(e),e![1]+f![1], 
                                  IsNormalForm(e) and IsNormalForm(f));
  end
);


InstallMethod(\-,
  "quotient path algebra elements",
  IsIdenticalObj,
  [IsPackedElementDefaultRep and IsElementOfQuotientOfPathAlgebra,
   IsPackedElementDefaultRep and IsElementOfQuotientOfPathAlgebra], 0,
  function(e, f)
    return ElementOfQuotientOfPathAlgebra(FamilyObj(e),e![1]-f![1], 
                                  IsNormalForm(e) and IsNormalForm(f));
  end
);


InstallMethod(\*,
  "quotient path algebra elements",
  IsIdenticalObj,
  [IsPackedElementDefaultRep and IsElementOfQuotientOfPathAlgebra,
   IsPackedElementDefaultRep and IsElementOfQuotientOfPathAlgebra], 0,
  function(e, f)
    return ElementOfQuotientOfPathAlgebra(FamilyObj(e),e![1]*f![1], false);
  end
);


InstallMethod(\*,
  "ring el * quot path algebra el",
  IsRingsMagmaRings,
  [IsRingElement,
   IsPackedElementDefaultRep and IsElementOfQuotientOfPathAlgebra],0,
  function(e,f)
    return ElementOfQuotientOfPathAlgebra(FamilyObj(f),e*f![1], IsNormalForm(f));
  end
);


InstallMethod(\*,
  "quot path algebra el*ring el",
  IsMagmaRingsRings,
    [IsPackedElementDefaultRep and IsElementOfQuotientOfPathAlgebra,
     IsRingElement],0,
    function(e,f)
        return ElementOfQuotientOfPathAlgebra(FamilyObj(e),e![1]*f, IsNormalForm(e));
end);


InstallMethod(\*,
  "quiver element and quotient of path algebra element",
  true, # should check to see that p is in correct quiver
  [IsPath, 
   IsPackedElementDefaultRep and IsElementOfQuotientOfPathAlgebra], 0,
  function( p, e )
    return ElementOfQuotientOfPathAlgebra(FamilyObj(e), p*e![1], false);
  end
);


InstallMethod(\*,
  "quotient of path algebra element and quiver element",
  true, # should check to see that p is in correct quiver
  [IsPackedElementDefaultRep and IsElementOfQuotientOfPathAlgebra,
   IsPath], 0,
  function( e, p )
    return ElementOfQuotientOfPathAlgebra(FamilyObj(e), e![1] * p, false);
  end
);


InstallMethod(AdditiveInverseOp,
  "quotient path algebra elements",
  true,
  [IsPackedElementDefaultRep and IsElementOfQuotientOfPathAlgebra], 0,
  function(e)
    return
        ElementOfQuotientOfPathAlgebra(FamilyObj(e),AdditiveInverse(e![1]),
                               IsNormalForm(e));
  end
);


InstallOtherMethod( OneOp,
  "for quotient path algebra algebra element",
  true,
  [ IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep ], 0,
  function( e )
  local one;
  one:= One( e![1] );
  if one <> fail then
    one:= ElementOfQuotientOfPathAlgebra( FamilyObj( e ), one, true );
  fi;

  return one;

  end
);


InstallMethod( ZeroOp,
  "for a quotient path algebra element",
  true,
  [ IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep ], 0,
  e -> ElementOfQuotientOfPathAlgebra( FamilyObj( e ), Zero( e![1] ), true )
);


InstallOtherMethod( MappedExpression,
  "for f.p. path algebra, and two lists of generators",
  IsElmsCollsX,
  [ IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep,
    IsHomogeneousList, IsHomogeneousList ], 0,
  function( expr, gens1, gens2 )
    return MappedExpression( expr![1], List(gens1, x -> x![1]), gens2 );
  end
);


InstallMethod( PrintObj,
  "quotient of path algebra elements",
  true,
  [ IsElementOfQuotientOfPathAlgebra and IsPackedElementDefaultRep ], 0,
  function( e )
    Print( "[", e![1], "]" );
  end
);


InstallMethod( ObjByExtRep,
  "for family of f.p. algebra elements with normal form",
  true,
  [ IsElementOfQuotientOfPathAlgebraFamily,
    IsList ], 0,
  function( Fam, descr )
    local pathAlgFam;

    pathAlgFam := ElementsFamily(FamilyObj(Fam!.pathAlgebra));

    return ElementOfQuotientOfPathAlgebra(Fam, 
                  ObjByExtRep( pathAlgFam, descr ), false);
  end
);


InstallHandlingByNiceBasis( "IsFpPathAlgebraElementsSpace",
  rec(
    detect := function( F, gens, V, zero )
      return IsElementOfQuotientOfPathAlgebraCollection( V );
    end,

    NiceFreeLeftModuleInfo := function( V )
      local gens, monomials, gen, list, i, zero, info;

      gens := GeneratorsOfLeftModule( V );
      monomials := [];

      for gen in gens do
        list := CoefficientsAndMagmaElements( gen![1] );
        for i in [1, 3 .. Length(list) - 1] do
            AddSet( monomials, list[i] );
        od;
      od;

      V!.monomials := monomials;

      zero := Zero( V )![1]![1];

      info := rec(monomials := monomials,
                  zerocoeff := zero,
                  family := ElementsFamily( FamilyObj( V ) ) );

      if IsEmpty( monomials ) then
        info.zerovector := [ Zero( LeftActingDomain( V ) ) ];
      else
        info.zerovector := ListWithIdenticalEntries( Length( monomials ),
                                                         zero );
      fi;

      return info;
    end,

    NiceVector := function(V, v)
      local info, c, monomials, i, pos;

      info := NiceFreeLeftModuleInfo( V );
      c := ShallowCopy( info.zerovector );
      v := CoefficientsAndMagmaElements( v![1] );
      monomials := info.monomials;

      for i in [2, 4 .. Length(v)] do
        pos := PositionSet( monomials, v[ i-1 ] );
        if pos = fail then
            return fail;
        fi;
        c[ pos ] := v[i];
      od;

      return c;
    end,

    UglyVector := function( V, r )
      local elem, info, parentFam;
      info := NiceFreeLeftModuleInfo( V );
      if Length( r ) <> Length( info.zerovector ) then
        return fail;
      elif IsEmpty( info.monomials ) then
        if IsZero( r ) then
            return Zero( V );
        else
            return fail;
        fi;
      fi;
      parentFam := ElementsFamily( FamilyObj( info.family!.pathAlgebra ) );
      elem := ElementOfMagmaRing( parentFam, parentFam!.zeroRing,
                                  r, info.monomials );
      return ElementOfQuotientOfPathAlgebra( info.family, elem, true );
    end
  )
);
    
    
InstallGlobalFunction( PathAlgebraContainingElement,
        function( elem )
    if IsElementOfQuotientOfPathAlgebra( elem ) then
        return FamilyObj( elem )!.wholeAlgebra;
    else
        return FamilyObj( elem )!.pathRing;
    fi;
end );


# If there was an IsElementOfPathAlgebra filter, it would be
# better to write PathAlgebraContainingElement as an operation
# with the following two methods:
#
# InstallMethod( PathAlgebraContainingElement,
#         "for an element of a path algebra",
#         [ IsElementOfPathAlgebra ],
#         function( elem )
#     return FamilyObj( elem )!.pathRing;
# end );
#
# InstallMethod( PathAlgebraContainingElement,
#         "for an element of a quotient of a path algebra",
#         [ IsElementOfQuotientOfPathAlgebra ],
#         function( elem )
#     return FamilyObj( elem )!.wholeAlgebra;
# end );


InstallMethod( OriginalPathAlgebra,
   "for a quotient of a path algebra",
   [ IsQuiverAlgebra ],
   function( quot )
      if IsPathAlgebra( quot ) then
         return quot;
      elif IsQuotientOfPathAlgebra( quot ) then
         return ElementsFamily( FamilyObj( quot ) )!.pathAlgebra;
      fi;
end );

InstallMethod( MakeUniformOnRight,
  "return array of right uniform path algebra elements",
  true,
  [ IsHomogeneousList ],
  0,
  function( gens )
    local l, t, v2, terms, uterms, newg, g, test;

    uterms := [];

    # get coefficients and monomials for all
    #  terms for gens:

    if Length(gens) = 0 then 
       return gens;
    else 
       test := IsPathAlgebra(PathAlgebraContainingElement(gens[1]));
       for g in gens do
          if test then 
             terms := CoefficientsAndMagmaElements(g);
          else
             terms := CoefficientsAndMagmaElements(g![1]);
          fi;    
          # Get terminus vertices for all terms:
          l := List(terms{[1,3..Length(terms)-1]}, x -> TargetOfPath(x));

          # Make the list unique:
          t := Unique(l);
 
          # Create uniformized array based on g:
          for v2 in t do
             newg := g*v2;
             if not IsZero(newg) then
                Add(uterms,newg);
             fi;
          od;
       od;
    fi;
    return Unique(uterms);
end
);

InstallMethod( GeneratorsTimesArrowsOnRight, 
   "for a path algebra",
   [ IsHomogeneousList ], 0,
   function( x ) 

   local A, fam, i, n, longer_list, extending_arrows, a, y;

   if Length(x) = 0 then
      Print("The entered list is empty.\n");
      return x;
   else
      A   := PathAlgebraContainingElement(x[1]);
      fam := ElementsFamily(FamilyObj(A));
      y   := MakeUniformOnRight(x);
      n   := Length(y); 

      longer_list := [];
      for i in [1..n] do
         extending_arrows := OutgoingArrowsOfVertex(TargetOfPath(TipMonomial(y[i]))); 
         for a in extending_arrows do
            if not IsZero(y[i]*a) then  
               Add(longer_list,y[i]*a);
            fi;
         od;      
      od; 

      return longer_list;
   fi;
end
);

InstallMethod( NthPowerOfArrowIdeal, 
   "for a path algebra",
   [ IsPathAlgebra, IS_INT ], 0,
   function( A, n ) 

   local num_vert, num_arrows, list, i;

   num_vert   := NumberOfVertices(QuiverOfPathAlgebra(A));
   num_arrows := NumberOfArrows(QuiverOfPathAlgebra(A));
   list := GeneratorsOfAlgebra(A){[1+num_vert..num_arrows+num_vert]};
   for i in [1..n-1] do 
      list := GeneratorsTimesArrowsOnRight(list);
   od;

   return list;
end
);

InstallMethod( TruncatedPathAlgebra, 
    "for a path algebra",
    [ IsField, IsQuiver, IS_INT ], 0,
    function( K, Q, n ) 

    local KQ, rels; 

    KQ   := PathAlgebra(K,Q);
    rels := NthPowerOfArrowIdeal(KQ,n);

    return KQ/rels;
end
);

InstallMethod( AddNthPowerToRelations, 
   "for a set of relations in a path algebra",
   [ IsPathAlgebra, IsHomogeneousList, IS_INT ], 0, 
   function ( pa, rels, n );
   
   Append(rels,NthPowerOfArrowIdeal(pa,n));   

   return rels; 

end
);

InstallMethod( OppositePathAlgebra,
        "for a path algebra",
        [ IsPathAlgebra ],
        function( PA )
    local PA_op, field, quiver_op;

    field := LeftActingDomain( PA );
    quiver_op := OppositeQuiver( QuiverOfPathAlgebra( PA ) );
    PA_op := PathAlgebra( field, quiver_op );

    SetOppositePathAlgebra( PA_op, PA );

    return PA_op;
end );


InstallMethod( OppositeAlgebra,
        "for a path algebra",
        [ IsPathAlgebra ],
        OppositePathAlgebra );


InstallGlobalFunction( OppositePathAlgebraElement,
        function( elem )
    local PA, PA_op, terms, op_term;

    PA := PathAlgebraContainingElement( elem );
    PA_op := OppositePathAlgebra( PA );

    if elem = Zero(PA) then 
       return Zero(PA_op);
    else 
       op_term :=
       function( t )
          return t.coeff * One( PA_op ) * OppositePath( t.monom );
       end;

       terms := PathAlgebraElementTerms( elem );
       return Sum( terms, op_term );
    fi;
end );


InstallMethod( OppositeRelations,
        "for a list of relations",
        [ IsDenseList ],
        function( rels )
    return List( rels, OppositePathAlgebraElement );
end );
        
        
InstallMethod( OppositePathAlgebra,
        "for a quotient of a path algebra",
        [ IsQuotientOfPathAlgebra ],
        function( quot )
    local PA, PA_op, rels, rels_op, I_op, gb, gbb, quot_op;

    PA := OriginalPathAlgebra( quot );
    PA_op := OppositePathAlgebra( PA );
    rels  := RelatorsOfFpAlgebra( quot );
    rels_op := OppositeRelations( rels );
    I_op := Ideal( PA_op, rels_op );
    gb   := GroebnerBasisFunction(PA_op)(rels_op,PA_op);
    gbb  := GroebnerBasis(I_op,gb);
    quot_op := PA_op / I_op;
    
#    if HasIsAdmissibleQuotientOfPathAlgebra(quot) and IsAdmissibleQuotientOfPathAlgebra(quot) then
#        SetIsAdmissibleQuotientOfPathAlgebra(quot_op, true);
#    fi; 
    if IsAdmissibleQuotientOfPathAlgebra(quot) then
        SetFilterObj(quot_op, IsAdmissibleQuotientOfPathAlgebra );
    fi; 

    SetOppositePathAlgebra( quot_op, quot );

    return quot_op;
end );


InstallMethod( OppositeAlgebra,
        "for a quotient of a path algebra",
        [ IsQuotientOfPathAlgebra ],
        OppositePathAlgebra );

InstallMethod( Centre,
   "for a path algebra",
   [ IsQuotientOfPathAlgebra ], 0,
   function( A ) 

   local Q, K, num_vert, vertices, arrows, B, cycle_list, i, j, b, 
         pos, commutators, center, zero_count, a, c, x, cycles, matrix,
         data, coeffs, fam, elms, solutions, gbb;
   
   if not IsFiniteDimensional(A) then
       Error("the entered algebra is not finite dimensional,\n");
   fi;
   B := CanonicalBasis(A);
   Q := QuiverOfPathAlgebra(A); 
   K := LeftActingDomain(A);
   num_vert := NumberOfVertices(Q);
   vertices := VerticesOfQuiver(Q);
   arrows   := GeneratorsOfAlgebra(A){[2+num_vert..1+num_vert+NumberOfArrows(Q)]};
  
   cycle_list := [];
   for b in B do
      if SourceOfPath(TipMonomial(b)) = TargetOfPath(TipMonomial(b)) then 
         Add(cycle_list,b);
      fi;
   od;
   commutators := [];
   center := [];
   cycles := Length(cycle_list);
   for c in cycle_list do
      for a in arrows do
         Add(commutators,c*a-a*c);
      od;
   od;

   matrix := NullMat(cycles,Length(B)*NumberOfArrows(Q),K);

   for j in [1..cycles] do
      for i in [1..NumberOfArrows(Q)] do
         matrix[j]{[Length(B)*(i-1)+1..Length(B)*i]} := Coefficients(B,commutators[i+(j-1)*NumberOfArrows(Q)]); 
      od;
   od;

   solutions := NullspaceMat(matrix);

   center := [];
   for i in [1..Length(solutions)] do
      x := Zero(A);
      for j in [1..cycles] do 
         if solutions[i][j] <> Zero(K) then 
            x := x + solutions[i][j]*cycle_list[j];
         fi;
      od;
      center[i] := x;
   od;
   return SubalgebraWithOne(A,center,"basis");
end
);

InstallMethod( Centre,
    "for a path algebra",
    [ IsPathAlgebra ], 0,
    function( A ) 

    local Q, vertexlabels, arrowlabels, vertices, arrows, components, basis, i,
          compverticespositions, temp, comparrows, cycle, lastone, v, n, tempx, j, 
          k, index;
    #
    # If  <A>  is an indecomposable path algebra, then the center of  <A>  is the 
    # linear span of the identity if the defining quiver is not an oriented cycle
    # (an A_n-tilde quiver).  If the defining quiver of  <A>  is an oriented cycle, 
    # then the center is generated by the identity and powers of the sum of all the 
    # different shortest cycles in the defining quiver.  
    #
    Q := QuiverOfPathAlgebra(A); 
    vertexlabels := List(VerticesOfQuiver(Q), String);
    arrowlabels := List(ArrowsOfQuiver(Q), String);
    vertices := VerticesOfQuiver(Q)*One(A); 
    arrows := ArrowsOfQuiver(Q); 
    components := ConnectedComponentsOfQuiver(Q);
    basis := [];
    for i in [1..Length(components)] do
        #
        # Constructing the linear span of the sum of the vertices, ie. the 
        # identity for this block of the path algebra.
        #
        compverticespositions := List(VerticesOfQuiver(components[i]), String);
        compverticespositions := List(compverticespositions, v -> Position(vertexlabels,v)); 
        temp := Zero(A);
        for n in compverticespositions do
            temp := temp + vertices[n];
        od;
        Add(basis, temp);
        # 
        # Next, if the component is given by an oriented cycle, construct the sum of all the 
        # different cycles in the component.
        #
        if ForAll(VerticesOfQuiver(components[i]), v -> Length(IncomingArrowsOfVertex(v)) = 1) and 
           ForAll(VerticesOfQuiver(components[i]), v -> Length(OutgoingArrowsOfVertex(v)) = 1) then
            # define linear span of the sum of cycles in the quiver
            comparrows := List(ArrowsOfQuiver(components[i]), String);
            comparrows := List(comparrows, a -> arrows[Position(arrowlabels, a)]);
            if Length(comparrows) > 0 then
                cycle := [];
                lastone := comparrows[1];
                Add(cycle, lastone);
                for j in [2..Length(comparrows)] do
                    v := TargetOfPath(lastone);
                    lastone := First(comparrows, a -> SourceOfPath(a) = v);
                    Add(cycle, lastone);
                od;
                temp := Zero(A);
                n := Length(comparrows);
                for j in [0..Length(comparrows) - 1] do
                    tempx := One(A);
                    for k in [0..Length(comparrows) - 1] do
                        tempx := tempx*cycle[((j + k) mod n) + 1];
                    od;
                    temp := temp + tempx;
                od;
                Add(basis, temp); 
            fi;
        fi;
    od;
    
    return SubalgebraWithOne( A, basis );
end
  );


#######################################################################
##
#O  VertexPosition(<elm>)
##
##  This function assumes that the input is a residue class of a trivial
##  path in finite dimensional quotient of a path algebra, and it finds  
##  the position of this trivial path/vertex in the list of vertices for
##  the quiver used to define the algebra.
##
InstallMethod ( VertexPosition, 
   "for an element in a quotient of a path algebra",
   true,
   [ IsElementOfQuotientOfPathAlgebra ],
   0,
   function( elm )

   return elm![1]![2][1]!.gen_pos;
end
);

#######################################################################
##
#O  VertexPosition(<elm>)
##
##  This function assumes that the input is a trivial path in finite 
##  dimensional a path algebra, and it finds the position of this 
##  trivial path/vertex in the list of vertices for the quiver used 
##  to define the algebra.
##
InstallOtherMethod ( VertexPosition, 
   "for an element in a PathAlgebra",
   true,
   [ IsElementOfMagmaRingModuloRelations ],
   0,
   function( elm )

   if "pathRing" in NamesOfComponents(FamilyObj(elm)) then 
      return elm![2][1]!.gen_pos;
   else
      return false;
   fi;
end
);

#######################################################################
##
#O  IsSelfinjectiveAlgebra ( <A> )
##
##  This function returns true or false depending on whether or not 
##  the algebra  <A>  is selfinjective.
##
##  This test is based on the paper by T. Nakayama: On Frobeniusean 
##  algebras I. Annals of Mathematics, Vol. 40, No.3, July, 1939. It 
##  assumes that the input is a basic algebra, which is always the 
##  case for a quotient of a path algebra modulo an admissible ideal.
##
##
InstallMethod( IsSelfinjectiveAlgebra, 
    "for a finite dimension (quotient of) a path algebra",
    [ IsQuiverAlgebra ], 0,
    function( A ) 

    local Q, soclesofproj, test; 
   
    if not IsFiniteDimensional(A) then 
        return false;
    fi;
    if not IsPathAlgebra(A) and not IsAdmissibleQuotientOfPathAlgebra(A) then 
        TryNextMethod();
    fi;
    #
    # If the algebra is a path algebra.
    #
    if IsPathAlgebra(A) then 
        Q := QuiverOfPathAlgebra(A);
        if NumberOfArrows(Q) > 0 then 
            return false;
        else
            return true;
        fi;
    fi;
    #
    # By now we know that the algebra is a quotient of a path algebra.
    # First checking if all indecomposable projective modules has a simpel
    # socle, and checking if all simple modules occur in the socle of the
    # indecomposable projective modules. 
    #
    soclesofproj := List(IndecProjectiveModules(A), p -> SocleOfModule(p));
    if not ForAll(soclesofproj, x -> Dimension(x) = 1) then
        return false;
    fi;
    test := Sum(List(soclesofproj, x -> DimensionVector(x)));
    
    return ForAll(test, t -> t = 1); 
end
);



InstallOtherMethod( CartanMatrix, 
    "for a finite dimensional (quotient of) path algebra",
    [ IsQuiverAlgebra ], 0,
    function( A ) 

    local P, C, i;
   
    if not IsFiniteDimensional(A) then 
 Print("Algebra is not finite dimensional!\n");
        return fail;
    fi;
    if not IsPathAlgebra(A) and not IsAdmissibleQuotientOfPathAlgebra(A) then 
 Print("Not a bound quiver algebra!\n");
        return fail;
    fi;
    P := IndecProjectiveModules(A);
    C := [];
    for i in [1..Length(P)] do
        Add(C,DimensionVector(P[i]));
    od;

    return C;
end
); # CartanMatrix

InstallMethod( CoxeterMatrix, 
    "for a finite dimensional (quotient of) path algebra",
    [ IsQuiverAlgebra ], 0,
    function( A ) 

    local P, C, i;

    C := CartanMatrix(A);
    if C = fail then
 Print("Unable to determine the Cartan matrix!\n");
        return fail;
    fi;
    if DeterminantMat(C) <> 0 then 
        return (-1)*C^(-1)*TransposedMat(C);
    else
        Print("The Cartan matrix is not invertible!\n");
 return fail;
    fi;
end
); # CoxeterMatrix

InstallMethod( CoxeterPolynomial, 
    "for a finite dimensional (quotient of) path algebra",
    [ IsQuiverAlgebra ], 0,
    function( A ) 

    local P, C, i;

    C := CoxeterMatrix(A);
    if C <> fail then 
        return CharacteristicPolynomial(C);
    else
        return fail;
    fi;
end
); # CoxeterPolynomial


InstallMethod( TipMonomialandCoefficientOfVector, 
   "for a path algebra",
   [ IsQuiverAlgebra, IsCollection ], 0,
   function( A, x ) 

   local pos, tipmonomials, sortedtipmonomials, tippath, i, n;

   pos := 1;
   tipmonomials := List(x,TipMonomial);
   sortedtipmonomials := ShallowCopy(tipmonomials);
   Sort(sortedtipmonomials,\<);

   if Length(tipmonomials) > 0 then
      tippath := sortedtipmonomials[Length(sortedtipmonomials)];
      pos := Minimum(Positions(tipmonomials,tippath));
   fi;

   return [pos,TipMonomial(x[pos]),TipCoefficient(x[pos])];
end
);


InstallMethod( TipReduceVectors, 
   "for a path algebra",
   [ IsQuiverAlgebra, IsCollection ], 0,
   function( A, x ) 

   local i, j, k, n, y, s, t, pos_m, z, stop;

   n := Length(x);
   if n > 0 then 
      for k in [1..n] do
        for j in [1..n] do
            if j <> k then  
               s := TipMonomialandCoefficientOfVector(A,x[k]);
               t := TipMonomialandCoefficientOfVector(A,x[j]); 
               if ( s <> fail ) and ( t <> fail ) then
                  if ( s[1] = t[1] ) and ( s[2] = t[2] ) and 
                     ( s[3] <> Zero(LeftActingDomain(A)) ) then 
                     x[j] := x[j] - (t[3]/s[3])*x[k];
                  fi;
               fi;
            fi;
        od;
      od;
      return x;
   fi;
end
);

#
# This has a bug !!!!!!!!!!!!!!!!!!!
#
InstallMethod( CoefficientsOfVectors, 
   "for a path algebra",
   [ IsAlgebra, IsCollection, IsList ], 0,
   function( A, x, y ) 

   local i, j, n, s, t, tiplist, vector, K, zero_vector, z;

   tiplist := [];
   for i in [1..Length(x)] do 
      Add(tiplist,TipMonomialandCoefficientOfVector(A,x[i]){[1..2]});
   od;

   vector := []; 
   K := LeftActingDomain(A);
   for i in [1..Length(x)] do
      Add(vector,Zero(K));
   od;
   zero_vector := [];
   for i in [1..Length(y)] do
      Add(zero_vector,Zero(A));
   od;

   z := y;
   if z = zero_vector then
      return vector;
   else 
      repeat
         s := TipMonomialandCoefficientOfVector(A,z);
         j := Position(tiplist,s{[1..2]});
         if j = fail then 
            return [x,y];
         fi;
         t := TipMonomialandCoefficientOfVector(A,x[j]); 
         z := z - (s[3]/t[3])*x[j];
         vector[j] := vector[j] + (s[3]/t[3]);
      until 
         z = zero_vector;
      return vector;
   fi;
end
);




#######################################################################
##
#P  IsSymmetricAlgebra( <A> )
##
##  This function determines if the algebra  A  is a symmetric algebra,
##  if it is a (quotient of a) path algebra. 
##
InstallMethod( IsSymmetricAlgebra, 
    "for a quotient of a path algebra",
    [ IsQuiverAlgebra ], 0,
    function( A )

   local   M,  DM;

    if not IsFiniteDimensional( A ) then 
        return false;
    fi;
    if IsPathAlgebra( A ) then
        return Length( ArrowsOfQuiver( QuiverOfPathAlgebra( A ) ) ) = 0;
    fi;    
    #
    # By now we know that the algebra is a finite dimensional quotient of a path algebra.
    #
    if not IsSelfinjectiveAlgebra( A ) then
        return false;
    fi;
    M := AlgebraAsModuleOverEnvelopingAlgebra( A );
    DM := DualOfAlgebraAsModuleOverEnvelopingAlgebra( A );

    return IsomorphicModules( M, DM );
end
);

#######################################################################
##
#P  IsSymmetricAlgebra( <A> )
##
##  This function determines if the algebra  A  is a symmetric algebra,
##  if it is a (quotient of a) path algebra. 
##
#InstallMethod( IsSymmetricAlgebra, 
#    "for a quotient of a path algebra",
#    [ IsQuiverAlgebra ], 0,
#    function( A )
#
#    local   b, BA, x, y;
#
#    b := FrobeniusForm( A );
#    if b = false then
#       return false;
#    fi;
#    BA := Basis( A );
#    for x in BA do
#     for y in BA do
#     if b( x, y ) <> b( y, x ) then
#        return false;
#     fi;
# od;
#    od;
#
#    return true;
#end
#);

#######################################################################
##
#P  IsWeaklySymmetricAlgebra( <A> )
##
##  This function determines if the algebra  A  is a weakly symmetric 
##  algebra, if it is a (quotient of a) path algebra. 
##
InstallMethod( IsWeaklySymmetricAlgebra, 
   "for a quotient of a path algebra",
   [ IsQuiverAlgebra ], 0,
   function( A ) 

   local P;
   
   if IsSelfinjectiveAlgebra(A) then
       P := IndecProjectiveModules(A);
       return ForAll(P, x -> DimensionVector(SocleOfModule(x)) = DimensionVector(TopOfModule(x)));
   else   
       return false; 
   fi;
end
);

InstallOtherMethod( \/,
    "for PathAlgebra and a list of generators",
    IsIdenticalObj,
    [ IsPathAlgebra, IsList ],
    function( KQ, relators )
    
    local gb, I, A;
    
    if not ForAll(relators, x -> ( x in KQ ) ) then
        Error("the entered list of elements should be in the path algebra!");
    fi;
    gb := GroebnerBasisFunction(KQ)(relators, KQ);
    I := Ideal(KQ,gb);
    GroebnerBasis(I,gb);
    A := KQ/I; 
#    if IsAdmissibleIdeal(I) then 
#        SetIsAdmissibleQuotientOfPathAlgebra(A, true);
#    fi;
    if IsAdmissibleIdeal(I) then 
        SetFilterObj(A, IsAdmissibleQuotientOfPathAlgebra );
    fi;

    return A;
end 
); 

########################################################################
##
#P  IsSchurianAlgebra( <A> ) 
##  <A> = a path algebra or a quotient of a path algebra
##
##  It tests if an algebra <A> is a schurian  algebra.
##  By definition it means that:
##  for all x,y\in Q_0 dim A(x,y)<=1.
##  Note: This method fail when a Groebner basis
##  for ideal has not been computed before creating q quotient!
##
InstallMethod( IsSchurianAlgebra,
    "for PathAlgebra or QuotientOfPathAlgebra",
    true,
    [ IsQuiverAlgebra ],
    function( A )
    
    local Q, test;
    
    if not IsPathAlgebra(A) and not IsAdmissibleQuotientOfPathAlgebra(A) then 
       TryNextMethod();
    fi;
    if IsFiniteDimensional(A) then
        test := Flat(List(IndecProjectiveModules(A), x -> DimensionVector(x)));
        return ForAll(test, x -> ( x <= 1 ) );
    else
        Error("the entered algebra is not finite dimensional,\n");
    fi;    
end 
); 

#################################################################
##
#P  IsSemicommutativeAlgebra( <A> ) 
##  <A> = a path algebra
##
##  It tests if a path algebra <A> is a semicommutative  algebra. 
##  Note that for a path algebra it is an empty condition
##  (when <A> is schurian + acyclic, cf. description for quotients below).
##  
InstallMethod( IsSemicommutativeAlgebra,
    "for path algebras",
    true,
    [ IsPathAlgebra ], 0,
    function ( A )
    
    local Q; 
    
    if not IsSchurianAlgebra(A) then
        return false;
    fi;
    
    Q := QuiverOfPathAlgebra(A);
    return IsAcyclicQuiver(Q);  
end
); # IsSemicommutativeAlgebra for IsPathAlgebra


########################################################################
##
#P  IsSemicommutativeAlgebra( <A> ) 
##  <A> = a quotient of a path algebra
##
##  It tests if a quotient of a path algebra <A>=kQ/I is a semicommutative  algebra.
##  By definition it means that:
##  1. A is schurian (i.e. for all x,y\in Q_0 dim A(x,y)<=1).
##  2. Quiver Q of A is acyclic.
##  3. For all pairs of vertices (x,y) the following condition is satisfied:
##     for every two paths P,P' from x to y:
##     P\in I <=> P'\in I
##
  
InstallMethod( IsSemicommutativeAlgebra,
    "for quotients of path algebras",
    true,
    [ IsQuotientOfPathAlgebra ], 0,
    function ( A )
    
    local Q, PA, I, vertices, vertex, v, vt,
          paths, path, p,
          noofverts, noofpaths,
          eA, pp,
          inI, notinI;
    
    PA := OriginalPathAlgebra(A);
    Q := QuiverOfPathAlgebra(PA);
    if (not IsAcyclicQuiver(Q)) 
      or (not IsSchurianAlgebra(A))
      then
        return false;
    fi;
    
    I := ElementsFamily(FamilyObj(A))!.ideal;
    
    vertices := VerticesOfQuiver(Q);
    paths := [];
    for path in Q do
      if LengthOfPath(path) > 0 then
        Add(paths, path);
      fi;
    od;
    noofverts := Length(vertices);
    noofpaths := Length(paths);
    eA := [];
    for v in [1..noofverts] do
      eA[v] := []; # here will be all paths starting from v
      for p in [1..noofpaths] do
        pp := vertices[v]*paths[p];
        if pp <> Zero(Q) then
          Add(eA[v], pp);
        fi;  
      od;
    od;
    
    for v in [1..noofverts] do
      for vt in [1..noofverts] do
        # checking all paths from v to vt if they belong to I
        inI := 0;
        notinI := 0;
        for pp in eA[v] do # now pp is a path starting from v
          pp := pp*vertices[vt];
          if pp <> Zero(Q) then
            if ElementOfPathAlgebra(PA, pp) in I then
              inI := inI + 1;
            else
              notinI := notinI + 1;
            fi;
            if (inI > 0) and (notinI > 0) then
              return false;
            fi;
          fi;
        od;
      od;
    od;
    
    return true;
end
); # IsSemicommutativeAlgebra for IsQuotientOfPathAlgebra

#######################################################################
##
#P  IsDistributiveAlgebra( <A> ) 
##  
##  This function returns true if the algebra  <A>  is finite 
##  dimensional and distributive. Otherwise it returns false.
##
InstallMethod ( IsDistributiveAlgebra, 
    "for an QuotientOfPathAlgebra",
    true,
    [ IsQuotientOfPathAlgebra ],
    0,
    function( A )

    local pids, localrings, radicalseries, uniserialtest, radlocalrings, 
          i, j, module, testspace, flag, radtestspace;
    
    if not IsFiniteDimensional(A) then 
        Error("the entered algebra is not finite dimensional,\n");
    fi;
    if not IsAdmissibleQuotientOfPathAlgebra(A) then
        TryNextMethod();
    fi;
    #  Finding a complete set of primitive idempotents in  A.
    pids := List(VerticesOfQuiver(QuiverOfPathAlgebra(A)), v -> v*One(A));
    #  
    #  For each primitive idempotent e, compute eAe and check if 
    #  eAe is a uniserial algebra for all e.
    localrings := List(pids, e -> Subalgebra(A,e*BasisVectors(Basis(A))*e));  
    # 
    #  Check if all algebras in  localrings  are unisersial.
    #
    radicalseries := List(localrings, R -> RadicalSeriesOfAlgebra(R));
    uniserialtest := Flat(List(radicalseries, series -> List([1..Length(series) - 1], i -> Dimension(series[i]) - Dimension(series[i+1]))));
    if not ForAll(uniserialtest, x -> x = 1) then 
       return false;
    fi;
    #  Check if the eAe-module eAf is uniserial or 
    #  the fAf-module eAf is uniserial for all pair
    #  of primitive idempotents e and f. 
    radlocalrings := List(localrings, R -> Subalgebra(R, Basis(RadicalOfAlgebra(R))));
#    radlocalrings := List(localrings, R -> BasisVectors(Basis(RadicalOfAlgebra(R))));
    for i in [1..Length(pids)] do
        for j in [1..Length(pids)] do 
            if i <> j then 
                module := LeftAlgebraModule(localrings[i],\*,Subspace(A,pids[i]*BasisVectors(Basis(A))*pids[j]));
                # compute the radical series of this module over localrings[i] and 
                # check if all layers are one dimensional.
                testspace := ShallowCopy(BasisVectors(Basis(module))); 
                flag := true;
                while Length(testspace) <> 0 and flag do
                    if Dimension(radlocalrings[i]) = 0 then
                        radtestspace := [];
                    else
# radtestspace := Filtered(Flat(List(testspace, t -> radlocalrings[i]^t)), x -> x <> Zero(x));
                        radtestspace := Filtered(Flat(List(testspace, t -> List(BasisVectors(Basis(radlocalrings[i])), b -> b^t))), x -> x <> Zero(x));
                    fi;
                    if Length(radtestspace) = 0 then
                        if Length(testspace) <> 1 then 
                            flag := false;
                        else
                            testspace := radtestspace;
                        fi;
                    else
                        radtestspace := Subspace(module, radtestspace); 
                        if Length(testspace) - Dimension(radtestspace) <> 1 then
                            flag := false;
                        else
                            testspace := ShallowCopy(BasisVectors(Basis(radtestspace)));
                        fi;
                    fi;
                od;
                if not flag then 
                    module := RightAlgebraModule(localrings[j],\*,Subspace(A,pids[i]*BasisVectors(Basis(A))*pids[j]));
                    # compute the radical series of this module over localrings[j] and
                    # check if all layers are one dimensional.
                    testspace := ShallowCopy(BasisVectors(Basis(module))); 
                    while Length(testspace) <> 0 do
                        if Dimension(radlocalrings[j]) = 0 then
                            radtestspace := [];
                        else
                            radtestspace := Filtered(Flat(List(testspace, t -> List(BasisVectors(Basis(radlocalrings[j])), b -> t^b))), x -> x <> Zero(x));                      
# radtestspace := Filtered(Flat(List(testspace, t -> t*radlocalrings[j])), x -> x <> Zero(x));
                        fi;
                        if Length(radtestspace) = 0 then
                            if Length(testspace) <> 1 then 
                                return false;
                            else
                                testspace := radtestspace;
                            fi;
                        else
                            radtestspace := Subspace(module, radtestspace); 
                            if Length(testspace) - Dimension(radtestspace) <> 1 then
                                return false;
                            else
                                testspace := ShallowCopy(BasisVectors(Basis(radtestspace)));
                            fi;
                        fi;
                    od;
                fi;
            fi;
        od;
    od;
    
    return true;
end 
);          

InstallOtherMethod ( IsDistributiveAlgebra, 
    "for an PathAlgebra",
    true,
    [ IsPathAlgebra ],
    0,
    function( A );
    
    return IsTreeQuiver(QuiverOfPathAlgebra(A));
end
);

#######################################################################
##
#A  NakayamaPermutation( <A> )
##
##  Checks if the entered algebra is selfinjective, and returns false
##  otherwise. When the algebra is selfinjective, then it returns a 
##  list of two elements, where the first is the Nakayama permutation 
##  on the simple modules, while the second is the Nakayama permutation
##  on the indexing set of the simple modules. 
## 
InstallMethod( NakayamaPermutation, 
    "for an algebra",
    [ IsQuotientOfPathAlgebra ], 0,
    function( A )

    local perm, nakayamaperm, nakayamaperm_index;
    
    if not IsSelfinjectiveAlgebra(A) then 
        return false;
    fi;
    perm := List(IndecProjectiveModules(A), p -> SocleOfModule(p));
    nakayamaperm := function( x )
        local dimvector, pos;
        
        dimvector := DimensionVector(x);
        if Dimension(x) <> 1 then
            Error("not a simple module was entered as an argument for the Nakayama permutation,\n");
        fi;
        pos := Position(dimvector,1);
        return perm[pos];
    end;
    nakayamaperm_index := function( x )
        local pos;
        
        if not x in [1..Length(perm)] then
            Error("an incorrect value was entered as an argument for the Nakayama permutation,\n");
        fi;
        
        return Position(DimensionVector(perm[x]),1);
    end;
    return [nakayamaperm, nakayamaperm_index];
end
);

InstallOtherMethod( NakayamaPermutation, 
    "for an algebra",
    [ IsPathAlgebra ], 0,
    function( A )

    local n, nakayamaperm, nakayamaperm_index;
    
    if not IsSelfinjectiveAlgebra(A) then 
        return false;
    fi;
    n := NumberOfVertices(QuiverOfPathAlgebra(A));
    nakayamaperm := function( x )
        local dimvector, pos;
        
        dimvector := DimensionVector(x);
        if Dimension(x) <> 1 then
            Error("not a simple module was entered as an argument for the Nakayama permutation,\n");
        fi;
        return x;
    end;
    nakayamaperm_index := function( x )
        local pos;
        
        if not x in [1..n] then
            Error("an incorrect value was entered as an argument for the Nakayama permutation,\n");
        fi;
        
        return x;
    end;
    
    return [nakayamaperm, nakayamaperm_index];
end
);

#######################################################################
##
#A  NakayamaAutomorphism( <A> )
##
##  Checks if the entered algebra is selfinjective, and returns false
##  otherwise. When the algebra is selfinjective, then it returns the 
##  Nakayama automorphism of  <A>. 
##
InstallMethod( NakayamaAutomorphism, 
--> --------------------

--> maximum size reached

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

[ Dauer der Verarbeitung: 0.44 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


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