source: git/Singular/LIB/jacobson.lib @ 6ef8674

fieker-DuValspielwiese
Last change on this file since 6ef8674 was 66d68c, checked in by Hans Schoenemann <hannes@…>, 14 years ago
format git-svn-id: file:///usr/local/Singular/svn/trunk@13499 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100755
File size: 29.1 KB
Line 
1//////////////////////////////////////////////////////////////////////////////
2version="$Id$";
3category="System and Control Theory";
4info="
5LIBRARY: jacobson.lib     Algorithms for Smith and Jacobson Normal Form
6AUTHOR: Kristina Schindelar,     Kristina.Schindelar@math.rwth-aachen.de,
7@*           Viktor Levandovskyy,      levandov@math.rwth-aachen.de
8
9OVERVIEW:
10We work over a ring R, that is an Euclidean principal ideal domain.
11@* If R is commutative, we suppose R to be a polynomial ring in one variable.
12@* If R is non-commutative, we suppose R to have two variables, say x and d.
13@* We treat then the basering as the Ore localization of R
14@* with respect to the mult. closed set S = K[x] without 0.
15@* Thus, we treat basering as principal ideal ring with d a polynomial
16@* variable and x an invertible one.
17@* Note, that in computations no division by x will actually happen.
18@*
19@* Given a rectangular matrix M over R, one can compute unimodular (that is
20@* invertible) square matrices U and V, such that U*M*V=D is a diagonal matrix.
21@* Depending on the ring, the diagonal entries of D have certain properties.
22@*
23@* We call a square matrix D as before 'a weak Jacobson normal form of M'.
24@* It is known, that over the first rational Weyl algebra K(x)<d>, D can be further
25@* transformed into a diagonal matrix (1,1,...,1,f,0,..,0), where f is in K(x)<d>. We call
26@* such a form of D the strong Jacobson normal form. The existence of strong form
27@* in not guaranteed if one works with algebra, which is not rational Weyl algebra.
28
29
30REFERENCES:
31@* [1] N. Jacobson, 'The theory of rings', AMS, 1943.
32@* [2] Manuel Avelino Insua Hermo, 'Varias perspectives sobre las bases de Groebner :
33@* Forma normal de Smith, Algorithme de Berlekamp y algebras de Leibniz'.
34@* PhD thesis, Universidad de Santiago de Compostela, 2005.
35@* [3] V. Levandovskyy, K. Schindelar 'Computing Jacobson normal form using Groebner bases',
36@* to appear in Journal of Symbolic Computation, 2010.
37
38PROCEDURES:
39smith(M[,eng1,eng2]);  compute the Smith Normal Form of M over commutative ring
40jacobson(M[,eng]); compute a weak Jacobson Normal Form of M over non-commutative ring
41divideUnits(L);     create ones out of units in the output of smith or jacobson
42
43SEE ALSO: control_lib
44
45KEYWORDS: Jacobson form; Jacobson normal form; Smith form; Smith normal form; matrix diagonalization
46
47";
48
49LIB "poly.lib";
50LIB "involut.lib"; // involution
51LIB "dmodapp.lib"; // engine
52LIB "qhmoduli.lib"; // Min
53
54proc tstjacobson()
55{
56  /* tests all procs for consistency */
57  example divideUnits;
58  example smith;
59  example jacobson;
60}
61
62proc divideUnits(list L)
63"USAGE: divideUnits(L); list L
64RETURN: matrix or list of matrices
65ASSUME: L is an output of @code{smith} or a @code{jacobson} procedures, that is
66@* either L contains one rectangular matrix with elements only on the main diagonal
67@* or L consists of three matrices, where L[1] and L[3] are square invertible matrices
68@* while L[2] is a rectangular matrix with elements only on the main diagonal
69PURPOSE: divide out units from the diagonal and reflect this in transformation matrices
70EXAMPLE: example divideUnits; shows examples
71"
72{
73  // check assumptions
74  int s = size(L);
75  if ( (s!=1) && (s!=3) )
76  {
77    ERROR("The list has neither 1 nor 3 elements");
78  }
79  // check sizes of matrices
80
81  if (s==1)
82  {
83    list LL; LL[1] = L[1]; LL[2] = L[1];
84    L = LL;
85  }
86
87
88  // divide units out
89  matrix M = L[2];
90  int ncM = ncols(M);   int nrM = nrows(M);
91  //  matrix TM[nrM][nrM]; // m times m matrix
92  matrix TM = matrix(freemodule(nrM));
93  int i; int nsize = Min(intvec(nrM,ncM));
94  poly p; number n; intvec lexp;
95
96  for(i=1; i<=nsize; i++)
97  {
98    p = M[i,i];
99    lexp = leadexp(p);
100    //    TM[i,i] = 1;
101    // check: is p a unit?
102    if (p!=0)
103    {
104      if ( lexp == 0)
105      {
106        // hence p = n*1
107        n = leadcoef(p);
108        TM[i,i] = 1/n;
109      }
110    }
111  }
112  int ppl = printlevel-voice+2;
113  dbprint(ppl,"divideUnits: extra transformation matrix is: ");
114  dbprint(ppl, TM);
115  L[2] = TM*L[2];
116  if (s==3)
117  {
118    L[1] = TM*L[1];
119    return(L);
120  }
121  else
122  {
123    return(L[2]);
124  }
125}
126example
127{ "EXAMPLE:"; echo = 2;
128  ring R=(0,m,M,L1,L2,m1,m2,g), D, lp; // two pendula example
129  matrix P[3][4]=m1*L1*D^2,m2*L2*D^2,(M+m1+m2)*D^2,-1,
130  m1*L1^2*D^2-m1*L1*g,0,m1*L1*D^2,0,0,
131  m2*L2^2*D^2-m2*L2*g,m2*L2*D^2,0;
132  list s=smith(P,1);  // returns a list with 3 entries
133  print(s[2]); // a diagonal form, close to the Smith form
134  print(s[1]); // U, left transformation matrix
135  list t = divideUnits(s);
136  print(t[2]); // the Smith form of the matrix P
137  print(t[1]); // U', modified left transformation matrix
138}
139
140proc smith(matrix MA, list #)
141"USAGE: smith(M[, eng1, eng2]);  M matrix, eng1 and eng2 are optional integers
142RETURN: matrix or list of matrices, depending on arguments
143ASSUME: Basering is a commutative polynomial ring in one variable
144PURPOSE: compute the Smith Normal Form of M with (optionally) transformation matrices
145THEORY: Groebner bases are used for the Smith form like in [2] and [3].
146NOTE: By default, just the Smith normal form of M is returned.
147@* If the optional integer @code{eng1} is non-zero, the list {U,D,V} is returned
148@* where U*M*V = D and the diagonal field entries of D are not normalized.
149@* The normalization of the latter can be done with the 'divideUnits' procedure.
150@* U and V above are square unimodular (invertible) matrices.
151@* Note, that the procedure works for a rectangular matrix M.
152@*
153@* The optional integer @code{eng2} determines the Groebner basis engine:
154@* 0 (default) ensures the use of 'slimgb' , otherwise 'std' is used.
155DISPLAY: If @code{printlevel}=1, progress debug messages will be printed,
156@* if @code{printlevel}>=2, all the debug messages will be printed.
157EXAMPLE: example smith; shows examples
158SEE ALSO: divideUnits, jacobson
159"
160{
161  def R = basering;
162  // check assume: R must be a polynomial ring in 1 variable
163  setring R;
164  if (nvars(R) >1 )
165  {
166    ERROR("Basering must have exactly one variable");
167  }
168
169  int eng = 0;
170  int BASIS;
171  if ( size(#)>0 )
172  {
173    eng=1;
174    if (typeof(#[1])=="int")
175    {
176      eng=int(#[1]); // zero can also happen
177    }
178  }
179  if (size(#)==2)
180  {
181  BASIS=#[2];
182  }
183  else{BASIS=0;}
184
185
186  int ROW=ncols(MA);
187  int COL=nrows(MA);
188
189  //generate a module consisting of the columns of MA
190  module m=MA[1];
191  int i;
192  for(i=2;i<=ROW;i++)
193  {
194    m=m,MA[i];
195  }
196
197  //if MA eqauls the zero matrix give back MA
198  if ( (size(module(m))==0) and (size(transpose(module(m)))==0) )
199  {
200    module L=freemodule(COL);
201    matrix LM=L;
202    L=freemodule(ROW);
203    matrix RM=L;
204    list RUECK=RM;
205    RUECK=insert(RUECK,MA);
206    RUECK=insert(RUECK,LM);
207    return(RUECK);
208  }
209
210  if(eng==1)
211  {
212    list rueckLI=diagonal_with_trafo(R,MA,BASIS);
213    list rueckLII=divisibility(rueckLI[2]);
214    matrix CON=divideByContent(rueckLII[2]);
215    list rueckL=CON*rueckLII[1]*rueckLI[1], CON*rueckLII[2], rueckLI[3]*rueckLII[3];
216    return(rueckL);
217  }
218  else
219  {
220    matrix rueckm=diagonal_without_trafo(R,MA,BASIS);
221    list rueckL=divisibility(rueckm);
222    matrix CON=divideByContent(rueckm);
223    rueckm=CON*rueckL[2];
224    return(rueckm);
225  }
226}
227example
228{ "EXAMPLE:"; echo = 2;
229  ring r = 0,x,Dp;
230  matrix m[3][2]=x, x^4+x^2+21, x^4+x^2+x, x^3+x, 4*x^2+x, x;
231  list s=smith(m,1);
232  print(s[2]);  // non-normalized Smith form of m
233  print(s[1]*m*s[3] - s[2]); // check U*M*V = D
234  list t = divideUnits(s);
235  print(t[2]); // the Smith form of m
236}
237
238static proc diagonal_with_trafo( R, matrix MA, int B)
239{
240
241int ppl = printlevel-voice+2;
242
243  int BASIS=B;
244  int ROW=ncols(MA);
245  int COL=nrows(MA);
246  module m=MA[1];
247  int i,j,k;
248  for(i=2;i<=ROW;i++)
249  {
250    m=m,MA[i];
251  }
252
253
254  //add zero rows or columns
255  //add zero rows or columns
256  int adrow=0;
257  for(i=1;i<=COL;i++)
258  {
259  k=0;
260  for(j=1;j<=ROW;j++)
261  {
262  if(MA[i,j]!=0){k=1;}
263  }
264  if(k==0){adrow++;}
265  }
266
267    m=transpose(m);
268    for(i=1;i<=adrow;i++){m=m,0;}
269    m=transpose(m);
270
271  list RINGLIST=ringlist(R);
272  list o="C",0;
273  list oo="lp",1;
274  list ORD=o,oo;
275  RINGLIST[3]=ORD;
276  def r=ring(RINGLIST);
277  setring r;
278  //fix the required ordering
279  map MAP=R,var(1);
280  module m=MAP(m);
281
282  int flag=1;  ///////////////counts if the underlying ring is r (flag mod 2 == 1) or ro (flag mod 2 == 0)
283
284    module TrafoL=freemodule(COL);
285    module TrafoR=freemodule(ROW);
286    module EXL=freemodule(COL); //because we start with transpose(m)
287    module EXR=freemodule(ROW);
288
289    option(redSB);
290    option(redTail);
291    module STD_EX;
292    module Trafo;
293
294    int s,st,p,ff;
295
296    module LT,TSTD;
297    module STD=transpose(m);
298    int finish=0;
299    int fehlpos;
300    list pos;
301    matrix END;
302    matrix ENDSTD;
303    matrix STDFIN;
304    STDFIN=STD;
305    list COMPARE=STDFIN;
306
307    while(finish==0)
308    {
309      dbprint(ppl,"Going into the while cycle");
310
311      if(flag mod 2==1)
312      {
313        STD_EX=EXL,transpose(STD);
314      }
315      else
316      {
317        STD_EX=EXR,transpose(STD);
318      }
319        dbprint(ppl,"Computing Groebner basis: start");
320        dbprint(ppl-1,STD);
321      STD=engine(STD,BASIS);
322        dbprint(ppl,"Computing Groebner basis: finished");
323        dbprint(ppl-1,STD);
324
325      if(flag mod 2==1){s=ROW; st=COL;}else{s=COL; st=ROW;}
326        dbprint(ppl,"Computing Groebner basis for transformation matrix: start");
327        dbprint(ppl-1,STD_EX);
328      STD_EX=transpose(STD_EX);
329      STD_EX=engine(STD_EX,BASIS);
330        dbprint(ppl,"Computing Groebner basis for transformation matrix: finished");
331        dbprint(ppl-1,STD_EX);
332
333      //////// split STD_EX in STD and the transformation matrix
334      STD_EX=transpose(STD_EX);
335      STD=STD_EX[st+1];
336      LT=STD_EX[1];
337
338      ENDSTD=STD_EX;
339      for(i=2; i<=ncols(ENDSTD); i++)
340      {
341        if (i<=st)
342        {
343         LT=LT,STD_EX[i];
344        }
345        if (i>st+1)
346        {
347          STD=STD,STD_EX[i];
348        }
349      }
350
351      STD=transpose(STD);
352      LT=transpose(LT);
353
354      ////////////////////// compute the transformation matrices
355
356      if (flag mod 2 ==1)
357      {
358        TrafoL=transpose(LT)*TrafoL;
359      }
360      else
361      {
362        TrafoR=TrafoR*LT;
363      }
364
365
366      STDFIN=STD;
367      /////////////////////////////////// check if the D-th row is finished ///////////////////////////////////
368      COMPARE=insert(COMPARE,STDFIN);
369             if(size(COMPARE)>=3)
370       {
371        if(STD==COMPARE[3]){finish=1;}
372       }
373////////////////////////////////// change to the opposite module
374       TSTD=transpose(STD);
375       STD=TSTD;
376       flag++;
377      dbprint(ppl,"Finished one while cycle");
378    }
379
380
381   if (flag mod 2!=0) { STD=transpose(STD); }
382
383
384   //zero colums to the end
385    matrix STDMM=STD;
386    pos=list();
387    fehlpos=0;
388    while( size(STD)+fehlpos-ncols(STDMM) < 0)
389    {
390      for(i=1; i<=ncols(STDMM); i++)
391      {
392        ff=0;
393        for(j=1; j<=nrows(STDMM); j++)
394        {
395          if (STD[j,i]==0) { ff++; }
396        }
397        if(ff==nrows(STDMM))
398        {
399          pos=insert(pos,i); fehlpos++;
400        }
401      }
402    }
403    int fehlposc=fehlpos;
404    module SORT;
405    for(i=1; i<=fehlpos; i++)
406    {
407      SORT=gen(2);
408      for (j=3;j<=ROW;j++)
409      {
410        SORT=SORT,gen(j);
411      }
412      SORT=SORT,gen(1);
413      STD=STD*SORT;
414      TrafoR=TrafoR*SORT;
415    }
416
417    //zero rows to the end
418    STDMM=transpose(STD);
419    pos=list();
420    fehlpos=0;
421    while( size(transpose(STD))+fehlpos-ncols(STDMM) < 0)
422    {
423      for(i=1; i<=ncols(STDMM); i++)
424      {
425        ff=0; for(j=1; j<=nrows(STDMM); j++)
426        {
427           if(transpose(STD)[j,i]==0){ ff++;}}
428           if(ff==nrows(STDMM)) { pos=insert(pos,i); fehlpos++; }
429      }
430    }
431    int fehlposr=fehlpos;
432
433    for(i=1; i<=fehlpos; i++)
434    {
435      SORT=gen(2);
436      for(j=3;j<=COL;j++){SORT=SORT,gen(j);}
437      SORT=SORT,gen(1);
438      SORT=transpose(SORT);
439      STD=SORT*STD;
440      TrafoL=SORT*TrafoL;
441    }
442
443    setring R;
444    map MAPinv=r,var(1);
445    module STD=MAPinv(STD);
446    module TrafoL=MAPinv(TrafoL);
447    matrix TrafoLM=TrafoL;
448    module TrafoR=MAPinv(TrafoR);
449    matrix TrafoRM=TrafoR;
450    matrix STDM=STD;
451
452    //Test
453    if(TrafoLM*m*TrafoRM!=STDM){ return(0); }
454
455    list RUECK=TrafoRM;
456    RUECK=insert(RUECK,STDM);
457    RUECK=insert(RUECK,TrafoLM);
458    return(RUECK);
459}
460
461
462static proc divisibility(matrix M)
463   {
464    matrix STDM=M;
465    int i,j;
466    int ROW=nrows(M);
467    int COL=ncols(M);
468    module TrafoR=freemodule(COL);
469    module TrafoL=freemodule(ROW);
470    module SORT;
471    matrix TrafoRM=TrafoR;
472    matrix TrafoLM=TrafoL;
473    list posdeg0;
474    int posdeg=0;
475    int act;
476    int Sort=ROW;
477    if(size(std(STDM))!=0)
478    { while( size(transpose(STDM)[Sort])==0 ){Sort--;}}
479
480    for(i=1;i<=Sort ;i++)
481    {
482      if(leadexp(STDM[i,i])==0){posdeg0=insert(posdeg0,i);posdeg++;}
483    }
484    //entries of degree 0 at the beginning
485    for(i=1; i<=posdeg; i++)
486    {
487      act=posdeg0[i];
488      SORT=gen(act);
489      for(j=1; j<=COL; j++){if(j!=act){SORT=SORT,gen(j);}}
490      STDM=STDM*SORT;
491      TrafoRM=TrafoRM*SORT;
492      SORT=gen(act);
493      for(j=1; j<=ROW; j++){if(j!=act){SORT=SORT,gen(j);}}
494      STDM=transpose(SORT)*STDM;
495      TrafoLM=transpose(SORT)*TrafoLM;
496    }
497
498    poly G;
499    module UNITL=freemodule(ROW);
500    matrix GCDL=UNITL;
501    module UNITR=freemodule(COL);
502    matrix GCDR=UNITR;
503    for(i=posdeg+1; i<=Sort; i++)
504    {
505      for(j=i+1; j<=Sort; j++)
506      {
507        GCDL=UNITL;
508        GCDR=UNITR;
509        G=gcd(STDM[i,i],STDM[j,j]);
510        ideal Z=STDM[i,i],STDM[j,j];
511        matrix T=lift(Z,G);
512        GCDL[i,i]=T[1,1];
513        GCDL[i,j]=T[2,1];
514        GCDL[j,i]=-STDM[j,j]/G;
515        GCDL[j,j]=STDM[i,i]/G;
516        GCDR[i,j]=T[2,1]*STDM[j,j]/G;
517        GCDR[j,j]=T[2,1]*STDM[j,j]/G-1;
518        GCDR[j,i]=1;
519        STDM=GCDL*STDM*GCDR;
520        TrafoLM=GCDL*TrafoLM;
521        TrafoRM=TrafoRM*GCDR;
522      }
523    }
524    list RUECK=TrafoRM;
525    RUECK=insert(RUECK,STDM);
526    RUECK=insert(RUECK,TrafoLM);
527    return(RUECK);
528}
529
530static proc diagonal_without_trafo( R, matrix MA, int B)
531{
532  int ppl = printlevel-voice+2;
533
534  int BASIS=B;
535  int ROW=ncols(MA);
536  int COL=nrows(MA);
537  module m=MA[1];
538  int i;
539  for(i=2;i<=ROW;i++)
540  {m=m,MA[i];}
541
542
543  list RINGLIST=ringlist(R);
544  list o="C",0;
545  list oo="lp",1;
546  list ORD=o,oo;
547  RINGLIST[3]=ORD;
548  def r=ring(RINGLIST);
549  setring r;
550  //RICHTIGE ORDNUNG MACHEN
551  map MAP=R,var(1);
552  module m=MAP(m);
553
554  int flag=1; ///////////////counts if the underlying ring is r (flag mod 2 == 1) or ro (flag mod 2 == 0)
555
556
557    int act, j, ff;
558    option(redSB);
559    option(redTail);
560
561
562    module STD=transpose(m);
563    module TSTD;
564    int finish=0;
565    matrix STDFIN;
566    STDFIN=STD;
567    list COMPARE=STDFIN;
568
569    while(finish==0)
570    {
571      dbprint(ppl,"Going into the while cycle");
572      dbprint(ppl,"Computing Groebner basis: start");
573      dbprint(ppl-1,STD);
574      STD=engine(STD,BASIS);
575      dbprint(ppl,"Computing Groebner basis: finished");
576      dbprint(ppl-1,STD);
577      STDFIN=STD;
578      /////////////////////////////////// check if the D-th row is finished ///////////////////////////////////
579      COMPARE=insert(COMPARE,STDFIN);
580             if(size(COMPARE)>=3)
581       {
582        if(STD==COMPARE[3]){finish=1;}
583       }
584        ////////////////////////////////// change to the opposite module
585
586        TSTD=transpose(STD);
587        STD=TSTD;
588        flag++;
589        dbprint(ppl,"Finished one while cycle");
590    }
591
592    matrix STDMM=STD;
593    list pos=list();
594    int fehlpos=0;
595    while( size(STD)+fehlpos-ncols(STDMM) < 0)
596    {
597      for(i=1; i<=ncols(STDMM); i++)
598      {
599        ff=0;
600        for(j=1; j<=nrows(STDMM); j++)
601        {
602          if (STD[j,i]==0) { ff++; }
603        }
604        if(ff==nrows(STDMM))
605        {
606          pos=insert(pos,i); fehlpos++;
607        }
608      }
609    }
610   int fehlposc=fehlpos;
611    module SORT;
612    for(i=1; i<=fehlpos; i++)
613    {
614      SORT=gen(2);
615      for (j=3;j<=ROW;j++)
616      {
617        SORT=SORT,gen(j);
618      }
619      SORT=SORT,gen(1);
620      STD=STD*SORT;
621    }
622
623    //zero rows to the end
624    STDMM=transpose(STD);
625    pos=list();
626    fehlpos=0;
627    while( size(transpose(STD))+fehlpos-ncols(STDMM) < 0)
628    {
629      for(i=1; i<=ncols(STDMM); i++)
630      {
631        ff=0; for(j=1; j<=nrows(STDMM); j++)
632        {
633           if(transpose(STD)[j,i]==0){ ff++;}}
634           if(ff==nrows(STDMM)) { pos=insert(pos,i); fehlpos++; }
635      }
636    }
637    int fehlposr=fehlpos;
638
639    for(i=1; i<=fehlpos; i++)
640    {
641      SORT=gen(2);
642      for(j=3;j<=COL;j++){SORT=SORT,gen(j);}
643      SORT=SORT,gen(1);
644      SORT=transpose(SORT);
645      STD=SORT*STD;
646    }
647
648   //add zero rows or columns
649
650    int adrow=COL-size(transpose(STD));
651    int adcol=ROW-size(STD);
652
653    for(i=1;i<=adcol;i++){STD=STD,0;}
654    STD=transpose(STD);
655    for(i=1;i<=adrow;i++){STD=STD,0;}
656    STD=transpose(STD);
657
658    setring R;
659    map MAPinv=r,var(1);
660    module STD=MAPinv(STD);
661    matrix STDM=STD;
662    return(STDM);
663}
664
665
666// VL : engine replaced by the one from dmodapp.lib
667// cases are changed
668
669// static proc engine(module I, int i)
670// {
671//   module J;
672//   if (i==0)
673//   {
674//     J = std(I);
675//   }
676//   if (i==1)
677//   {
678//     J = groebner(I);
679//   }
680//   if (i==2)
681//   {
682//     J = slimgb(I);
683//   }
684//   return(J);
685// }
686
687proc jacobson(matrix MA, list #)
688 "USAGE:  jacobson(M, eng);  M matrix, eng an optional int
689RETURN: list
690ASSUME: Basering is a (non-commutative) ring in two variables.
691PURPOSE: compute a weak Jacobson normal form of M over the basering
692THEORY: Groebner bases and involutions are used, following [3]
693NOTE: A list L of matrices {U,D,V} is returned. That is L[1]*M*L[3]=L[2],
694@*      where L[2] is a diagonal matrix and
695@*      L[1], L[3] are square invertible polynomial (unimodular) matrices.
696@*      Note, that M can be rectangular.
697@* The optional integer @code{eng2} determines the Groebner basis engine:
698@* 0 (default) ensures the use of 'slimgb' , otherwise 'std' is used.
699DISPLAY: If @code{printlevel}=1, progress debug messages will be printed,
700@* if @code{printlevel}>=2, all the debug messages will be printed.
701EXAMPLE: example jacobson; shows examples
702SEE ALSO: divideUnits, smith
703"
704{
705  def R = basering;
706  // check assume: R must be a polynomial ring in 2 variables
707  setring R;
708  if ( (nvars(R) !=2 ) )
709  {
710    ERROR("Basering must have exactly two variables");
711  }
712
713  // check if MA is zero matrix and return corr. U,V
714  if ( (size(module(MA))==0) and (size(transpose(module(MA)))==0) )
715  {
716    int nr = nrows(MA);
717    int nc = ncols(MA);
718    matrix U = matrix(freemodule(nr));
719    matrix V = matrix(freemodule(nc));
720    list L; L[1]=U; L[2] = MA; L[3] = V;
721    return(L);
722  }
723
724  int B=0;
725  if ( size(#)>0 )
726  {
727    B=1;
728    if (typeof(#[1])=="int")
729    {
730    B=int(#[1]); // zero can also happen
731    }
732  }
733
734  //change ring
735  list RINGLIST=ringlist(R);
736  list o="C",0;
737  intvec v=0,1;
738  list oo="a",v;
739  v=1,1;
740  list ooo="lp",v;
741  list ORD=o,oo,ooo;
742  RINGLIST[3]=ORD;
743  def r=ring(RINGLIST);
744  setring r;
745
746  //fix the required ordering
747  map MAP=R,var(1),var(2);
748  matrix M=MAP(MA);
749
750  module TrafoL, TrafoR;
751  list TRIANGLE;
752  TRIANGLE=triangle(M,B);
753  TrafoL=TRIANGLE[1];
754  TrafoR=TRIANGLE[3];
755  module m=TRIANGLE[2];
756
757  //back to the ring
758  setring R;
759  map MAPR=r,var(1),var(2);
760  module ma=MAPR(m);
761  matrix MAA=ma;
762  module TL=MAPR(TrafoL);
763  module TR=MAPR(TrafoR);
764  matrix TRR=TR;
765  matrix CON=divideByContent(MAA);
766
767list RUECK=CON*TL, CON*MAA, TRR;
768return(RUECK);
769}
770example
771{
772  "EXAMPLE:"; echo = 2;
773  ring r = 0,(x,d),Dp;
774  def R = nc_algebra(1,1);   setring R; // the 1st Weyl algebra
775  matrix m[2][2] = d,x,0,d; print(m);
776  list J = jacobson(m); // returns a list with 3 entries
777  print(J[2]); // a Jacobson Form D for m
778  print(J[1]*m*J[3] - J[2]); // check that U*M*V = D
779  /*   now, let us do the same for the shift algebra  */
780  ring r2 = 0,(x,s),Dp;
781  def R2 = nc_algebra(1,s);   setring R2; // the 1st shift algebra
782  matrix m[2][2] = s,x,0,s; print(m); // matrix of the same for as above
783  list J = jacobson(m);
784  print(J[2]); // a Jacobson Form D, quite different from above
785  print(J[1]*m*J[3] - J[2]); // check that U*M*V = D
786}
787
788static proc triangle( matrix MA, int B)
789{
790 int ppl = printlevel-voice+2;
791
792  map inv=ncdetection();
793  int ROW=ncols(MA);
794  int COL=nrows(MA);
795
796  //generate a module consisting of the columns of MA
797  module m=MA[1];
798  int i,j,s,st,p,k,ff,ex, nz, ii,nextp;
799  for(i=2;i<=ROW;i++)
800  {
801    m=m,MA[i];
802  }
803  int BASIS=B;
804
805  //add zero rows or columns
806  int adrow=0;
807  for(i=1;i<=COL;i++)
808  {
809  k=0;
810  for(j=1;j<=ROW;j++)
811  {
812  if(MA[i,j]!=0){k=1;}
813  }
814  if(k==0){adrow++;}
815  }
816
817    m=transpose(m);
818    for(i=1;i<=adrow;i++){m=m,0;}
819    m=transpose(m);
820
821
822    int flag=1;  ///////////////counts if the underlying ring is r (flag mod 2 == 1) or ro (flag mod 2 == 0)
823
824    module TrafoL=freemodule(COL);
825    module TrafoR=freemodule(ROW);
826    module EXL=freemodule(COL); //because we start with transpose(m)
827    module EXR=freemodule(ROW);
828
829    option(redSB);
830    option(redTail);
831    module STD_EX,LT,TSTD, L, Trafo;
832
833
834
835    module STD=transpose(m);
836    int finish=0;
837    list pos, COM, COM_EX;
838    matrix END, ENDSTD, STDFIN;
839    STDFIN=STD;
840    list COMPARE=STDFIN;
841
842
843  while(finish==0)
844    {
845      dbprint(ppl,"Going into the while cycle");
846      if(flag mod 2==1){STD_EX=EXL,transpose(STD); ex=2*COL;} else {STD_EX=EXR,transpose(STD); ex=2*ROW;}
847
848      dbprint(ppl,"Computing Groebner basis: start");
849      dbprint(ppl-1,STD);
850      STD=engine(STD,BASIS);
851      dbprint(ppl,"Computing Groebner basis: finished");
852      dbprint(ppl-1,STD);
853      if(flag mod 2==1){s=ROW; st=COL;}else{s=COL; st=ROW;}
854
855      STD_EX=transpose(STD_EX);
856      dbprint(ppl,"Computing Groebner basis for transformation matrix: start");
857      dbprint(ppl-1,STD_EX);
858      STD_EX=engine(STD_EX,BASIS);
859      dbprint(ppl,"Computing Groebner basis for transformation matrix: finished");
860      dbprint(ppl-1,STD_EX);
861
862      COM=1;
863      COM_EX=1;
864      for(i=2; i<=size(STD); i++)
865         { COM=COM[1..size(COM)],i; COM_EX=COM_EX[1..size(COM_EX)],i; }
866      nz=size(STD_EX)-size(STD);
867
868      //zero rows in the begining
869
870       if(size(STD)!=size(STD_EX) )
871       {
872         for(i=1; i<=size(STD_EX)-size(STD); i++)
873         {
874           COM_EX=0,COM_EX[1..size(COM_EX)];
875         }
876       }
877
878       for(i=nz+1; i<=size(STD_EX); i++ )
879        {if( leadcoef(STD[i-nz])!=leadcoef(STD_EX[i]) )          {STD[i-nz]=leadcoef(STD_EX[i])*STD[i-nz];}
880        }
881
882        //assign the zero rows in STD_EX
883
884       for (j=2; j<=nz; j++)
885       {
886        p=0;
887        i=1;
888        while(STD_EX[j-1][i]==0){i++;};
889        p=i-1;
890        nextp=1;
891        k=0;
892        i=1;
893        while(STD_EX[j][i]==0 and i<=p)
894        { k++; i++;}
895        if (k==p){ COM_EX[j]=-1; }
896       }
897
898      //assign the zero rows in STD
899      for (j=2; j<=size(STD); j++)
900       {
901        i=size(transpose(STD));
902        while(STD[j-1][i]==0){i--;}
903        p=i;
904        i=size(transpose(STD[j]));
905        while(STD[j][i]==0){i--;}
906        if (i==p){ COM[j]=-1; }
907       }
908
909       for(j=1; j<=size(COM); j++)
910        {
911        if(COM[j]<0){COM=delete(COM,j);}
912        }
913
914      for(i=1; i<=size(COM_EX); i++)
915        {ff=0;
916         if(COM_EX[i]==0){ff=1;}
917         else
918          {  for(j=1; j<=size(COM); j++)
919               { if(COM_EX[i]==COM[j]){ff=1;} }
920          }
921         if(ff==0){COM_EX[i]=-1;}
922        }
923
924      L=STD_EX[1];
925      for(i=2; i<=size(COM_EX); i++)
926       {
927        if(COM_EX[i]!=-1){L=L,STD_EX[i];}
928       }
929
930      //////// split STD_EX in STD and the transformation matrix
931
932       L=transpose(L);
933       STD=L[st+1];
934       LT=L[1];
935
936
937       for(i=2; i<=s+st; i++)
938        {
939         if (i<=st)
940          {
941           LT=LT,L[i];
942          }
943         if (i>st+1)
944          {
945          STD=STD,L[i];
946          }
947        }
948
949       STD=transpose(STD);
950       STDFIN=matrix(STD);
951       COMPARE=insert(COMPARE,STDFIN);
952       LT=transpose(LT);
953
954      ////////////////////// compute the transformation matrices
955
956       if (flag mod 2 ==1)
957        {
958         TrafoL=transpose(LT)*TrafoL;
959        }
960       else
961        {
962         TrafoR=TrafoR*involution(LT,inv);
963        }
964
965      ///////////////////////// check whether the alg terminated /////////////////
966      if(size(COMPARE)>=3)
967       {
968        if(STD==COMPARE[3]){finish=1;}
969       }
970       ////////////////////////////////// change to the opposite module
971       TSTD=transpose(STD);
972       STD=involution(TSTD,inv);
973       flag++;
974       dbprint(ppl,"Finished one while cycle");
975    }
976
977if (flag mod 2 ==0){ STD = involution(STD,inv);} else { STD = transpose(STD);  }
978
979    list REVERSE=TrafoL,STD,TrafoR;
980    return(REVERSE);
981}
982
983static proc divideByContent(matrix M)
984{
985//find first entrie not equal to zero
986int i,k;
987k=1;
988vector CON;
989   for(i=1;i<=ncols(M);i++)
990   {
991    if(leadcoef(M[i])!=0){CON=CON+leadcoef(M[i])*gen(k); k++;}
992   }
993poly con=content(CON);
994matrix TL=1/con*freemodule(nrows(M));
995return(TL);
996}
997
998
999/////interesting examples for smith////////////////
1000
1001/*
1002
1003//static proc Ex_One_wheeled_bicycle()
1004{
1005ring RA=(0,m), D, lp;
1006matrix bicycle[2][3]=(1+m)*D^2, D^2, 1, D^2, D^2-1, 0;
1007list s=smith(bicycle, 1,0);
1008print(s[2]);
1009print(s[1]*bicycle*s[3]-s[2]);
1010}
1011
1012
1013//static proc Ex_RLC-circuit()
1014{
1015ring RA=(0,m,R1,R2,L,C), D, lp;
1016matrix  circuit[2][3]=D+1/(R1*C), 0, -1/(R1*C), 0, D+R2/L, -1/L;
1017list s=smith(circuit, 1,0);
1018print(s[2]);
1019print(s[1]*circuit*s[3]-s[2]);
1020}
1021
1022
1023//static proc Ex_two_pendula()
1024{
1025ring RA=(0,m,M,L1,L2,m1,m2,g), D, lp;
1026matrix pendula[3][4]=m1*L1*D^2,m2*L2*D^2,(M+m1+m2)*D^2,-1,m1*L1^2*D^2-m1*L1*g,0,m1*L1*D^2,0,0,
1027m2*L2^2*D^2-m2*L2*g,m2*L2*D^2,0;
1028list s=smith(pendula, 1,0);
1029print(s[2]);
1030print(s[1]*pendula*s[3]-s[2]);
1031}
1032
1033//static proc Ex_linerized_satellite_in_a_circular_equatorial_orbit()
1034{
1035ring RA=(0,m,omega,r,a,b), D, lp;
1036matrix satellite[4][6]=
1037D,-1,0,0,0,0,
1038-3*omega^2,D,0,-2*omega*r,-a/m,0,
10390,0,D,-1,0,0,
10400,2*omega/r,0,D,0,-b/(m*r);
1041list s=smith(satellite, 1,0);
1042print(s[2]);
1043print(s[1]*satellite*s[3]-s[2]);
1044}
1045
1046//static proc Ex_flexible_one_link_robot()
1047{
1048ring RA=(0,M11,M12,M13,M21,M22,M31,M33,K1,K2), D, lp;
1049matrix robot[3][4]=M11*D^2,M12*D^2,M13*D^2,-1,M21*D^2,M22*D^2+K1,0,0,M31*D^2,0,M33*D^2+K2,0;
1050list s=smith(robot, 1,0);
1051print(s[2]);
1052print(s[1]*robot*s[3]-s[2]);
1053}
1054
1055*/
1056
1057
1058/////interesting examples for jacobson////////////////
1059
1060/*
1061
1062//static proc Ex_compare_output_with_maple_package_JanetOre()
1063{
1064    ring w = 0,(x,d),Dp;
1065    def W=nc_algebra(1,1);
1066    setring W;
1067    matrix m[3][3]=[d2,d+1,0],[d+1,0,d3-x2*d],[2d+1, d3+d2, d2];
1068    list J=jacobson(m,0);
1069    print(J[1]*m*J[3]);
1070    print(J[2]);
1071    print(J[1]);
1072    print(J[3]);
1073    print(J[1]*m*J[3]-J[2]);
1074}
1075
1076// modification for shift algebra
1077{
1078    ring w = 0,(x,s),Dp;
1079    def W=nc_algebra(1,s);
1080    setring W;
1081    matrix m[3][3]=[s^2,s+1,0],[s+1,0,s^3-x^2*s],[2*s+1, s^3+s^2, s^2];
1082    list J=jacobson(m,0);
1083    print(J[1]*m*J[3]);
1084    print(J[2]);
1085    print(J[1]);
1086    print(J[3]);
1087    print(J[1]*m*J[3]-J[2]);
1088}
1089
1090//static proc Ex_cyclic()
1091{
1092    ring w = 0,(x,d),Dp;
1093    def W=nc_algebra(1,1);
1094    setring W;
1095    matrix m[3][3]=d,0,0,x*d+1,d,0,0,x*d,d;
1096    list J=jacobson(m,0);
1097    print(J[1]*m*J[3]);
1098    print(J[2]);
1099    print(J[1]);
1100    print(J[3]);
1101    print(J[1]*m*J[3]-J[2]);
1102}
1103
1104// modification for shift algebra: gives a module with ann = s^2
1105{
1106    ring w = 0,(x,s),Dp;
1107    def W=nc_algebra(1,s);
1108    setring W;
1109    matrix m[3][3]=s,0,0,x*s+1,s,0,0,x*s,s;
1110    list J=jacobson(m,0);
1111    print(J[1]*m*J[3]);
1112    print(J[2]);
1113    print(J[1]);
1114    print(J[3]);
1115    print(J[1]*m*J[3]-J[2]);
1116}
1117
1118// yet another modification for shift algebra: gives a module with ann = s
1119// xs+1 is replaced by x*s+s
1120{
1121    ring w = 0,(x,s),Dp;
1122    def W=nc_algebra(1,s);
1123    setring W;
1124    matrix m[3][3]=s,0,0,x*s+s,s,0,0,x*s,s;
1125    list J=jacobson(m,0);
1126    print(J[1]*m*J[3]);
1127    print(J[2]);
1128    print(J[1]);
1129    print(J[3]);
1130    print(J[1]*m*J[3]-J[2]);
1131}
1132
1133// variations for above setup with shift algebra:
1134
1135// easy but instructive one: see the difference to Weyl case!
1136matrix m[2][2]=s,x,0,s; print(m);
1137
1138// more interesting:
1139matrix n[3][3]=s,x,0,0,s,x,s,0,x;
1140
1141// things blow up
1142matrix m[2][3] = s,x^2*s,x^3*s,s*x^2,s*x+1,(x+1)^3;
1143matrix m[2][3] = s,x^2*s,x^3*s,s*x^2,s*x+1,(x+s)^2; // variation
1144matrix m[2][4] = s,x^2*s,x^3*s,s*x^2,s*x+1,(x+1)^3, (x+s)^2, x*s; // bug!
1145matrix m[3][4] = s,x^2*s,x^3*s,s*x^2,s*x+1,(x+1)^3, (x+s)^2, x*s; // here the last row contains zeros
1146
1147// this one is quite nasty and time consumig
1148matrix m[3][4] = s,x^2*s,x^3*s,s*x^2,s*x+1,(x+1)^3, (x+s)^2, x*s,x,x^2,x^3,s;
1149
1150// example from the paper:
1151    ring w = 0,(x,d),Dp;
1152    def W=nc_algebra(1,1);
1153    setring W;
1154    matrix m[2][2]=d^2-1,d+1,d^2+1,d-x;
1155    list J=jacobson(m,0);
1156    print(J[1]*m*J[3]);     print(J[2]);     print(J[1]);     print(J[3]);
1157    print(J[1]*m*J[3]-J[2]);
1158
1159    ring w2 = 0,(x,s),Dp;
1160    def W2=nc_algebra(1,s);
1161    setring W2;
1162    poly d = s;
1163    matrix m[2][2]=d^2-1,d+1,d^2+1,d-x;
1164    list J=jacobson(m,0);
1165    print(J[1]*m*J[3]);     print(J[2]);     print(J[1]);     print(J[3]);
1166    print(J[1]*m*J[3]-J[2]);
1167// here, both JNFs are cyclic
1168
1169// another example from the paper:
1170    ring w = 0,(x,d),Dp;
1171    def W=nc_algebra(1,1);
1172    setring W;
1173   matrix m[2][2]=-x*d+1, x^2*d, -d, x*d+1;
1174    list J=jacobson(m,0);
1175    print(J[1]*m*J[3]);     print(J[2]);     print(J[1]);     print(J[3]);
1176    print(J[1]*m*J[3]-J[2]);
1177
1178    ring w2 = 0,(x,s),Dp;
1179    def W2=nc_algebra(1,s);
1180    setring W2;
1181    poly d = s;
1182   matrix m[2][2]=-x*d+1, x^2*d, -d, x*d+1;
1183    list J=jacobson(m,0);
1184    print(J[1]*m*J[3]);     print(J[2]);     print(J[1]);     print(J[3]);
1185    print(J[1]*m*J[3]-J[2]);
1186
1187// yet another example from the paper, also Middeke
1188   ring w = (0,y),(x,d),Dp;
1189   def W=nc_algebra(1,1);
1190   setring W;
1191   matrix m[2][2]=y^2*d^2+d+1, 1, x*d, x^2*d^2+d+y;
1192   list J=jacobson(m,0);
1193   print(J[1]*m*J[3]);     print(J[2]);     print(J[1]);     print(J[3]);
1194   print(J[1]*m*J[3]-J[2]);
1195
1196
1197*/
Note: See TracBrowser for help on using the repository browser.