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

Quelle  involutive-np.gi   Sprache: unbekannt

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

#############################################################################
##
##  involutive-np.gi     GAP package IBNP        Gareth Evans & Chris Wensley
##  

#############################################################################
##
#M  LeftDivision( <alg> <mons> <ord> )
##
InstallMethod( LeftDivision, "generic method for list of monomials",
    true, [ IsAlgebra, IsList, IsNoncommutativeMonomialOrdering ], 0,
function( A, mons, ord )

    local genA, ngens, nmons, lvars, rvars, i, emoni;
    genA := GeneratorsOfAlgebra( A );
    if not ( genA[1] = One(A) ) then 
        Error( "expecting genA[1] = One(A)" );
    fi;
    genA := genA{ [2..Length(genA)] };
    ngens := Length( genA );
    nmons := Length( mons );
    lvars := ListWithIdenticalEntries( nmons, 0 );
    rvars := ListWithIdenticalEntries( nmons, 0 );
    for i in [1..nmons] do   ## for each monnomial 
        lvars[i] := [1..ngens];
        rvars[i] := [ ];
    od;
    return [ lvars, rvars ];
end );


#############################################################################
##
#M  RightDivision( <alg> <mons> <ord> )
##
InstallMethod( RightDivision, "generic method for list of monomials",
    true, [ IsAlgebra, IsList, IsNoncommutativeMonomialOrdering ], 0,
function( A, mons, ord )

    local genA, ngens, nmons, lvars, rvars, i, emoni;
    genA := GeneratorsOfAlgebra( A );
    if not ( genA[1] = One(A) ) then 
        Error( "expecting genA[1] = One(A)" );
    fi;
    genA := genA{ [2..Length(genA)] };
    ngens := Length( genA );
    nmons := Length( mons );
    lvars := ListWithIdenticalEntries( nmons, 0 );
    rvars := ListWithIdenticalEntries( nmons, 0 );
    for i in [1..nmons] do   ## for each monnomial 
        lvars[i] := [ ];
        rvars[i] := [1..ngens];
    od;
    return [ lvars, rvars ];
end );

#############################################################################
##
#M  LeftOverlapDivision( <alg>, <mons> <ord> )
##
InstallMethod( LeftOverlapDivision, "generic method for list of monomials",
    true, [ IsAlgebra, IsList, IsNoncommutativeMonomialOrdering ], 0,
function( A, mons, ord )

    ## Overview: this is an implementation of Algorithm 13.
    ## returns local overlap-based multiplicative variables
    ## Detail: this function implements various algorithms
    ## described in the thesis "Noncommutative Involutive Bases"
    ## for finding left and right multiplicative variables
    ## for a set of polynomials based on the overlaps
    ## between the leading monomials of the polynomials.

    local  genA, ngenA, nmons, lenmon, nonMult, leftMult, rightMult, 
           i, moni, leni, j, monj, lenj, k, m;

    genA := GeneratorsOfAlgebra( A );
    if not ( genA[1] = One(A) ) then 
        Error( "expecting genA[1] = One(A)" );
    fi;
    genA := genA{ [2..Length(genA)] };
    ngenA := Length( genA );
    nmons := Length( mons );
    if( nmons = 0 ) then 
        return [ [], [] ];
    fi;
    ## set up arrays
    lenmon := List( mons, m -> Length(m) );
    leftMult := ListWithIdenticalEntries( nmons, 0 );
    rightMult := ListWithIdenticalEntries( nmons, 0 );
    nonMult := ListWithIdenticalEntries( nmons, 0 );
    for i in [1..nmons] do
        nonMult[i] := [ ];
    od;
    ## apply the conditions
    for i in [1..nmons] do
        moni := mons[i];
        leni := lenmon[i];
        for j in [i..nmons] do
            monj := mons[j];
            lenj := lenmon[j];
            if ( i <> j ) then
                ## looking for monj as a subword of moni
                for k in [1..leni-lenj] do
                    if moni{[k..(k+lenj-1)]} = monj then
                        Info( InfoIBNP, 3, "(1) [i,j,k]=", [i,j,k],
                            " adding ", moni[k+lenj], " to ", nonMult[j] );
                        Add( nonMult[j], moni[k+lenj] );
                    fi;
                od;
                ## looking for moni as a subword of monj
                for k in [1..lenj-leni] do
                    if monj{[k..(k+leni-1)]} = moni then
                        Info( InfoIBNP, 3, "(2) [i,j,k]=", [i,j,k],
                            " adding ", monj[k+leni], " to ", nonMult[i] );
                        Add( nonMult[i], monj[k+leni] );
                    fi;
                od;
            fi;
            m := Minimum( leni-1, lenj-1 );
            ## looking for overlap RHS[j] = LHS[i]
            for k in [1..m] do
                if ( moni{[1..k]} = monj{[(lenj-k+1)..lenj]} ) then
                        Info( InfoIBNP, 3, "(3) [i,j,k]=", [i,j,k],
                            " adding ", moni[k+1], " to ", nonMult[j] );
                        Add( nonMult[j], moni[k+1] );
                fi;
            od;
            ## looking for overlap RHS[i] = LHS[j]
            for k in [1..m] do
                if ( monj{[1..k]} = moni{[(leni-k+1)..leni]} ) then
                       Info( InfoIBNP, 3, "(4) [i,j,k]=", [i,j,k],
                            " adding ", monj[k+1], " to ", nonMult[i] );
                        Add( nonMult[i], monj[k+1] );
                fi;
            od;
        od;
    od;
    for i in [1..nmons] do
        leftMult[i] := [1..ngenA];
        rightMult[i] := Difference( [1..ngenA], nonMult[i] );
    od;
    return [ leftMult, rightMult ];
end );

