@@ -627,32 +627,52 @@ BindGlobal("nfmPolyEvalFromSpan", function(span,pol)
627627 return resu;
628628end );
629629
630- # TODO: recognise cyclic matrices
631- # Primary Decomposition using a modified version of Allan Steel's algorithm
632- # Standalone version
633- # Returns matrix B such that B*A*B^-1 is in primary decomposition form
634- # along with dimensions of primary subspaces
635- InstallGlobalFunction(PrimaryDecomp, function (A )
636- local rank,F,n,m,f,w,p,j,i,wspan,gens,facs,L_i,qi,k,v,
637- COB,pot,gs,f2,dims,toAdd,combined,dim;
630+
631+ BindGlobal(" factoriseByKnownFactors" , function (kFacs,pol )
632+ local fac,factup,i,resfacs,count,newpol,oldpol;
633+ resfacs := [] ;
634+ oldpol := pol;
635+ for factup in kFacs do
636+ fac := factup[ 1 ] ;
637+ count := 0 ;
638+ for i in [ 1 .. factup[ 2 ]] do
639+ newpol := Quotient(oldpol, fac);
640+ if newpol = fail then
641+ break ;
642+ fi ;
643+ count := count + 1 ;
644+ oldpol := newpol;
645+ od ;
646+ if not count = 0 then
647+ Add(resfacs, [ fac, count] );
648+ fi ;
649+ od ;
650+ return resfacs;
651+ end );
652+
653+ # TODO: if size of minpolfacs is one we can return identity
654+ # Primary Decomposition using a modified version of Allan Steel's algorithm for use in the Jordan normal form function
655+ # Takes matrix along with its minimal polynomial and its factorised version as input
656+ # Returns matrix B such that B*A*B^-1 is in primary decomp. form, dimensions of primary subspaces
657+ # and factors of minimal polynomial in correct order
658+ BindGlobal(" nfmPrimaryDecompositionforJNF" , function (A, minpol, minpolfacs )
659+ local rank,F,n,m,f,w,p,j,i,wspan,gens,facs,L_i,qi,k,v,
660+ COB,pot,gs,f2,toAdd,pos,dims,dim;
638661 rank := 0 ;
639662 n := NrRows(A);
640663 F := DefaultFieldOfMatrix(A);
641664 v := nfmGenerateRandomVector(F,n);
642- A := Matrix(F,A);
643- if IsZero(A) then
644- return OneMutable(A);
645- fi ;
646- gens := [] ; # Li_s as in Steel paper will go in here
665+ gens := [] ; # Li_s as in Steel paper will go in here (but without separate U)
647666 gs := [] ; # distinct factors of minimal polynomial
667+ dims := [] ;
648668 while not rank = n do
649669 m := UnivariatePolynomial(F,SpinMatVector(A,v)[ 3 ] );
650670 p := One(PolynomialRing(F));
651671 for i in [ 1 .. Size(gens)] do
652672 L_i := gens[ i] ;
653673 if not IsOne(Gcd(m,gs[ i] )) then
654674 f := m;
655- pot := 0 ;
675+ pot := 0 ;
656676 for j in [ 1 .. n] do
657677 f2 := Quotient(f,gs[ i] );
658678 if f2 = fail then
@@ -663,8 +683,8 @@ InstallGlobalFunction(PrimaryDecomp, function(A)
663683 od ;
664684 w := PolynomialToMatVec(A,f,v);
665685 p := p * gs[ i] ^ pot;
666- # minimal polynomial of w has degree smaller than or equal to n - degree(f)
667- wspan := nfmSpinUntil(w,A,n - Degree(f));
686+ # minimal polynomial of w has degree smaller than or equal to minpol/f
687+ wspan := nfmSpinUntil(w,A,Degree(minpol) - Degree(f));
668688 toAdd := EcheloniseMat(Concatenation(wspan,gens[ i] ));
669689 if not IsMatrix(toAdd) then
670690 toAdd := [ toAdd] ; # Convert vector to 1-row matrix
@@ -676,8 +696,9 @@ InstallGlobalFunction(PrimaryDecomp, function(A)
676696 v := PolynomialToMatVec(A,p,v);
677697 m := Quotient(m,p);
678698 if not IsOne(m) then
679- facs := Factors(m);
680- facs := Collected(facs);
699+ # TODO: make this work
700+ # facs := factoriseByKnownFactors(minpolfacs,m);
701+ facs := Collected(Factors(m));
681702 for i in [ 1 .. Size(facs)] do
682703 qi := (facs[ i][ 1 ] )^ (facs[ i][ 2 ] );
683704 w := PolynomialToMatVec(A,Quotient(m,qi),v);
@@ -686,7 +707,7 @@ InstallGlobalFunction(PrimaryDecomp, function(A)
686707 Add(gs, facs[ i][ 1 ] );
687708 od ;
688709 fi ;
689- # alles in eine matrix
710+ # put everything into a single matrix
690711 COB := ZeroMatrix(F,n,n);
691712 k := 0 ;
692713 for i in [ 1 .. Size(gens)] do
@@ -701,70 +722,70 @@ InstallGlobalFunction(PrimaryDecomp, function(A)
701722 v := nfmFindVectorNotInSubspaceNC(COB);
702723 fi ;
703724 od ;
704- # sorted blocks and count dims
705725 COB := ZeroMatrix(F,n,n);
706- combined := [] ;
707- for i in [ 1 .. Size(gs)] do
708- Add(combined, [ gens[ i] ,gs[ i]] );
709- od ;
710- Sort(combined, { v,w} -> v[ 2 ] < w[ 2 ] );
726+ # sort primary subspaces back into order and collect dims
711727 k := 0 ;
712- dims := [] ;
713- for i in [ 1 .. Size (gs) ] do
714- L_i := combined [ i ][ 1 ] ;
715- dim := NrRows(L_i);
728+ for i in [ 1 .. Size(gens) ] do
729+ pos := Position (gs, minpolfacs [ i ][ 1 ] );
730+ L_i := gens [ pos ] ;
731+ dim := NrRows(L_i); # ?
716732 Add(dims, dim);
717733 CopySubMatrix(L_i, COB, [ 1 .. dim] , [ k+ 1 .. k+ dim] ,[ 1 .. n] , [ 1 .. n] );
718734 k := k + dim;
719735 od ;
720736 return [ COB, dims] ;
721737end );
722738
723- BindGlobal(" factoriseByKnownFactors" , function (kFacs,pol )
724- local fac,factup,i,resfacs,count,newpol,oldpol;
725- resfacs := [] ;
726- oldpol := pol;
727- for factup in kFacs do
728- fac := factup[ 1 ] ;
729- count := 0 ;
730- for i in [ 1 .. factup[ 2 ]] do
731- newpol := Quotient(oldpol, fac);
732- if newpol = fail then
733- break ;
734- fi ;
735- count := count + 1 ;
736- oldpol := newpol;
739+ # Primary Decomposition for cyclic matrices
740+ # Jordan normal form will call this function if a cyclic matrix is detected
741+ BindGlobal(" nfmPrimaryDecompositionforJNFCyclic" , function (A, minpol, minpolfacs )
742+ local vspan,n,w,mf,wspan,qi,k,COB,dims;
743+ n := NrRows(A);
744+ vspan := nfmFindCyclicVectorNC(A);
745+ dims := [] ;
746+ COB := ZeroMutable(A);
747+ k := 0 ;
748+ for mf in minpolfacs do
749+ qi := (mf[ 1 ] )^ (mf[ 2 ] );
750+ w := nfmPolyEvalFromSpan(vspan,Quotient(minpol,qi));
751+ wspan := nfmSpinUntil(w,A,Degree(mf[ 1 ] )* mf[ 2 ] );
752+ CopySubMatrix(wspan, COB, [ 1 .. NrRows(wspan)] , [ k+ 1 .. k+ NrRows(wspan)] , [ 1 .. n] , [ 1 .. n] );
753+ Add(dims, NrRows(wspan));
754+ k := k + NrRows(wspan);
737755 od ;
738- if not count = 0 then
739- Add(resfacs, [ fac, count] );
740- fi ;
741- od ;
742- return resfacs;
756+ return [ COB, dims] ;
743757end );
744758
745- # TODO: if size of minpolfacs is one we can return identity
746- # Primary Decomposition using a modified version of Allan Steel's algorithm for use in the Jordan normal form function
747- # Takes matrix along with its minimal polynomial and its factorised version as input
748- # Returns matrix B such that B*A*B^-1 is in primary decomp. form, dimensions of primary subspaces
749- # and factors of minimal polynomial in correct order
750- BindGlobal( " nfmPrimaryDecompositionforJNF " , function (A, minpol, minpolfacs )
751- local rank,F,n,m,f,w,p,j,i,wspan,gens,facs,L_i,qi,k,v,
752- COB,pot,gs,f2,toAdd,pos,dims, dim;
759+ # TODO: recognise cyclic matrices
760+ # Primary Decomposition using a modified version of Allan Steel's algorithm
761+ # Standalone version
762+ # Returns matrix B such that B*A*B^-1 is in primary decomposition form
763+ # along with dimensions of primary subspaces
764+ InstallGlobalFunction(PrimaryDecomp , function (A )
765+ local rank,F,n,m,f,w,p,j,i,wspan,gens,facs,L_i,qi,k,v,
766+ COB,pot,gs,f2,dims, toAdd,combined, dim,minpol ;
753767 rank := 0 ;
754768 n := NrRows(A);
755769 F := DefaultFieldOfMatrix(A);
756770 v := nfmGenerateRandomVector(F,n);
757- gens := [] ; # Li_s as in Steel paper will go in here (but without separate U)
771+ A := Matrix(F,A);
772+ minpol := MinimalPolynomial(F,A);
773+ if Degree(minpol) = n then
774+ return nfmPrimaryDecompositionforJNFCyclic(A,minpol,Collected(Factors(minpol)));
775+ fi ;
776+ if IsZero(A) then
777+ return IdentityMat(n,F);
778+ fi ;
779+ gens := [] ; # Li_s as in Steel paper will go in here
758780 gs := [] ; # distinct factors of minimal polynomial
759- dims := [] ;
760781 while not rank = n do
761782 m := UnivariatePolynomial(F,SpinMatVector(A,v)[ 3 ] );
762783 p := One(PolynomialRing(F));
763784 for i in [ 1 .. Size(gens)] do
764785 L_i := gens[ i] ;
765786 if not IsOne(Gcd(m,gs[ i] )) then
766787 f := m;
767- pot := 0 ;
788+ pot := 0 ;
768789 for j in [ 1 .. n] do
769790 f2 := Quotient(f,gs[ i] );
770791 if f2 = fail then
@@ -775,8 +796,8 @@ BindGlobal("nfmPrimaryDecompositionforJNF", function(A, minpol, minpolfacs)
775796 od ;
776797 w := PolynomialToMatVec(A,f,v);
777798 p := p * gs[ i] ^ pot;
778- # minimal polynomial of w has degree smaller than or equal to minpol/f
779- wspan := nfmSpinUntil(w,A,Degree(minpol) - Degree(f));
799+ # minimal polynomial of w has degree smaller than or equal to n - degree(f)
800+ wspan := nfmSpinUntil(w,A,n - Degree(f));
780801 toAdd := EcheloniseMat(Concatenation(wspan,gens[ i] ));
781802 if not IsMatrix(toAdd) then
782803 toAdd := [ toAdd] ; # Convert vector to 1-row matrix
@@ -788,9 +809,8 @@ BindGlobal("nfmPrimaryDecompositionforJNF", function(A, minpol, minpolfacs)
788809 v := PolynomialToMatVec(A,p,v);
789810 m := Quotient(m,p);
790811 if not IsOne(m) then
791- # TODO: make this work
792- # facs := factoriseByKnownFactors(minpolfacs,m);
793- facs := Collected(Factors(m));
812+ facs := Factors(m);
813+ facs := Collected(facs);
794814 for i in [ 1 .. Size(facs)] do
795815 qi := (facs[ i][ 1 ] )^ (facs[ i][ 2 ] );
796816 w := PolynomialToMatVec(A,Quotient(m,qi),v);
@@ -799,7 +819,7 @@ BindGlobal("nfmPrimaryDecompositionforJNF", function(A, minpol, minpolfacs)
799819 Add(gs, facs[ i][ 1 ] );
800820 od ;
801821 fi ;
802- # put everything into a single matrix
822+ # alles in eine matrix
803823 COB := ZeroMatrix(F,n,n);
804824 k := 0 ;
805825 for i in [ 1 .. Size(gens)] do
@@ -814,40 +834,25 @@ BindGlobal("nfmPrimaryDecompositionforJNF", function(A, minpol, minpolfacs)
814834 v := nfmFindVectorNotInSubspaceNC(COB);
815835 fi ;
816836 od ;
837+ # sorted blocks and count dims
817838 COB := ZeroMatrix(F,n,n);
818- # sort primary subspaces back into order and collect dims
839+ combined := [] ;
840+ for i in [ 1 .. Size(gs)] do
841+ Add(combined, [ gens[ i] ,gs[ i]] );
842+ od ;
843+ Sort(combined, function (v,w ) return v[ 2 ] < w[ 2 ] ; end );
819844 k := 0 ;
820- for i in [ 1 .. Size(gens) ] do
821- pos := Position(gs, minpolfacs [ i ][ 1 ] );
822- L_i := gens [ pos ] ;
823- dim := NrRows(L_i); # ?
845+ dims := [] ;
846+ for i in [ 1 .. Size(gs) ] do
847+ L_i := combined [ i ][ 1 ] ;
848+ dim := NrRows(L_i);
824849 Add(dims, dim);
825850 CopySubMatrix(L_i, COB, [ 1 .. dim] , [ k+ 1 .. k+ dim] ,[ 1 .. n] , [ 1 .. n] );
826851 k := k + dim;
827852 od ;
828853 return [ COB, dims] ;
829854end );
830855
831- # Primary Decomposition for cyclic matrices
832- # Jordan normal form will call this function if a cyclic matrix is detected
833- BindGlobal(" nfmPrimaryDecompositionforJNFCyclic" , function (A, minpol, minpolfacs )
834- local vspan,n,w,mf,wspan,qi,k,COB,dims;
835- n := NrRows(A);
836- vspan := nfmFindCyclicVectorNC(A);
837- dims := [] ;
838- COB := ZeroMutable(A);
839- k := 0 ;
840- for mf in minpolfacs do
841- qi := (mf[ 1 ] )^ (mf[ 2 ] );
842- w := nfmPolyEvalFromSpan(vspan,Quotient(minpol,qi));
843- wspan := nfmSpinUntil(w,A,Degree(mf[ 1 ] )* mf[ 2 ] );
844- CopySubMatrix(wspan, COB, [ 1 .. NrRows(wspan)] , [ k+ 1 .. k+ NrRows(wspan)] , [ 1 .. n] , [ 1 .. n] );
845- Add(dims, NrRows(wspan));
846- k := k + NrRows(wspan);
847- od ;
848- return [ COB, dims] ;
849- end );
850-
851856# Input: For matrix A with minimal polynomial p^m: m, vector v and p(A)
852857# Returns: v, length r of v, vp^(r-1)(A)
853858BindGlobal(" GetMinPolPowerWithVec" , function (m,v,Ainp )
0 commit comments