Ticket #57: jacobson.lib

File jacobson.lib, 24.1 KB (added by Oleksandr , 15 years ago)
Line 
1//////////////////////////////////////////////////////////////////////////////
2version="$Id: jacobson.lib,v 1.4 2008/12/01 20:51:16 levandov Exp $";
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
8THEORY: We work over a principal ideal domain R. We suppose R to be either
9@*  the commutative polynomial ring in one variable or the Ore localization of
10@*  the first Weyl algebra with respect to S = K[x]\{0} (i.e. K(x)<D|D*x=x*D+1>)
11@*  Under these assumptions on R, given a rectangular matrix M over R, one can
12@*  compute unimodular matrices U, V such that U*M*V=D is a diagonal matrix.
13@*  Depending on the ring, the diagonal entries of D have certain properties.
14@*  Over a commutative ring in one variable, the matrix D is unique and called
15@*  the Smith Normal Form of M, whereas in the non-commutative case D is not
16@*  unique and a weak Jacobson Normal Form of M is computed.
17
18TODO: WHAT ABOUT UNIQUENESS OF JACOBSON NORMAL FORM? WHICH ONE IS RETURNED?
19
20PROCEDURES:
21smith(M[,eng1,eng2]);  computes the Smith Normal Form
22jacobson(M[,eng]);     computes a weak Jacobson Normal Form
23
24SEE ALSO: control_lib
25";
26
27  LIB "poly.lib"; // TODO: WHAT FOR?
28  LIB "involut.lib"; // TODO: WHAT FOR?
29
30///////////////////////////////////////////////////////////////////////////////
31
32// TODO: IT IS BETTER TO WORK WITH MODULES INSTEAD OF MATRICES!!!
33// PLEASE SWITCH MATRICES TO MODULES!
34
35// TODO: IS THE ALGORITHM WELL KNOWN OR IS IT DUE TO SOME BOOK???
36// ADD REFERENCE IS SO.
37proc smith(matrix MA, list #)
38"USAGE: smith(M[, eng1, eng2]);  M matrix, eng1 and eng2 are optional integers
39RETURN: matrix or list, either a matrix D or a list containing matrices {U,D,V},
40       such that U*M*V = D, where D is diagonal (the Smith Normal Form of M)
41       and the matrices U and V are unimodular.
42ASSUME: The current ring is assumed to be the commutative polynomial ring in
43        one variable
44NOTE: If the optional integer eng1 is non-zero, returns the list {U,D,V},
45@*    otherwise only the matrix, the Smith Normal Form of M is returned.
46@*    The optional integer eng2 determines the engine, that computes the GB:
47@*    0 means 'std' (default), 1 means 'groebner' and 2 means 'slimgb'.
48@* If @code{printlevel}=1, progress debug messages will be printed,
49@* if @code{printlevel}>=2, all the debug messages will be printed.
50EXAMPLE: example smith; shows examples
51"
52{
53  def R = basering;
54
55  // TODO: ADD ASSUMPTION CHECKS!!!
56
57  int eng = 0;
58  int BASIS = 0;
59
60  if ( size(#) > 0 )
61  {
62    if (typeof(#[1])=="int")
63    {
64      eng=#[1]; // zero can also happen
65    }
66
67    if (size(#) > 1)
68    {
69      if (typeof(#[2])=="int")
70      {
71        BASIS=#[2];
72      }
73    }
74  }
75 
76
77  int ROW=ncols(MA);
78  int COL=nrows(MA);
79
80  //generate a module consisting of the columns of MA
81  module m = MA;
82  int i;
83
84  //if MA eqauls the zero matrix give back MA
85  if ( (size(m)==0) and (size(transpose(m))==0) )
86  {
87    return(list( matrix(freemodule(COL)), MA, matrix(freemodule(ROW)) ));
88  }
89
90  if(eng > 0)
91  {
92    list rueckLI=diagonal_with_trafo(R,MA,BASIS);
93    list rueckLII=divisibility(rueckLI[2]);
94    matrix CON=divideByContent(rueckLII[2]);
95    list rueckL=CON*rueckLII[1]*rueckLI[1], CON*rueckLII[2], rueckLI[3]*rueckLII[3];
96    return(rueckL);
97  }
98  else
99  {
100    matrix rueckm=diagonal_without_trafo(R,MA,BASIS);
101    list rueckL=divisibility(rueckm);
102    matrix CON=divideByContent(rueckm);
103    rueckm=CON*rueckL[2];
104    return(rueckm);
105  }
106}
107example
108{ "EXAMPLE:"; echo = 2;
109  ring r = 0,x,Dp;
110  matrix m[3][2]=x, x^4+x^2+21, x^4+x^2+x, x^3+x, 4*x^2+x, x;
111  print(m); // M
112  print(smith(m)); // Smith Normal Form of M
113  list S=smith(m,1);
114  // TODO: BUG THE FOLLOWING GIVES A DIFFERENT RESULT TO ABOVE!
115  print(S[2]); // Smith Normal Form D of M
116  // TODO: ARE U AND V REALLY UNIMODULAR?
117  S[1]; // U
118  det(S[1]);
119  S[3]; // V
120  det(S[3]);
121  print(S[1]*m*S[3] - S[2]); // check that U*M*V = D
122  print(smith(matrix(0))); // Smith Normal Form of 0
123
124}
125
126// TODO: THIS PROCEDURE SEEMS TOO COMPLICATED, THUS PLEASE
127// TODO: 1. ADD HELP WITH ASSUMPTIONS AND RETURN DESCRIPTION
128// TODO: 2. ADD STEP-BY-STEP COMMENTS INTO THE CODE
129
130static proc diagonal_with_trafo( R, matrix MA, int B)
131{
132
133int ppl = printlevel-voice+2;
134
135  int BASIS=B;
136  int ROW=ncols(MA);
137  int COL=nrows(MA);
138  module m=MA[1];
139  int i,j,k;
140  for(i=2;i<=ROW;i++)
141  {
142    m=m,MA[i];
143  }
144
145
146  //add zero rows or columns
147  //add zero rows or columns
148  int adrow=0;
149  for(i=1;i<=COL;i++)
150  {
151  k=0;
152  for(j=1;j<=ROW;j++)
153  {
154  if(MA[i,j]!=0){k=1;}
155  }
156  if(k==0){adrow++;}
157  }
158   
159    m=transpose(m);
160    for(i=1;i<=adrow;i++){m=m,0;}
161    m=transpose(m);
162
163  list RINGLIST=ringlist(R);
164  list o="C",0;
165  list oo="lp",1;
166  list ORD=o,oo;
167  RINGLIST[3]=ORD;
168  def r=ring(RINGLIST);
169  setring r;
170  //fix the required ordering
171  map MAP=R,var(1);
172  module m=MAP(m);
173
174  int flag=1;  ///////////////counts if the underlying ring is r (flag mod 2 == 1) or ro (flag mod 2 == 0)
175
176    module TrafoL=freemodule(COL);
177    module TrafoR=freemodule(ROW);
178    module EXL=freemodule(COL); //because we start with transpose(m)
179    module EXR=freemodule(ROW);
180
181    option(redSB);
182    option(redTail);
183    module STD_EX;
184    module Trafo;
185
186    int s,st,p,ff;
187   
188    module LT,TSTD;
189    module STD=transpose(m);
190    int finish=0;
191    int fehlpos;
192    list pos;
193    matrix END;
194    matrix ENDSTD;
195    matrix STDFIN;
196    STDFIN=STD;
197    list COMPARE=STDFIN;
198
199    while(finish==0)
200    {
201      dbprint(ppl,"Going into the while cycle");
202
203      if(flag mod 2==1)
204      {
205        STD_EX=EXL,transpose(STD);
206      }
207      else
208      {
209        STD_EX=EXR,transpose(STD);
210      }
211        dbprint(ppl,"Computing Groebner basis: start");
212        dbprint(ppl-1,STD);
213      STD=engine(STD,BASIS);
214        dbprint(ppl,"Computing Groebner basis: finished");
215        dbprint(ppl-1,STD);
216
217      if(flag mod 2==1){s=ROW; st=COL;}else{s=COL; st=ROW;}
218        dbprint(ppl,"Computing Groebner basis for transformation matrix: start");
219        dbprint(ppl-1,STD_EX);
220      STD_EX=transpose(STD_EX);
221      STD_EX=engine(STD_EX,BASIS);
222        dbprint(ppl,"Computing Groebner basis for transformation matrix: finished");
223        dbprint(ppl-1,STD_EX);
224
225      //////// split STD_EX in STD and the transformation matrix
226      STD_EX=transpose(STD_EX);
227      STD=STD_EX[st+1];
228      LT=STD_EX[1];
229
230      ENDSTD=STD_EX;
231      for(i=2; i<=ncols(ENDSTD); i++)
232      {
233        if (i<=st)
234        {
235         LT=LT,STD_EX[i];
236        }
237        if (i>st+1)
238        {
239          STD=STD,STD_EX[i];
240        }
241      }
242
243      STD=transpose(STD);
244      LT=transpose(LT);
245
246      ////////////////////// compute the transformation matrices
247     
248      if (flag mod 2 ==1)
249      {
250        TrafoL=transpose(LT)*TrafoL;
251      }
252      else
253      {
254        TrafoR=TrafoR*LT;
255      }
256
257
258      STDFIN=STD;
259      /////////////////////////////////// check if the D-th row is finished ///////////////////////////////////
260      COMPARE=insert(COMPARE,STDFIN);
261        if(size(COMPARE)>=3)
262       {   
263        if(STD==COMPARE[3]){finish=1;}
264       }
265////////////////////////////////// change to the opposite module
266       TSTD=transpose(STD);
267       STD=TSTD;
268       flag++;
269      dbprint(ppl,"Finished one while cycle");
270    }
271
272
273   if (flag mod 2!=0) { STD=transpose(STD); }
274   
275   
276   //zero colums to the end
277    matrix STDMM=STD;
278    pos=list();
279    fehlpos=0;
280    while( size(STD)+fehlpos-ncols(STDMM) < 0)
281    {
282      for(i=1; i<=ncols(STDMM); i++)
283      {
284        ff=0;
285        for(j=1; j<=nrows(STDMM); j++)
286        {
287          if (STD[j,i]==0) { ff++; }
288        }
289        if(ff==nrows(STDMM))
290        {
291          pos=insert(pos,i); fehlpos++;
292        }
293      }
294    }
295    int fehlposc=fehlpos;
296    module SORT;
297    for(i=1; i<=fehlpos; i++)
298    {
299      SORT=gen(2);
300      for (j=3;j<=ROW;j++)
301      {
302        SORT=SORT,gen(j);
303      }
304      SORT=SORT,gen(1);
305      STD=STD*SORT;
306      TrafoR=TrafoR*SORT;
307    }
308
309    //zero rows to the end
310    STDMM=transpose(STD);
311    pos=list();
312    fehlpos=0;
313    while( size(transpose(STD))+fehlpos-ncols(STDMM) < 0)
314    {
315      for(i=1; i<=ncols(STDMM); i++)
316      {
317        ff=0; for(j=1; j<=nrows(STDMM); j++)
318        {
319           if(transpose(STD)[j,i]==0){ ff++;}}
320           if(ff==nrows(STDMM)) { pos=insert(pos,i); fehlpos++; }
321      }
322    }
323    int fehlposr=fehlpos;
324
325    for(i=1; i<=fehlpos; i++)
326    {
327      SORT=gen(2);
328      for(j=3;j<=COL;j++){SORT=SORT,gen(j);}
329      SORT=SORT,gen(1);
330      SORT=transpose(SORT);
331      STD=SORT*STD;
332      TrafoL=SORT*TrafoL;
333    }
334     
335    setring R;
336    map MAPinv=r,var(1);
337    module STD=MAPinv(STD);
338    module TrafoL=MAPinv(TrafoL);
339    matrix TrafoLM=TrafoL;
340    module TrafoR=MAPinv(TrafoR);
341    matrix TrafoRM=TrafoR;
342    matrix STDM=STD;
343
344    //Test
345    if(TrafoLM*m*TrafoRM!=STDM){ return(0); }
346   
347    list RUECK=TrafoRM;
348    RUECK=insert(RUECK,STDM);
349    RUECK=insert(RUECK,TrafoLM);
350    return(RUECK);
351}
352
353
354
355// TODO: THIS PROCEDURE SEEMS TOO COMPLICATED, THUS PLEASE
356// TODO: 1. ADD HELP WITH ASSUMPTIONS AND RETURN DESCRIPTION
357// TODO: 2. ADD STEP-BY-STEP COMMENTS INTO THE CODE
358
359static proc divisibility(matrix M)
360   {
361    matrix STDM=M;
362    int i,j;
363    int ROW=nrows(M);
364    int COL=ncols(M);
365    module TrafoR=freemodule(COL);
366    module TrafoL=freemodule(ROW);
367    module SORT;
368    matrix TrafoRM=TrafoR;
369    matrix TrafoLM=TrafoL;
370    list posdeg0;
371    int posdeg=0;
372    int act;
373    int Sort=ROW;
374    if(size(std(STDM))!=0)
375    { while( size(transpose(STDM)[Sort])==0 ){Sort--;}}
376
377    for(i=1;i<=Sort ;i++)
378    {
379      if(leadexp(STDM[i,i])==0){posdeg0=insert(posdeg0,i);posdeg++;}
380    }
381    //entries of degree 0 at the beginning
382    for(i=1; i<=posdeg; i++)
383    {
384      act=posdeg0[i];
385      SORT=gen(act);
386      for(j=1; j<=COL; j++){if(j!=act){SORT=SORT,gen(j);}}
387      STDM=STDM*SORT;
388      TrafoRM=TrafoRM*SORT;
389      SORT=gen(act);
390      for(j=1; j<=ROW; j++){if(j!=act){SORT=SORT,gen(j);}}
391      STDM=transpose(SORT)*STDM;
392      TrafoLM=transpose(SORT)*TrafoLM;
393    }
394
395    poly G;
396    module UNITL=freemodule(ROW);
397    matrix GCDL=UNITL;
398    module UNITR=freemodule(COL);
399    matrix GCDR=UNITR;
400    for(i=posdeg+1; i<=Sort; i++)
401    {
402      for(j=i+1; j<=Sort; j++)
403      {
404        GCDL=UNITL;
405        GCDR=UNITR;
406        G=gcd(STDM[i,i],STDM[j,j]);
407        ideal Z=STDM[i,i],STDM[j,j];
408        matrix T=lift(Z,G);
409        GCDL[i,i]=T[1,1];
410        GCDL[i,j]=T[2,1];
411        GCDL[j,i]=-STDM[j,j]/G;
412        GCDL[j,j]=STDM[i,i]/G;
413        GCDR[i,j]=T[2,1]*STDM[j,j]/G;
414        GCDR[j,j]=T[2,1]*STDM[j,j]/G-1;
415        GCDR[j,i]=1;
416        STDM=GCDL*STDM*GCDR;
417        TrafoLM=GCDL*TrafoLM;
418        TrafoRM=TrafoRM*GCDR;
419      }
420    }
421    list RUECK=TrafoRM;
422    RUECK=insert(RUECK,STDM);
423    RUECK=insert(RUECK,TrafoLM);
424    return(RUECK);
425}
426
427
428// TODO: THIS PROCEDURE SEEMS TOO COMPLICATED, THUS PLEASE
429// TODO: 1. ADD HELP WITH ASSUMPTIONS AND RETURN DESCRIPTION
430// TODO: 2. ADD STEP-BY-STEP COMMENTS INTO THE CODE
431
432static proc diagonal_without_trafo( R, matrix MA, int B)
433{
434  int ppl = printlevel-voice+2; 
435
436  int BASIS=B;
437  int ROW=ncols(MA);
438  int COL=nrows(MA);
439  module m=MA[1];
440  int i;
441  for(i=2;i<=ROW;i++)
442  {m=m,MA[i];}
443
444
445  list RINGLIST=ringlist(R);
446  list o="C",0;
447  list oo="lp",1;
448  list ORD=o,oo;
449  RINGLIST[3]=ORD;
450  def r=ring(RINGLIST);
451  setring r;
452  //RICHTIGE ORDNUNG MACHEN
453  map MAP=R,var(1);
454  module m=MAP(m);
455
456  int flag=1; ///////////////counts if the underlying ring is r (flag mod 2 == 1) or ro (flag mod 2 == 0)
457
458
459    int act, j, ff;
460    option(redSB);
461    option(redTail);
462
463
464    module STD=transpose(m);
465    module TSTD;
466    int finish=0;
467    matrix STDFIN;
468    STDFIN=STD;
469    list COMPARE=STDFIN;
470
471    while(finish==0)
472    {
473      dbprint(ppl,"Going into the while cycle");
474      dbprint(ppl,"Computing Groebner basis: start");
475      dbprint(ppl-1,STD);
476      STD=engine(STD,BASIS);
477      dbprint(ppl,"Computing Groebner basis: finished");
478      dbprint(ppl-1,STD);
479      STDFIN=STD;
480      /////////////////////////////////// check if the D-th row is finished ///////////////////////////////////
481      COMPARE=insert(COMPARE,STDFIN);
482        if(size(COMPARE)>=3)
483       {   
484        if(STD==COMPARE[3]){finish=1;}
485       }     
486        ////////////////////////////////// change to the opposite module
487
488        TSTD=transpose(STD);
489        STD=TSTD;
490        flag++;
491        dbprint(ppl,"Finished one while cycle");
492    }
493
494    matrix STDMM=STD;
495    list pos=list();
496    int fehlpos=0;
497    while( size(STD)+fehlpos-ncols(STDMM) < 0)
498    {
499      for(i=1; i<=ncols(STDMM); i++)
500      {
501        ff=0;
502        for(j=1; j<=nrows(STDMM); j++)
503        {
504          if (STD[j,i]==0) { ff++; }
505        }
506        if(ff==nrows(STDMM))
507        {
508          pos=insert(pos,i); fehlpos++;
509        }
510      }
511    }
512   int fehlposc=fehlpos;
513    module SORT;
514    for(i=1; i<=fehlpos; i++)
515    {
516      SORT=gen(2);
517      for (j=3;j<=ROW;j++)
518      {
519        SORT=SORT,gen(j);
520      }
521      SORT=SORT,gen(1);
522      STD=STD*SORT;
523    }
524
525    //zero rows to the end
526    STDMM=transpose(STD);
527    pos=list();
528    fehlpos=0;
529    while( size(transpose(STD))+fehlpos-ncols(STDMM) < 0)
530    {
531      for(i=1; i<=ncols(STDMM); i++)
532      {
533        ff=0; for(j=1; j<=nrows(STDMM); j++)
534        {
535           if(transpose(STD)[j,i]==0){ ff++;}}
536           if(ff==nrows(STDMM)) { pos=insert(pos,i); fehlpos++; }
537      }
538    }
539    int fehlposr=fehlpos;
540
541    for(i=1; i<=fehlpos; i++)
542    {
543      SORT=gen(2);
544      for(j=3;j<=COL;j++){SORT=SORT,gen(j);}
545      SORT=SORT,gen(1);
546      SORT=transpose(SORT);
547      STD=SORT*STD;
548    }
549   
550   //add zero rows or columns
551
552    int adrow=COL-size(transpose(STD));
553    int adcol=ROW-size(STD);
554
555    for(i=1;i<=adcol;i++){STD=STD,0;}
556    STD=transpose(STD);
557    for(i=1;i<=adrow;i++){STD=STD,0;}
558    STD=transpose(STD);
559
560    setring R;
561    map MAPinv=r,var(1);
562    module STD=MAPinv(STD);
563    matrix STDM=STD;
564    return(STDM);
565}
566
567
568
569static proc engine(module I, int i)
570{
571  module J;
572  if (i==0)
573  {
574    J = std(I);
575  }
576  if (i==1)
577  {
578    J = groebner(I);
579  }
580  if (i==2)
581  {
582    J = slimgb(I);
583  }
584  return(J);
585}
586
587///////////////////////////////////////////////////////////////////////////////
588
589
590// TODO: IS THE ALGORITHM WELL KNOWN OR IS IT DUE TO SOME BOOK???
591// ADD REFERENCE IF SO.
592// TODO: ADD A NOTE ABOUT THE CHOSEN JACOBSON NORMAL FORM!
593
594proc jacobson(matrix MA, list #)
595"USAGE:  jacobson(M[, eng]);  M matrix, eng an optional integer
596RETURN: list, a list containing matrices {U,D,V}, such that U*M*V = D,
597        where U and V are unimodular, D is diagonal.
598ASSUME: The current ring is assumed to be the Ore localization of the first
599        Weyl algebra with respect to S = K[x]\{0} (i.e. K(x)<D|D*x=x*D+1>).
600NOTE: The optional integer eng2 determines the engine, that computes the GB:
601@*    0 means 'std' (default), 1 means 'groebner' and 2 means 'slimgb'.
602@* If @code{printlevel}=1, progress debug messages will be printed,
603@* if @code{printlevel}>=2, all the debug messages will be printed.
604EXAMPLE: example jacobson; shows examples
605"
606{
607  def R = basering;
608
609  // TODO: ADD ASSUMPTION CHECKS!!!
610
611  int B=0;
612
613  if ( size(#)>0 )
614  {
615    if (typeof(#[1])=="int")
616    {
617      B = #[1]; // zero can also happen
618    }
619  }
620
621  //change ring
622  list RINGLIST=ringlist(R);
623  list o="C",0;
624  intvec v=1,0;
625  list oo="a",v;
626  v=1,1;
627  list ooo="lp",v;
628  list ORD=o,oo,ooo;
629  RINGLIST[3]=ORD;
630  def r=ring(RINGLIST);
631  setring r;
632 
633  //fix the required ordering
634  matrix M=imap(R, MA);
635
636  list T = triangle(M,B);
637  module TrafoL = T[1];
638  module m      = T[2];
639  module TrafoR = T[3];
640
641  //back to the ring
642  setring R;
643
644  matrix MAA = imap(r, m);
645  matrix CON = divideByContent(MAA);
646  matrix TL = imap(r, TrafoL);
647  matrix TR = imap(r, TrafoR);
648 
649  // TODO: CHECK WHETHER HERE SHOULD BE CON*TR!?
650  return(list(CON*TL, CON*MAA, TR));
651
652}
653example
654{ "EXAMPLE:"; echo = 2;
655  ring r = 0,(x,d),Dp;
656  def R=nc_algebra(1,1); setring R;
657  R; // the Weyl algebra in x and d
658  // jacobson(matrix(0)); // TODO: BUG HERE!!!
659
660  matrix m[2][2]=d,x,0,d;
661  print(m);
662  list J = jacobson(m); // returns a list with 3 entries
663  print(J[2]); // a Jacobson Form D
664  // TODO: ARE U AND V REALLY UNIMODULAR?
665  J[1]; // U
666  J[3]; // V
667
668  print(J[1]*m*J[3] - J[2]); // check that U*M*V = D
669
670  matrix m[3][2]=x, x^4+x^2+21, x^4+x^2+x, x^3+x, 4*x^2+x, x;
671  print(m); // M
672  list JJ = jacobson(m); // returns a list with 3 entries
673
674  // TODO: BUG: WHY THE FOLLOWING JACOBSON FORM IS NOT DIAGONAL???!
675  print(JJ[2]); // a Jacobson Form D
676  print(JJ[1]*m*JJ[3] - JJ[2]); // check that U*M*V = D
677
678  // TODO: ARE U AND V REALLY UNIMODULAR?
679  JJ[1]; // U
680  JJ[3]; // V
681
682  list S=smith(m,1);
683
684  print(S[2]); // Smith Normal Form S of M
685  print(S[1]*m*S[3] - S[2]); // check that U*M*V = S
686
687  // TODO: ARE U AND V REALLY UNIMODULAR?
688  S[1]; // U
689  S[3]; // V
690}
691
692
693// TODO: THIS PROCEDURE SEEMS TOO COMPLICATED, THUS PLEASE
694// TODO: 1. ADD HELP WITH ASSUMPTIONS AND RETURN DESCRIPTION
695// TODO: 2. ADD STEP-BY-STEP COMMENTS INTO THE CODE
696
697static proc triangle( matrix MA, int B)
698{
699 int ppl = printlevel-voice+2;
700
701  map inv=ncdetection();
702  int ROW=ncols(MA);
703  int COL=nrows(MA);
704
705  //generate a module consisting of the columns of MA
706  module m=MA[1];
707  int i,j,s,st,p,k,ff,ex, nz, ii,nextp;
708  for(i=2;i<=ROW;i++)
709  {
710    m=m,MA[i];
711  }
712  int BASIS=B;
713
714  //add zero rows or columns
715  int adrow=0;
716  for(i=1;i<=COL;i++)
717  {
718  k=0;
719  for(j=1;j<=ROW;j++)
720  {
721  if(MA[i,j]!=0){k=1;}
722  }
723  if(k==0){adrow++;}
724  }
725
726    m=transpose(m);
727    for(i=1;i<=adrow;i++){m=m,0;}
728    m=transpose(m);
729
730
731    int flag=1;  ///////////////counts if the underlying ring is r (flag mod 2 == 1) or ro (flag mod 2 == 0)
732
733    module TrafoL=freemodule(COL);
734    module TrafoR=freemodule(ROW);
735    module EXL=freemodule(COL); //because we start with transpose(m)
736    module EXR=freemodule(ROW);
737
738    option(redSB);
739    option(redTail);
740    module STD_EX,LT,TSTD, L, Trafo;
741
742   
743   
744    module STD=transpose(m);
745    int finish=0;
746    list pos, COM, COM_EX;
747    matrix END, ENDSTD, STDFIN;
748    STDFIN=STD;
749    list COMPARE=STDFIN;
750
751
752  while(finish==0)
753    {
754      dbprint(ppl,"Going into the while cycle");
755      if(flag mod 2==1){STD_EX=EXL,transpose(STD); ex=2*COL;} else {STD_EX=EXR,transpose(STD); ex=2*ROW;}
756
757      dbprint(ppl,"Computing Groebner basis: start");
758      dbprint(ppl-1,STD);
759      STD=engine(STD,BASIS);
760      dbprint(ppl,"Computing Groebner basis: finished");
761      dbprint(ppl-1,STD);
762      if(flag mod 2==1){s=ROW; st=COL;}else{s=COL; st=ROW;}
763 
764      STD_EX=transpose(STD_EX);
765      dbprint(ppl,"Computing Groebner basis for transformation matrix: start");
766      dbprint(ppl-1,STD_EX);
767      STD_EX=engine(STD_EX,BASIS);
768      dbprint(ppl,"Computing Groebner basis for transformation matrix: finished");
769      dbprint(ppl-1,STD_EX);
770
771      COM=1;
772      COM_EX=1;
773      for(i=2; i<=size(STD); i++)
774         { COM=COM[1..size(COM)],i; COM_EX=COM_EX[1..size(COM_EX)],i; }
775      nz=size(STD_EX)-size(STD);
776
777      //zero rows in the begining
778
779       if(size(STD)!=size(STD_EX) )
780       {
781         for(i=1; i<=size(STD_EX)-size(STD); i++)
782         {
783           COM_EX=0,COM_EX[1..size(COM_EX)];
784         }
785       } 
786
787       
788       
789     
790       for(i=nz+1; i<=size(STD_EX); i++ )
791        {if( leadcoef(STD[i-nz])!=leadcoef(STD_EX[i]) )   {STD[i-nz]=leadcoef(STD_EX[i])*STD[i-nz];}
792        }
793
794        //assign the zero rows in STD_EX
795
796       for (j=2; j<=nz; j++)
797       {
798        p=0;
799        i=1;
800        while(STD_EX[j-1][i]==0){i++;};
801        p=i-1;
802        nextp=1;
803        k=0;
804        i=1;
805        while(STD_EX[j][i]==0 and i<=p)
806        { k++; i++;}
807        if (k==p){ COM_EX[j]=-1; }
808       }
809     
810      //assign the zero rows in STD
811      for (j=2; j<=size(STD); j++)
812       {
813        i=size(transpose(STD));
814        while(STD[j-1][i]==0){i--;}
815        p=i;
816        i=size(transpose(STD[j]));
817        while(STD[j][i]==0){i--;}
818        if (i==p){ COM[j]=-1; }
819       }
820
821       for(j=1; j<=size(COM); j++)
822        {
823        if(COM[j]<0){COM=delete(COM,j);}
824        }
825     
826      for(i=1; i<=size(COM_EX); i++)
827        {ff=0;
828         if(COM_EX[i]==0){ff=1;}
829         else
830          {  for(j=1; j<=size(COM); j++)
831               { if(COM_EX[i]==COM[j]){ff=1;} }
832          }
833         if(ff==0){COM_EX[i]=-1;}
834        }
835
836      L=STD_EX[1];
837      for(i=2; i<=size(COM_EX); i++)
838       {
839        if(COM_EX[i]!=-1){L=L,STD_EX[i];}
840       }
841
842      //////// split STD_EX in STD and the transformation matrix
843
844       L=transpose(L);
845       STD=L[st+1];
846       LT=L[1];
847
848     
849       for(i=2; i<=s+st; i++)
850        {
851         if (i<=st)
852          {
853           LT=LT,L[i];
854          }
855         if (i>st+1)
856          {
857          STD=STD,L[i];
858          }
859        }
860
861       STD=transpose(STD);
862       STDFIN=matrix(STD);
863       COMPARE=insert(COMPARE,STDFIN);
864       LT=transpose(LT);
865
866      ////////////////////// compute the transformation matrices
867     
868       if (flag mod 2 ==1)
869        {
870         TrafoL=transpose(LT)*TrafoL;
871        }
872       else
873        {
874         TrafoR=TrafoR*involution(LT,inv);
875        }
876
877
878      ///////////////////////// check whether the alg termined /////////////////
879      if(size(COMPARE)>=3)
880       {   
881        if(STD==COMPARE[3]){finish=1;}
882       }       
883       ////////////////////////////////// change to the opposite module
884       TSTD=transpose(STD);
885       STD=involution(TSTD,inv);
886       flag++;
887       dbprint(ppl,"Finished one while cycle");
888    }
889
890if (flag mod 2 ==0){ STD = involution(STD,inv);} else { STD = transpose(STD);  }
891 
892    list REVERSE=TrafoL,STD,TrafoR;
893    return(REVERSE);
894}
895
896static proc divideByContent(matrix M)
897{
898//find first entrie not equal to zero
899int i,k;
900k=1;
901vector CON;
902   for(i=1;i<=ncols(M);i++)
903   {
904    if(leadcoef(M[i])!=0){CON=CON+leadcoef(M[i])*gen(k); k++;}
905   }
906poly con=content(CON);
907matrix TL=1/con*freemodule(nrows(M));
908return(TL);
909}
910
911
912/////interesting examples for smith////////////////
913
914static proc Ex_One_wheeled_bicycle()
915{
916ring RA=(0,m), D, lp;
917matrix bicycle[2][3]=(1+m)*D^2, D^2, 1, D^2, D^2-1, 0;
918list s=smith(RA,bicycle, 1,0);
919print(s[2]);
920print(s[1]*bicycle*s[3]-s[2]);
921}
922
923
924static proc Ex_RLC-circuit()
925{
926ring RA=(0,m,R1,R2,L,C), D, lp;
927matrix  circuit[2][3]=D+1/(R1*C), 0, -1/(R1*C), 0, D+R2/L, -1/L;
928list s=smith(RA,circuit, 1,0);
929print(s[2]);
930print(s[1]*circuit*s[3]-s[2]);
931}
932
933
934static proc Ex_two_pendula()
935{
936ring RA=(0,m,M,L1,L2,m1,m2,g), D, lp;
937
938matrix 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,
939m2*L2^2*D^2-m2*L2*g,m2*L2*D^2,0;
940list s=smith(RA,pendula, 1,0);
941print(s[2]);
942print(s[1]*pendula*s[3]-s[2]);
943}
944
945
946
947static proc Ex_linerized_satellite_in_a_circular_equatorial_orbit()
948{
949ring RA=(0,m,omega,r,a,b), D, lp;
950
951matrix satellite[4][6]=
952D,-1,0,0,0,0,
953-3*omega^2,D,0,-2*omega*r,-a/m,0,
9540,0,D,-1,0,0,
9550,2*omega/r,0,D,0,-b/(m*r);
956
957list s=smith(RA,satellite, 1,0);
958print(s[2]);
959print(s[1]*satellite*s[3]-s[2]);
960}
961
962static proc Ex_flexible_one_link_robot()
963{
964ring RA=(0,M11,M12,M13,M21,M22,M31,M33,K1,K2), D, lp;
965
966matrix 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;
967list s=smith(RA,robot, 1,0);
968print(s[2]);
969print(s[1]*robot*s[3]-s[2]);
970}
971
972
973
974/////interesting examples for jacobson////////////////
975
976static proc Ex_compare_output_with_maple_package_JanetOre() 
977{   ring w = 0,(x,d),Dp;
978    def W=nc_algebra(1,1);
979    setring W;
980    matrix m[3][3]=[d2,d+1,0],[d+1,0,d3-x2*d],[2d+1, d3+d2, d2];
981    list J=jacobson(W,m,0);
982    print(J[1]*m*J[3]);
983    print(J[2]);
984    print(J[1]);
985    print(J[3]);
986    print(J[1]*m*J[3]-J[2]);
987}
988
989
990static proc Ex_cyclic()
991{   ring w = 0,(x,d),Dp;
992    def W=nc_algebra(1,1);
993    setring W;
994    matrix m[3][3]=d,0,0,x*d+1,d,0,0,x*d,d;
995    list J=jacobson(W,m,0);
996    print(J[1]*m*J[3]);
997    print(J[2]);
998    print(J[1]);
999    print(J[3]);
1000    print(J[1]*m*J[3]-J[2]);
1001}
1002