#############################################################################
##
#M  RightOverlapDivision( <alg> <mons> <ord> )
##
InstallMethod( RightOverlapDivision, "generic method for list of monomials",
    true, [ IsAlgebra, IsList, IsNoncommutativeMonomialOrdering ], 0,
function( A, mons, ord )

    ## Overview: this is an implementation of Algorithm 13.
    ## returns local overlap-based multiplicative variables
    ## Detail: this function implements various algorithms
    ## described in the thesis "Noncommutative Involutive Bases"
    ## for finding left and right multiplicative variables
    ## for a set of polynomials based on the overlaps
    ## between the leading monomials of the polynomials.
    ## This function is the mirror image of LeftOverlapDivision.

    local  genA, ngenA, nmons, lenmon, nonMult, leftMult, rightMult, 
           i, moni, leni, j, monj, lenj, k, m;

    genA := GeneratorsOfAlgebra( A );
    if not ( genA[1] = One(A) ) then 
        Error( "expecting genA[1] = One(A)" );
    fi;
    genA := genA{ [2..Length(genA)] };
    ngenA := Length( genA );
    nmons := Length( mons );
    if( nmons = 0 ) then 
        return [ [], [] ];
    fi;
    ## set up arrays
    lenmon := List( mons, m -> Length(m) );
    leftMult := ListWithIdenticalEntries( nmons, 0 );
    rightMult := ListWithIdenticalEntries( nmons, 0 );
    nonMult := ListWithIdenticalEntries( nmons, 0 );
    for i in [1..nmons] do
        nonMult[i] := [ ];
    od;
    ## apply the conditions
    for i in [1..nmons] do
        moni := mons[i];
        leni := lenmon[i];
        for j in [i..nmons] do
            monj := mons[j];
            lenj := lenmon[j];
            if ( i <> j ) then
                ## looking for monj as a subword of moni
                if ( leni > lenj ) then
                    for k in Reversed( [leni..lenj+1] ) do
                        if moni{[(k+lenj-1)..k]} = monj then
                            Info( InfoIBNP, 3, "(1) [i,j,k]=", [i,j,k],
                             " adding ", moni[k-lenj], " to ", nonMult[j] );
                            Add( nonMult[j], moni[k-lenj] );
                        fi;
                    od;
                fi;
                ## looking for moni as a subword of monj
                if ( lenj > leni ) then
                    for k in Reversed( [lenj..leni+1] ) do
                        if monj{[(k+leni-1)..k]} = moni then
                            Info( InfoIBNP, 3, "(2) [i,j,k]=", [i,j,k],
                             " adding ", monj[k-leni], " to ", nonMult[i] );
                            Add( nonMult[i], monj[k-leni] );
                        fi;
                    od;
                fi;
            fi;
            m := Minimum( leni-1, lenj-1 );
            ## looking for overlap RHS[i] = LHS[j]
            for k in [1..m] do
                if ( moni{[(leni-k+1)..leni]} = monj{[1..k]} ) then
                        Info( InfoIBNP, 3, "(3) [i,j,k]=", [i,j,k],
                            " adding ", moni[leni-k], " to ", nonMult[j] );
                        Add( nonMult[j], moni[leni-k] );
                fi;
            od;
            ## looking for overlap RHS[j] = LHS[i]
            for k in [1..m] do
                if ( monj{[(lenj-k+1)..lenj]} = moni{[1..k]} ) then
                        Info( InfoIBNP, 3, "(4) [i,j,k]=", [i,j,k],
                            " adding ", monj[lenj-k], " to ", nonMult[i] );
                        Add( nonMult[i], monj[lenj-k] );
                fi;
            od;
        od;
    od;
    for i in [1..nmons] do
        rightMult[i] := [1..ngenA];
        leftMult[i] := Difference( [1..ngenA], nonMult[i] );
    od;
    return [ leftMult, rightMult ];
end );

