Changeset 9a3ece in git for Singular/LIB/normal.lib


Ignore:
Timestamp:
May 26, 1999, 2:25:23 PM (25 years ago)
Author:
Olaf Bachmann <obachman@…>
Branches:
(u'spielwiese', 'fe61d9c35bf7c61f2b6cbf1b56e25e2f08d536cc')
Children:
1598568cca6b50706674b0e35565a4c89bcfef83
Parents:
9fd5f8a67b2159d3a039d7b0b34e704f6a617dfb
Message:
* new version from GP and GMG -- norid, normap


git-svn-id: file:///usr/local/Singular/svn/trunk@3053 2c84dea3-7e68-4137-9b89-c4e89433aadc
File:
1 edited

Legend:

Unmodified
Added
Removed
  • Singular/LIB/normal.lib

    r9fd5f8 r9a3ece  
    22// normal.lib
    33// algorithms for computing the normalization based on
    4 // the ideas of De Jong,Vasconcelos
     4// the criterion of Grauert/Remmert and ideas of De Jong & Vasconcelos
    55// written by Gert-Martin Greuel and Gerhard Pfister
    66///////////////////////////////////////////////////////////////////////////////
    77
    8 version="$Id: normal.lib,v 1.11 1999-03-15 12:07:19 Singular Exp $";
     8version="$Id: normal.lib,v 1.12 1999-05-26 12:25:23 obachman Exp $";
    99info="
    10 LIBRARY: normal.lib: PROCEDURE FOR NORMALIZATION (I)
    11 
    12   normal(ideal I)
    13   // computes a set of rings such that their product is the
    14   // normalization of the reduced basering/I
     10LIBRARY: normal.lib     PROCEDURES FOR NORMALIZATION
     11
     12 normal(I);             computes the normalization of basering/I
     13 extraweight(R);        intvec of variable weights of ring R
     14 HomJJ(L);              presentation of End_R(J) as affine ring, L a list     
    1515";
    1616
     
    2020LIB "presolve.lib";
    2121///////////////////////////////////////////////////////////////////////////////
    22 
     22static
    2323proc isR_HomJR (list Li)
    2424"USAGE:   isR_HomJR (Li);  Li = list: ideal SBid, ideal J, poly p
     
    153153///////////////////////////////////////////////////////////////////////////////
    154154
    155 proc HomJJ (list Li,list #)
    156 "USAGE:   HomJJ (Li);  Li = list: SBid,id,J,poly p
     155proc HomJJ (list Li)
     156"USAGE:   HomJJ (Li);  Li = list: ideal SBid, ideal id, ideal J, poly p
    157157ASSUME:  R    = P/id,  P = basering, a polynomial ring, id an ideal of P,
    158158         SBid = standard basis of id,
     
    166166               endphi describes the canonical map R -> Hom_R(J,J)
    167167         _[2]: an integer which is 1 if phi is an isomorphism, 0 if not
     168NOTE:    printlevel >=1: display comments (default: printlevel=0)
    168169EXAMPLE: example HomJJ;  shows an example
    169170"
     
    174175   intvec rw,rw1;
    175176   list L;
    176    if( size(#) >=1 )
    177    {
    178       if( typeof(#[1]) == "int" ) { y = #[1]; }
    179    }
     177   
     178   y = printlevel-voice+2;  // y=printlevel (default: y=0)
    180179 def P = basering;
    181180   ideal SBid, id, J = Li[1], Li[2], Li[3];
     
    219218//---------- computation of p*Hom(J,J) as R-ideal -----------------------------
    220219   f  = quotient(p*J,J);
    221    if(y==1)
    222    {
    223       "the module Hom(rad(J),rad(J)) presented by the values on";
    224       "the non-zerodivisor";
    225       "  ";
    226       p;
    227       " ";
    228       f;
     220   if ( y>=1 )
     221   { "// the module p*Hom(rad(J),rad(J)) = p*J:J, p a non-zerodivisor";
     222     
     223      "// p"; p;
     224      "// f=p*J:J";f;
    229225   }
    230226   f2 = std(p);
     
    271267      L=lastRing;
    272268      L = insert(L,1,1);
    273       dbprint(printlevel-voice+3,"// case R = Hom(J,J)");
    274       if(y==1)
     269      dbprint(y,"// case R = Hom(J,J)");
     270      if(y>=1)
    275271      {
    276272         "R=Hom(rad(J),rad(J))";
     
    300296      return(L);
    301297   }
    302    if(y==1)
     298   if(y>=1)
    303299   {
    304300      "R is not equal to Hom(rad(J),rad(J)), we have to try again";
     
    340336   list L1;
    341337
    342 //---------- computation of Hom(J,J) as ring ----------------------------------
     338//---------- computation of Hom(J,J) as affine ring ---------------------------
    343339// determine kernel of: R[T1,...,Tq] -> J:J >-> R[1/p]=R[t]/(t*p-1),
    344340// Ti -> fi/p -> t*fi (p=f1=f[1]), to get ring structure. This is of course
     
    350346   T = matrix(ideal(T(1..q)),1,q);
    351347   Lin = ideal(T*syzf);
    352    if(y==1)
     348   if(y>=1)
    353349   {
    354350      "the ring structure of Hom(rad(J),rad(J)) as R-algebra";
     
    367363      }
    368364   }
    369    if(y==1)
     365   if(y>=1)
    370366   {
    371367      "the quadratic relations";
     
    402398  // export(endid);
    403399  // export(endphi);
    404    if(y==1)
     400   if(y>=1)
    405401   {
    406402      "the new ring after reduction of the number of variables";
     
    439435  list Li = std(id),id,J,p;
    440436  list L   = HomJJ(Li);
    441   def end = L[1];      // defines ring L[1], containing ideals endid and endphi
    442   setring end;         // makes end the basering
     437  def end = L[1];    // defines ring L[1], containing ideals endid and endphi
     438  setring end;       // makes end the basering
    443439  end;
    444   endid;               // end/endid is isomorphic to End(r/id) as ring
    445   map psi = r,endphi;  // defines the canonical map r/id -> End(r/id)
     440  endid;             // end/endid is isomorphic to End(r/id) as ring
     441  map psi = r,endphi;// defines the canonical map r/id -> End(r/id)
    446442  psi;
    447 
    448   ring r   = 32003,(x,y,z),dp;
    449   ideal id = x2-xy-xz+yz;
    450   ideal J =y-z,x-z;
    451   poly p = x+16001y+16001z;
    452   list Li = std(id),id,J,p;
    453   list L   = HomJJ(Li,0);
    454   def end = L[1];      // defines ring L[1], containing ideals endid and endphi
    455   setring end;         // makes end the basering
    456   end;
    457   endid;               // end/endid is isomorphic to End(r/id) as ring
    458 
    459443}
    460444
    461445///////////////////////////////////////////////////////////////////////////////
    462446proc normal(ideal id, list #)
    463 "USAGE:   normal(i,choose);  i ideal,choose empty or 1
    464          in case you choose 1 the factorizing Buchberger algorithm
    465          is not used which is sometimes more efficient
    466 RETURN:  a list of rings L=R1,...,Rk, in each Ri are two ideals
    467          Si,Mi such that the product of Ri/Mi is the normalization
    468          Si is a standardbasis of Mi
    469 NOTE:    to use the rings: def r=L[i];setring r;
     447"USAGE:   normal(i [,choose]);  i ideal, choose empty or 1
     448         if choose=1 the factorizing Buchberger algorithm is not used
     449         (which is sometimes more efficient)
     450RETURN:  a list L of rings, in each ring L[i] are two ideals
     451         norid, normap such that the product of the L[i]/norid is the
     452         normalization of basering/id and normap is the map from basering/id
     453         to L[i]/norid
     454NOTE:    to use the rings type: def r=L[i]; setring r; norid; normap;
     455         increasing printlevel displays more comments (default: printlevel=0)
     456COMMENT: The algoritm works in principle for any basering and reduced ideal.
     457         The implementation should work correctly for any global (p-) ordering,
     458         however, this is not fully tested.
     459         If the input ideal i is weighted homogeneous a weighted ordering may
     460         be used (qhweight(i); computes weights).
    470461EXAMPLE: example normal; shows an example
    471462"
     
    473464   int i,j,y;
    474465   list result,prim,keepresult;
     466   y=printlevel-voice+2;
     467
     468   if ( find(ordstr(basering),"s")+find(ordstr(basering),"M") != 0)
     469   {
     470     "
     471// Not implemented for this ordering,
     472// please change to global ordering!";
     473     return(result);
     474   }
     475
    475476
    476477   if(size(#)==0)
     
    535536          attrib(prim[1],"isRegInCodim2",0);
    536537      }
     538      dbprint(y+1,"
     539// If the name of your list is L type:
     540//          def r=L[i]; setring r; norid; normap;
     541// then r/norid is the i-th ring of the normaliztion
     542// and normap the map of the basring to r/norid");
     543
    537544      return(normalizationPrimes(prim[1],maxideal(1)));
    538545   }
     
    548555      }
    549556
    550       if(y==1)
     557      if(y>=1)
    551558      {
    552559         "we have ";size(prim);"components";
     
    554561      for(i=1;i<=size(prim);i++)
    555562      {
    556          if(y==1)
     563         if(y>=1)
    557564         {
    558565            "we are in loop";i;
     
    592599         }
    593600      }
     601
     602      dbprint(y+1,"
     603// If the name of your list is L type:
     604//          def r=L[i]; setring r; norid; normap;
     605// then r/norid is the i-th ring of the normaliztion
     606// and normap the map of the basring to r/norid");
     607 
    594608      return(result);
    595609   }
     
    597611example
    598612{ "EXAMPLE:"; echo = 2;
    599    ring  r = 0,(x,y,z),dp;
    600 
     613   ring r=32003,(x,y,z),wp(2,1,2);
     614   ideal i=z3-xy4;
     615   list pr=normal(i);
     616   pr;
     617   def r1=pr[1];
     618   setring r1;
     619   norid;
     620   normap;
    601621}
    602622
    603 
     623///////////////////////////////////////////////////////////////////////////////
     624static
    604625proc normalizationPrimes(ideal i,ideal ihp, list #)
    605626"USAGE:   normalizationPrimes(i);  i prime ideal
     
    608629         S is a standardbasis of M
    609630NOTE:    to use the ring: def r=L[1];setring r;
     631         printlevel >=1: display comments (default: printlevel=0)
    610632EXAMPLE: example normalizationPrimes; shows an example
    611633"
    612634{
    613    int y;
    614    if(y==1)
     635   int y = printlevel-voice+2;  // y=printlevel (default: y=0)
     636 
     637   if(y>=1)
    615638   {
    616639      "START one normalization loop with the ideal";
     
    625648   def BAS=basering;
    626649   list result,keepresult1,keepresult2;
    627    ideal J,SB,MB,KK;
     650   ideal J,SB,MB;
    628651   int depth,lauf,prdim;
    629652   int ti=timer;
     
    631654   if(size(i)==0)
    632655   {
    633       if(y==1)
     656      if(y>=1)
    634657      {
    635658          "the ideal was the zero-ideal";
     
    637660         execute "ring newR7="+charstr(basering)+",("+varstr(basering)+"),("
    638661                      +ordstr(basering)+");";
    639          ideal KK=ideal(0);
    640          ideal PP=fetch(BAS,ihp);
    641          export PP;
    642          export KK;
     662         ideal norid=ideal(0);
     663         ideal normap=fetch(BAS,ihp);
     664         export norid;
     665         export normap;
    643666         result=newR7;
    644667         setring BAS;
     
    647670   }
    648671
    649    if(y==1)
     672   if(y>=1)
    650673   {
    651674      "                                  ";
     
    656679   list SM=mstd(i);
    657680
    658    if(y==1)
     681   if(y>=1)
    659682   {
    660683      " the dimension is                 ";
     
    727750      if(dim(JM[1])==-1)
    728751      {
    729          if(y==1)
     752         if(y>=1)
    730753         {
    731754            "the ideal was smooth";
     
    736759         def newR6=LL[1];
    737760         setring newR6;
    738          ideal KK=endid;
    739          ideal PP=endphi;
    740 //        execute "ring newR6="+charstr(basering)+",("+varstr(basering)+"),("
    741 //                      +ordstr(basering)+");";
    742 //         ideal KK=fetch(BAS,MB);
    743 //         ideal PP=fetch(BAS,ihp);
    744          export PP;
    745          export KK;
     761         ideal norid=endid;
     762         ideal normap=endphi;
     763         export norid;
     764         export normap;
    746765         result=newR6;
    747766         setring BAS;
     
    753772   if((dim(SM[1])==0)&&(homog(SM[2])==1))
    754773   {
    755       if(y==1)
     774      if(y>=1)
    756775      {
    757776         "the ideal was zero-dimensional and homogeneous";
     
    762781      def newR5=LL[1];
    763782      setring newR5;
    764       ideal KK=endid;
    765       ideal PP=endphi;
    766 //      execute "ring newR5="+charstr(basering)+",("+varstr(basering)+"),("
    767 //                      +ordstr(basering)+");";
    768 //      ideal KK=fetch(BAS,MB);
    769 //      ideal PP=fetch(BAS,ihp);
    770       export PP;
    771       export KK;
     783      ideal norid=endid;
     784      ideal normap=endphi;
     785      export norid;
     786      export normap;
    772787      result=newR5;
    773788      setring BAS;
     
    781796        &&(homog(SM[2])==1))
    782797   {
    783       if(y==1)
     798      if(y>=1)
    784799      {
    785800         "the ideal defines a line";
     
    790805      def newR4=LL[1];
    791806      setring newR4;
    792       ideal KK=endid;
    793       ideal PP=endphi;
    794 //      execute "ring newR4="+charstr(basering)+",("+varstr(basering)+"),("
    795 //                      +ordstr(basering)+");";
    796 //      ideal KK=fetch(BAS,MB);
    797 //      ideal PP=fetch(BAS,ihp);
    798       export PP;
    799       export KK;
     807      ideal norid=endid;
     808      ideal normap=endphi;
     809      export norid;
     810      export normap;
    800811      result=newR4;
    801812      setring BAS;
     
    812823      attrib(SM[2],"isCompleteIntersection",1);
    813824      attrib(SM[2],"isEquidimensional",1);
    814       if(y==1)
     825      if(y>=1)
    815826      {
    816827         "it is a complete Intersection";
    817828      }
    818829   }
    819 //   if(attrib(i,"isIsolatedSingularity")==0)
    820 //   {
    821 //      list L=sres(SM[2],0);
    822 //      prdim=ncols(betti(L))-1;
    823 //      depth=nvars(basering)-prdim;
    824 //   }
    825 
    826   // if(attrib(SM[2],"isCohenMacaulay")==0)
    827   // {
    828   //    test for CohenMacaulay
    829   //    if((dim(SM[1]))==depth)
    830   //    {
    831   //    attrib(SM[2],"isCohenMacaulay",1);
    832   //    "it is CohenMacaulay";
    833   //    }
    834   // }
    835830
    836831   //compute the singular locus+lower dimensional components
     
    841836      J=minor(jacob(SM[2]),nvars(basering)-dim(SM[1]));
    842837      //ti=timer;
    843       if(y==1)
     838      if(y>=1)
    844839      {
    845840         "SB of singular locus will be computed";
     
    848843
    849844    //kills the embeded components
    850 //    if(homog(SM[2])==1)
    851 //    {
    852 //       sin=sat(sin,maxideal(1))[1];
    853 //    }
    854845
    855846      list JM=mstd(sin);
    856       if(y==1)
     847      if(y>=1)
    857848      {
    858849         "                                  ";
     
    867858      if(dim(JM[1])==-1)
    868859      {
    869          if(y==1)
     860         if(y>=1)
    870861         {
    871862            "it is smooth";
     
    874865         intvec rw;
    875866         list LL=substpart(MB,ihp,0,rw);
    876 //         execute "ring newR3="+charstr(basering)+",("+varstr(basering)+"),("
    877 //                      +ordstr(basering)+");";
    878867         def newR3=LL[1];
    879868         setring newR3;
    880 //         ideal KK=fetch(BAS,MB);
    881 //         ideal PP=fetch(BAS,ihp);
    882          ideal KK=endid;
    883          ideal PP=endphi;
    884          export PP;
    885          export KK;
     869         ideal norid=endid;
     870         ideal normap=endphi;
     871         export norid;
     872         export normap;
    886873         result=newR3;
    887874         setring BAS;
     
    916903      if(size(qAnn)==0)
    917904      {
    918          if(y==1)
     905         if(y>=1)
    919906         {
    920907            "                                  ";
     
    928915         //Hom(I,R)=R
    929916         list RR;
    930   //       list RR=SM[1],maxideal(1),SL[1];
    931   //       "test with Hom(I,R)";
    932   //       ti=timer;
    933   //       if(isR_HomJR(RR)==1)
    934   //       {
    935   //         "it was normal";
    936   //          timer-ti;
    937   //          SB=SM[1];
    938   //          SM=SM[2];
    939   //          export SB,MB;
    940   //          result=BAS;
    941   //          return(result);
    942   //       }
    943   //       timer-ti;
    944917         RR=SM[1],SM[2],maxideal(1),SL[1];
    945918         ti=timer;
    946919         RR=HomJJ(RR,y);
    947    //      timer-ti;
    948920         if(RR[2]==0)
    949921         {
     
    961933         execute "ring newR7="+charstr(basering)+",("+varstr(basering)+"),("
    962934                      +ordstr(basering)+");";
    963          ideal KK=fetch(BAS,MB);
    964          ideal PP=fetch(BAS,ihp);
    965          export PP;
    966          export KK;
     935         ideal norid=fetch(BAS,MB);
     936         ideal normap=fetch(BAS,ihp);
     937         export norid;
     938         export normap;
    967939         result=newR7;
    968940         setring BAS;
     
    1014986   {
    1015987      list RR;
    1016  //      "test with Hom(I,I) before the radical computation";
    1017         //again test for normality
    1018         //Hom(I,R)=R
    1019  //     list RR=SM[1],JM[2],SL[1];
    1020  //     "test with Hom(I,R)";
    1021  //     ti=timer;
    1022  //     if(isR_HomJR(RR)==1)
    1023  //     {
    1024  //      "it was normal";
    1025  //        timer-ti;
    1026  //        SB=SM[1];
    1027  //        SM=SM[2];
    1028  //        export SB,MB;
    1029  //        result=BAS;
    1030  //        return(result);
    1031  //     }
    1032  //     timer-ti;
    1033 
    1034  //     list  RR=SM[1],SM[2],JM[2],SL[1];
    1035  //     ti=timer;
    1036988      list RS;
    1037  //   list RS=HomJJ(RR);
    1038  //   timer-ti;
    1039  //     if(RS[2]==0)
    1040  //     {
    1041  //        "Hom(I,I) was sucessfull without radical";
    1042  //        def newR=RS[1];
    1043  //        setring newR;
    1044  //        list tluser=normalizationPrimes(SM);
    1045  //        setring BAS;
    1046  //        return(tluser);
    1047  //     }
    1048989
    1049990      //now we have to compute the radical
    1050       if(y==1)
     991      if(y>=1)
    1051992      {
    1052993         "radical computation";
    1053994      }
    1054 //      ti=timer;
    1055 
    1056995
    1057996      if((attrib(JM[2],"isRad")==0)&&(attrib(SM[2],"isEquidimensional")==0))
     
    10771016          }
    10781017      }
    1079 //    timer-ti;
    10801018
    10811019      JM=J,J;
    10821020
    10831021      //evtl. fuer SL[1] anderen Nichtnullteiler aus J waehlen
    1084       // SL=simplify(reduce(J,SM[1]),2);
    1085       // Ann=quotient(SM[2],SL[1]);
    1086       // qAnn=simplify(reduce(Ann,SM[1]),2);
    1087       // if(size(qAnn)!=0)
    1088       // {
    1089         // keepresult1=normalizationPrimes(qAnn+SM[2]);
    1090         // keepresult2=normalizationPrimes(SL[1]+SM[2]);
    1091         // for(lauf=1;lauf<=size(keepresult2);j++)
    1092         // {
    1093         //    keepresult1=insert(keepresult1,keepresult2[lauf]);
    1094         // }
    1095         // return(keepresult1);
    1096       // }
    10971022      RR=SM[1],SM[2],JM[2],SL[1];
    10981023
    10991024//   evtl eine geeignete Potenz von JM?
    1100      if(y==1)
     1025     if(y>=1)
    11011026     {
    11021027        "compute Hom(rad(J),rad(J)):";
    11031028     }
    1104 //   ti=timer;
    11051029
    11061030     RS=HomJJ(RR,y);
    1107 //   timer-ti;
    11081031
    11091032      if(RS[2]==1)
     
    11121035         setring lastR;
    11131036         map psi1=BAS,endphi;
    1114          ideal KK=endid;
    1115          ideal PP=psi1(ihp);
    1116          export PP;
    1117          export KK;
     1037         ideal norid=endid;
     1038         ideal normap=psi1(ihp);
     1039         export norid;
     1040         export normap;
    11181041         setring BAS;
    1119         // return(RS[1]);
    11201042         return(lastR);
    11211043      }
     
    11291051      list tluser=
    11301052             normalizationPrimes(endid,psi(ihp),simplify(psi(MJ)+endid,4));
    1131             // normalizationPrimes(endid);
    11321053      setring BAS;
    11331054      return(tluser);
     
    11391060      execute "ring newR1="+charstr(basering)+",("+varstr(basering)+"),("
    11401061                      +ordstr(basering)+");";
    1141       if(y==1)
     1062      if(y>=1)
    11421063      {
    11431064         "zero-divisor found";
     
    11641085      ideal new2=quotient(SM[2],Ann)+SM[2];
    11651086// evtl. qAnn nehmen
    1166 //      ideal new2=SL[1]+SM[2];
    11671087      execute "ring newR2="+charstr(basering)+",("+varstr(basering)+"),("
    11681088                      +ordstr(basering)+");";
     
    11961116example
    11971117{ "EXAMPLE:";echo = 2;
    1198    LIB"normal.lib";
    11991118   //Huneke
    1200 ring qr=31991,(a,b,c,d,e),dp;
    1201 ideal i=
    1202 5abcde-a5-b5-c5-d5-e5,
    1203 ab3c+bc3d+a3be+cd3e+ade3,
    1204 a2bc2+b2cd2+a2d2e+ab2e2+c2de2,
    1205 abc5-b4c2d-2a2b2cde+ac3d2e-a4de2+bcd2e3+abe5,
    1206 ab2c4-b5cd-a2b3de+2abc2d2e+ad4e2-a2bce3-cde5,
    1207 a3b2cd-bc2d4+ab2c3e-b5de-d6e+3abcd2e2-a2be4-de6,
    1208 a4b2c-abc2d3-ab5e-b3c2de-ad5e+2a2bcde2+cd2e4,
    1209 b6c+bc6+a2b4e-3ab2c2de+c4d2e-a3cde2-abd3e2+bce5;
    1210 
    1211 list pr=normal(i);
    1212 def r1=pr[1];
    1213 setring r1;
    1214 KK;
     1119   ring qr=31991,(a,b,c,d,e),dp;
     1120   ideal i=
     1121   5abcde-a5-b5-c5-d5-e5,
     1122   ab3c+bc3d+a3be+cd3e+ade3,
     1123   a2bc2+b2cd2+a2d2e+ab2e2+c2de2,
     1124   abc5-b4c2d-2a2b2cde+ac3d2e-a4de2+bcd2e3+abe5,
     1125   ab2c4-b5cd-a2b3de+2abc2d2e+ad4e2-a2bce3-cde5,
     1126   a3b2cd-bc2d4+ab2c3e-b5de-d6e+3abcd2e2-a2be4-de6,
     1127   a4b2c-abc2d3-ab5e-b3c2de-ad5e+2a2bcde2+cd2e4,
     1128   b6c+bc6+a2b4e-3ab2c2de+c4d2e-a3cde2-abd3e2+bce5;
     1129
     1130   list pr=normalizationPrimes(i);
     1131   def r1=pr[1];
     1132   setring r1;
     1133   norid;
     1134   normap;
    12151135}
    1216 
    1217 proc substpart(ideal endid,ideal endphi, int homo, intvec rw)
     1136///////////////////////////////////////////////////////////////////////////////
     1137static
     1138proc substpart(ideal endid, ideal endphi, int homo, intvec rw)
    12181139{
    12191140   def newRing=basering;
     
    12971218   return(L);
    12981219}
    1299 
     1220///////////////////////////////////////////////////////////////////////////////
     1221static
    13001222proc diagon(ideal i)
    13011223{
     
    13081230/////////////////////////////////////////////////////////////////////////////
    13091231/*
     1232                           Examples:
    13101233LIB"normal.lib";
    1311 int aa=timer;list pr=normal(i);timer-aa;
    1312 
    1313 
    1314 
    13151234//Huneke
    13161235ring qr=31991,(a,b,c,d,e),dp;
Note: See TracChangeset for help on using the changeset viewer.