source: git/Singular/LIB/jacobson.lib @ 7a051de

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