#############################################################################
##
#M  StrongLeftOverlapDivision( <alg> <mons> <ord> )
##
InstallMethod( StrongLeftOverlapDivision,
    "generic method for list of monomials", true,
    [ IsAlgebra, IsList, IsNoncommutativeMonomialOrdering ], 0,
function( A, mons, ord )

    local mvars, genA, ngenA, lvars, rvars, nvars, nmons, 
          i, ui, j, uj, lenj, found, k;

    mvars := LeftOverlapDivision( A, mons, ord );

    ## Disjoint right cones: ensure that at least one variable in every
    ## monomial u_j is right non-multiplicative for every monomial u_i.
    Info( InfoIBNP, 2, "checking disjoint cones condition" );
    genA := GeneratorsOfAlgebra( A );
    if not ( genA[1] = One(A) ) then 
        Error( "expecting genA[1] = One(A)" );
    fi;
    genA := genA{ [2..Length(genA)] };
    ngenA := Length( genA );
    lvars := ShallowCopy( mvars[1] );
    rvars := ShallowCopy( mvars[2] );
    nvars := List( rvars, L -> Difference( [1..ngenA], L ) );
    nmons := Length( mons );
    for i in [1..nmons] do
        ui := mons[i];
        for j in Reversed( [1..nmons] ) do
            uj := mons[j];
            lenj := Length( uj );
            found := false;
            k := 1;
            while ( k <= lenj ) do
                if ( uj[k] in nvars[i] ) then 
                    found := true;
                    k := lenj + 1;
                else
                    k := k+1;
                fi;
            od;
            if not found then
                Info( InfoIBNP, 3, "adding ", uj[1], " when j = ", j, 
                                   " to nvars[i] with i = ", i );
                Add( nvars[i], uj[1] );
            fi;
        od;
    od;
    rvars := List( nvars, L -> Difference( [1..ngenA], L ) );
    return [ lvars, rvars ];
end );

#############################################################################
##
#M  StrongRightOverlapDivision( <alg> <mons> <ord> )
##
InstallMethod( StrongRightOverlapDivision,
    "generic method for list of monomials", true,
    [ IsAlgebra, IsList, IsNoncommutativeMonomialOrdering ], 0,
function( A, mons, ord )

    local mvars, genA, ngenA, lvars, rvars, nvars, nmons, 
          i, ui, leni, j, uj, found, k;

    mvars := RightOverlapDivision( A, mons, ord );

    ## Disjoint left cones: ensure that at least one variable in every
    ## monomial u_i is right non-multiplicative for every monomial u_j.
    genA := GeneratorsOfAlgebra( A );
    if not ( genA[1] = One(A) ) then 
        Error( "expecting genA[1] = One(A)" );
    fi;
    genA := genA{ [2..Length(genA)] };
    ngenA := Length( genA );
    lvars := ShallowCopy( mvars[1] );
    rvars := ShallowCopy( mvars[2] );
    nvars := List( lvars, L -> Difference( [1..ngenA], L ) );
    nmons := Length( mons );
    for j in [1..nmons] do
        uj := mons[j];
        for i in Reversed( [1..nmons] ) do
            ui := mons[i];
            leni := Length( ui );
            found := false;
            k := 1;
            while ( k <= leni ) do
                if ( ui[k] in nvars[j] ) then 
                    found := true;
                    k := leni + 1;
                else
                    k := k+1;
                fi;
            od;
            if not found then
                Add( nvars[j], ui[leni] );
            fi;
        od;
    od;
    lvars := List( nvars, L -> Difference( [1..ngenA], L ) );
    return [ lvars, rvars ];
end );

#############################################################################
##
#M  DivisionRecordNP( <alg> <polys> <ord> )
##
InstallMethod( DivisionRecordNP, "generic method for list of monomials",
    true, [ IsAlgebra, IsList, IsNoncommutativeMonomialOrdering ], 0,
function( A, polys, ord )

    ## Overview: returns local overlap-based multiplicative variables
    ## Detail: this function implements various algorithms
    ## described in the thesis "Noncommutative Involutive Bases"
    ## for finding left and right multiplicative variable 
    ## for a set of noncommutative polynomials

    local  genA, ngens, npolys, p, Lp, mons, mvars, drec, ok;

    genA := GeneratorsOfAlgebra( A );
    if not ( genA[1] = One(A) ) then 
        Error( "expecting genA[1] = One(A)" );
    fi;
    genA := genA{ [2..Length(genA)] };
    ngens := Length( genA );
    if( polys = [ ] ) then 
        return [ ];
    fi;
    npolys := Length( polys );
    ## set up arrays
    mons := LMonsNP( polys ); 
    Info( InfoIBNP, 3, "mons = ", mons );
    if ( NoncommutativeDivision = "Left" ) then 
        mvars := LeftDivision( A, mons, ord );
    elif ( NoncommutativeDivision = "Right" ) then
        mvars := RightDivision( A, mons, ord );
    elif ( NoncommutativeDivision = "LeftOverlap" ) then
        mvars := LeftOverlapDivision( A, mons, ord );
    elif ( NoncommutativeDivision = "RightOverlap" ) then
        mvars := RightOverlapDivision( A, mons, ord );
    elif ( NoncommutativeDivision = "StrongLeftOverlap" ) then
        mvars := StrongLeftOverlapDivision( A, mons, ord );
    elif ( NoncommutativeDivision = "StrongRightOverlap" ) then
        mvars := StrongRightOverlapDivision( A, mons, ord );
    else
        Error( "invalid NoncommutativeDivision" );
    fi;
    drec := rec( div := NoncommutativeDivision,
                 mvars := mvars, polys := polys );
    ok := IsDivisionRecord( drec );
    return drec;
end );

#############################################################################
##
#M  IPolyReduceNP( <alg> <poly> <drec> <ord> )
##
InstallMethod( IPolyReduceNP, 
    "generic method for a poly, record with fields [polys, mult vars]", true,
    [ IsAlgebra, IsObject, IsRecord, IsNoncommutativeMonomialOrdering ], 0,
function( A, pol, drec, ord )
## Overview: Reduces 2nd arg w.r.t. 3rd arg (polys and vars)
##
## Detail: drec is a record containing a list 'polys' of polynomials
## and their multiplicative variables 'vars'.
## Given a polynomial _pol_, this function involutively
## reduces the polynomial with respect to the given polys
## with associated left and right multiplicative variables vars.

    return CombinedIPolyReduceNP( A, pol, drec, ord, false );
end );

#############################################################################
##
#M  LoggedIPolyReduceNP( <alg> <poly> <drec> <ord> )
##
InstallMethod( LoggedIPolyReduceNP, 
    "generic method for a poly, record with fields [polys, mult vars]", true,
    [ IsAlgebra, IsObject, IsRecord, IsNoncommutativeMonomialOrdering ], 0,
function( A, pol, drec, ord )
##
## Overview: Reduces 2nd arg w.r.t. 3rd arg (polys and vars)
## just as in IPolyReduceNP, but returns a record contsaining the reduced
## polynomial and also logged information showing how the result is 
## obtained from the original polynomial.
##
    return CombinedIPolyReduceNP( A, pol, drec, ord, true );
end );

#############################################################################
##
#M  CombinedIPolyReduceNP( <alg> <poly> <drec> <ord> <logging> )
##
InstallMethod( CombinedIPolyReduceNP, 
    "generic method for a poly, record with fields [polys, mult vars]", true,
    [ IsAlgebra, IsObject, IsRecord, 
      IsNoncommutativeMonomialOrdering, IsBool ], 0,
function( A, obj, drec, ord, logging )

    local  polys, vars, pol, pl, i, numpolys, cutoffL, cutoffR, value,
           lenOrig, lenSub, poli, front, back, diff, factors, mon, moni,
           varL, varR, facL, facR, monj, coeff, coeffi, quot, M, appears,
           term, found, reduced, f, facf, lenf, lenL, lenR, polL, polR, logs;

    if not IsDivisionRecord( drec ) then
        Error( "third argument should be an overlap record" );
    fi;
    ## determine whether obj is in NP or GP format
    if IsList( obj ) then 
        pol := obj;
    else
        pol := GP2NP( obj );
        if ( pol = fail ) then
            Error( "obj should be a polynomial in NP or GP format" );
        fi;
    fi;
    Info( InfoIBNP, 3, "in IPolyReduceNP: pol = ", pol, 
                       ",  logging = ", logging );
    pl := InfoLevel( InfoIBNP );
    polys := drec.polys;
    numpolys := Length( polys );
    logs := List( [1..numpolys], i -> [  ] );
    vars := drec.mvars;
    front := [ [ ], [ ] ];
    back := pol;
    ## we now recursively reduce every term in the polynomial
    ## until no more reductions are possible
    while ( back[1] <> [ ] ) do 
        Info( InfoIBNP, 3, "first loop: ",
                  "front = ", NP2GP( front, A ),
                  ", back = ", NP2GP( back, A ) );
        reduced := true;
        while reduced and ( back <> [ [], [] ] ) do
            Info( InfoIBNP, 3, "second loop: back = ", back );
            reduced := false;
            mon := back[1][1];
            coeff := back[2][1];
            i := 0;
            while ( i < numpolys ) and ( not reduced ) do  
                Info( InfoIBNP, 3, "third loop: back = ", back );
                ## for each polynomial in the list
                i := i+1;
                poli := polys[i];
                moni := poli[1][1];  ## pick a test monomial                                                                 
                factors := DivNM( mon, moni );
                lenf := Length(factors);
                if ( lenf > 0 ) then ## moni divides mon
                    M := 0;  ## assume that the first conventional division 
                             ## is not an involutive division
                             ## while there are conventional divisions left 
                             ## to look at and while none of these have yet
                             ## proved to be involutive divisions
                    found := false;
                    f := 0;
                    while ( not found ) and ( f < lenf ) and ( M = 0 ) do
                        ## assume that this conventional division 
                        ## is an involutive division
                        f := f+1;
                        facf := factors[f];
                        M := 1;
                        ## extract the ith left & right mult variables
                        varL := vars[1][i];
                        varR := vars[2][i];
                        ## Extract the left and right factors
                        facL := facf[1];
                        facR := facf[2];
                        ## test all variables in facL for left
                        ## multiplicability in the ith monomial
                        lenL := Length( facL );
                        ## decide whether one/all variables in facL 
                        ## are left multiplicative
                        ## right-most variable only
                        if ( lenL > 0 ) then
                            monj := facL[ lenL ];
                            appears := monj in varL;
                            ## if the generator doesn't appear this 
                            ## is not an involutive division
                            if ( not appears ) then 
                                M := 0;
                            else
                                Info( InfoIBNP, 3, monj, " not in ", varL );
                            fi;
                        fi;
                        ## test all variables in facR for right
                        ## multiplicability in the ith monomial
                        if ( M = 1 ) then
                            lenR := Length( facR );
                            ## decide whether one/all variables in facR
                            ## are left multiplicative
                            ## Left-most var only
                            if ( lenR > 0 ) then
                                monj := facR[1];
                                appears := monj in varR;
                                ## if the generator doesn't appear
                                ## this is not an involutive division
                                if ( not appears ) then
                                    M := 0;
                                else
                                    Info( InfoIBNP, 3, monj," not in ", varR );
                                fi;
                            fi;
                        fi;
                        ## if this conventional division wasn't involutive, 
                        ## look at the next division
                        if ( M = 1 ) then
                            found := true;
                        fi;
                    od;
                       
                    ## if an involutive division was found
                    if found then
                        if ( pl > 2 ) then
                            Print( "found: ", mon, " = ", facf[1], ",",
                                              moni, ",", facf[2], "\n" );
                        fi;
                        ## indicate a reduction has been carried out 
                        ## to exit the loop
                        ## pick the divisor's leading coefficient
                        coeffi := poli[2][1];
                        if ( facL <> [ ] ) then 
                            diff := MulNP( [ [facL], [1] ], poli ); 
                        else 
                            diff := poli;
                        fi;
                        if ( facR <> [ ] ) then
                            diff := MulNP( diff, [ [facR], [1] ] );
                        fi;
                        quot := - coeff/coeffi;
                        diff := AddNP( back, diff, 1, quot );
                        Info( InfoIBNP, 2, "front = ", NP2GP( front, A ) );
                        Info( InfoIBNP, 2, " diff = ", NP2GP( diff, A ) );
                        if logging then 
                            Add( logs[i], [ - quot, facf[1], facf[2] ] );
                        fi;
                        reduced := true;
                        ## in the next iteration we will be 
                        ## reducing the new polynomial diff
                        back := CleanNP( diff );
                        Info( InfoIBNP, 3, "cleaned back: ", back );
                    fi;
                fi;
            od;
        od;
        ## no reduction of the lead term, so add it to front
        if ( back <> [ [ ], [ ] ] ) then
            term := [ [ back[1][1] ], [ back[2][1] ] ];
            if ( front = [ [ ], [ ] ] ) then 
                front := term;
            else
                front := AddNP( front, term, 1, 1 ); 
            fi; 
            back := AddNP( back, term, 1, -1 );
            Info( InfoIBNP, 3, "front = ", front );
            Info( InfoIBNP, 3, " back = ", back );
        fi;
    od;
    if not logging then
        return front;  ## return the reduced and simplified polynomial
    else
        return rec( result := front, logs := logs, polys := polys );
    fi;
end );

#############################################################################
##
#M  VerifyLoggedIRecordNP( <poly> <logs> )
##
InstallMethod( VerifyLoggedRecordNP, 
    "generic method for an NP-poly and a logged record", true,
    [ IsList, IsRecord ], 0,
function( pol, logrec )
##
## Overview: Verifies that logrec.logs and logrec.result can be combined
## to recaculate the original pol
##
    local logs, polys, result, r, i, poli, j, Lij, p;

    logs := logrec.logs;
    polys := logrec.polys;
    result := logrec.result;
    r := ShallowCopy( result );
    for i in [1..Length(logs)] do
        poli := polys[i];
        for j in [1..Length( logs[i] )] do
            Lij := logs[i][j];
            if ( Lij[2] <> [ ] ) then
                p := MulNP( [ [ Lij[2] ], [1] ], poli );
            else
                p := poli;
            fi;
            if ( Lij[3] <> [ ] ) then
                p := MulNP( p, [ [ Lij[3] ], [1] ] );
            fi;
            r := AddNP( r, [ p[1], Lij[1]*p[2] ], 1, 1 );
        od;
    od;
    return ( r = pol );
end );

#############################################################################
##
#M  IAutoreduceNP( <alg> <polys> <ord> )
##
InstallMethod( IAutoreduceNP, "generic method for list of polys",
    true, [ IsAlgebra, IsList, IsNoncommutativeMonomialOrdering ], 0,
function( A, polys, ord )

    ## Overview: Autoreduces an FAlgList recursively 
    ## until no more reductions are possible 
    ## Detail: This function involutively reduces each member of an FAlgList 
    ## w.r.t. all the other members of the list, removing the polynomial 
    ## from the list if it is involutively reduced to 0. This process is
    ## iterated until no more such reductions are possible. 

    local d, twod, pl, oldPoly, newPoly, nrec, new, old, oldCopy, drec,
          vars, pos, pushPos, len, gcd;

    len := Length( polys );
    ## twod := 2^d;
    pl := InfoLevel( InfoIBNP );
    if( len < 2 ) then 
        ## the input basis is empty or consists of a single polynomial
        return polys;
    fi;

    ## start by reducing the final element (working backwards means
    ## that less work has to be done calculating multiplicative variables)
    pos := len;
    ## make a copy of the input basis for traversal
    old := StructuralCopy( polys );
    while( pos > 0 ) do   ## for each polynomial in old
        ## extract the pos-th element of the basis
        oldPoly := old[pos];
        Info( InfoIBNP, 3, "reducing polynomial polys(", pos, 
            "\nlooking at element ", oldPoly, " of basis" );
        ## construct basis without 'poly'
        oldCopy := StructuralCopy( old );  ## make a copy of old
        len := Length( oldCopy );
        ## calculate Multiplicative Variables if using a local division
        drec := DivisionRecordNP( A, oldCopy, ord );
        vars := drec.mvars;
        ## vars := fMonPairListRemoveNumber( pos, vars );
        vars[1] := Concatenation( vars[1]{[1..pos-1]}, 
                                  vars[1]{[pos+1..len]} ); 
        vars[2] := Concatenation( vars[2]{[1..pos-1]}, 
                                  vars[2]{[pos+1..len]} ); 

        new := Concatenation( old{[1..pos-1]}, old{[pos+1..len]} );
        Sort( new, GtNPoly );
        nrec := DivisionRecord( A, new, ord );
        old := StructuralCopy( oldCopy );     ## restore old
        ## to recap, old is now unchanged whilst new holds all
        ## the elements of old except oldPoly.
        ## involutively reduce the old polynomial w.r.t. the truncated list
        newPoly := IPolyReduceNP( A, oldPoly, nrec, ord );

        ## if the polynomial did not reduce to 0
        if not ( newPoly = [ [ ], [ ] ] ) then 
            ## divide the polynomial through by its GCD
            gcd := Gcd( newPoly[2] );
            newPoly := [ newPoly[1], newPoly[2]/gcd ];
            if( pl > 2 ) then 
                Print( "reduced pol to " ); 
                PrintNP( newPoly );
                Print( "\n" );
            fi;
            ## check for trivial ideal
            if ( newPoly = [ ] ) then 
                return [ [ ], [ ] ];
            fi;
            if IsNegInt( newPoly[2][1] ) then 
                newPoly[2] := -newPoly[2];
            fi;
            ## if the old polynomial is equal to the new polynomial
            ## (i.e. no reduction took place)
            if ( oldPoly = newPoly ) then 
                ## we may proceed to look at the next polynomial 
                pos := pos - 1;
            else 
                ## otherwise some reduction took place so start again
                ## if we are restricting prolongations based on degree,...
                ## add the new polynomial onto the list
                ## push the new polynomial onto the end of the list
                old := Concatenation( new, [ newPoly ] );
                Info( InfoIBNP, 3, "adding reduced poly: ", 
                      oldPoly, " --> ", newPoly );
                Sort( old, GtNPoly );
                ## return to the end of the list minus one
                ## (we know the last element is irreducible)
                pos := Length( old ) - 1;
            fi;
        else    
            ## the polynomial reduced to zero
            ## remove the polynomial from the list
            Info( InfoIBNP, 2, "poly reduced to zero: ", oldPoly );
            old := StructuralCopy( new );
            ## continue to look at the next element
            pos := pos - 1;
            if ( pl > 2 ) then 
                Print( "Reduced p to 0\n");
            fi;
        fi;
    od;
    Sort( old, GtNPoly );
    ##  return the fully autoreduced basis
    if ( old = polys ) then ## no change
        return true;
    else
        return old;
    fi;
end );

#############################################################################
##
#M  InvolutiveBasisNP( <alg> <polys> )
##
InstallMethod( InvolutiveBasisNP, 
    "generic method for algebra + list of polys", true,
    [ IsAlgebra, IsList, IsNoncommutativeMonomialOrdering ], 0,
function( A, polys, ord )

    ##  Implements Algorithm 12 for computing locally involutive bases. 

    local  pl, gens, ngens, all, zero, mrec, mvars, nvars, basis0, basis,
           nbasis, done, prolong, u, lenu, v, i, j, k, npro, found;

    pl := InfoLevel( InfoIBNP );
    gens := GeneratorsOfAlgebra( A );
    if not ( gens[1] = One(A) ) then 
        Error( "expecting gens[1] = One(A)" );
    fi;
    gens := gens{ [2..Length(gens)] };
    ngens := Length( gens );
    all := [ 1..ngens ];
    zero := [ [ ], [ ] ];
    Info( InfoIBNP, 2, "Computing an Involutive Basis...");
    basis := List( polys, p -> CleanNP(p) );
    done := false;
    Sort( basis, GtNPoly );
    while ( not done ) do
        if ( pl >= 2 ) then
            Print( "restarting with basis:\n" );
            PrintNPList( basis );
        fi;
        basis0 := ShallowCopy( basis );
        basis := IAutoreduceNP( A, basis0, ord );
        if ( basis = true ) then 
            basis := basis0;
        fi;
        nbasis := Length( basis );
        mrec := DivisionRecordNP( A, basis, ord );
        Info( InfoIBNP, 2, "mrec = ", mrec );
        mvars := mrec.mvars;
        nvars := [ List( mvars[1], v -> Difference( all, v ) ), 
                   List( mvars[2], v -> Difference( all, v ) ) ];
        Info( InfoIBNP, 2, "nvars = ", nvars );
        ## construct the prolongations
        prolong := [ ];
        for i in [1..nbasis] do
            ## left prolongations
            lenu := Length( basis[i][1] );
            for j in nvars[1][i] do
                u := StructuralCopy( basis[i] );
                for k in [1..lenu] do
                    u[1][k] := Concatenation( [j], u[1][k] );
                od;
                Add( prolong, CleanNP( u ) );
                Info( InfoIBNP, 2, "left prolongation: ", u );
            od;
            ## right prolongations
            for j in nvars[2][i] do
                u := StructuralCopy( basis[i] );
                for k in [1..lenu] do
                    Add( u[1][k], j );
                od;
                Add( prolong, CleanNP( u ) );
                Info( InfoIBNP, 2, "right prolongation: ", u );
            od;
        od;
        Sort( prolong, LtNPoly );
        if ( pl >= 2 ) then
            Print( "prolong = \n" );
            PrintNPList( prolong );
        fi;
        npro := Length( prolong ); 
        found := false;
        i := 0;
        while ( not found ) and ( i < npro ) do 
            i := i+1;
            u := prolong[i];
            v := IPolyReduceNP( A, u, mrec, ord );
            if ( v <> [ [ ], [ ] ] ) then 
                found := true; 
                if IsNegInt( v[2][1] ) then 
                    v[2] := -v[2];
                fi;
                Add( basis, v );
                if ( pl > 0 ) and 
                   ( Length(basis) > InvolutiveAbortLimit ) then
                      return fail;
                fi;
                Info( InfoIBNP, 1, "adding ", u, " -> ", v );
            fi;
        od;
        if not found then
            done := true;
        fi;
        basis0 := IAutoreduceNP( A, basis, ord );
        if not ( basis0 = true ) then
            basis := basis0;
            Sort( basis, GtNPoly );
        fi;
    od;
    return DivisionRecordNP( A, basis, ord );
end );

#############################################################################
##
#E  involutive-np.gi . . . . . . . . . . . . . . . . . . . . . . .  ends here
## 

[ Dauer der Verarbeitung: 0.44 Sekunden  ]